Class(클래스)

  • 객체를 정의하는 툴, 또는 설계도와 같은 의미로 사용된다.
  • 클래스는 멤버(member)로 속성을 표현하는 필드(field)와 기능을 표현하는 메소드(method)를 가진다.
  • 필드 : 객체의 상태
  • 메소드 : 객체의 행동
  • 인스턴스(Instance) 
    • 클래스를 사용하기 위해 해당 클래스 타입의 객체(Object)를 선언해야 한다.
    • 클래스의 인스턴스화 : 클래스로부터 객체를 선언하는 과정
    • 인스턴스는 선언된 해당 클래스 타입의 객체이다. -> 인스턴스는 메모리에 할당된 객체
  • 메소드(method)
    • 메소드 : 특정 작업을 수행하기 위한 명령문의 집합
    • 중복 코드 최소화 -> 가독성 향상
    • 유지보수 용이
  • 생성자(consructor)
    • 생성된 객체의 필드를 초기화해주는 메소드
    • 객체의 생성과 동시에 인스턴스 변수를 원하는 값으로 초기화할 수 있다.
    • 생성자도 메소드 이기 때문에, 메소드 오버로딩 가능 하지만, return X
    • 1. class는 무조건 생성자를 1개 이상 갖는다. : 없으면 default constructor 자동 생ㅅ어
    • 2. class 이름과 동일
    • 3. instance 초기화 담당
  • 필드(field)
    • 클래스에 포함된 변수(variable)
class { -> instance 생성 

1) fields

2) constructors

3) methods

}
public class Student{
	// fields (변수)
	String stuName; // String -> class -> reference Type -> 문자
	String stuNum; // 학번(00231123) : 연산이 필요하면 int, 아니면 사용하기 편한 String
	int stuAge; // 나이 - 숫자
	String stuDept; // 학과 - 문자열
	
	// 생성자 - 클래스 이름과 동일, 메소드와 유사(메소드는 Return이 있음)
	// 인스턴스를 초기화해주는 역할 
	// default constructor 
	Student() {
		
	}
	
	// methods (함수)
	public static void main(String args[]) {
		Student stu = new Student(); // instance 생성 : new + constructor
		// . operator ( . 연산자 )
		stu.stuName = "홍길동"; 
		stu.stuNum = "00231123";
		stu.stuAge = 20;
		stu.stuDept = "컴퓨터";
		
		System.out.println();
	}
}

 

 

상속(inheritance)

  • 부모 class가 가지는 내용을 확장해서 자식 class를 만드는 방식
  • 기존 클래스에 기능을 추가하거나 재정의해서 새로운 클래스를 정의하는 것
  • 장점
    • 기존 클래스를 재활용 가능
    • 중복 멤버를 미리 부모 클래스에 작성하면 자식 클래스에서 작성하지 않아도 된다.
    • 클래스 간의 계층 관계를 구성함으로써 다형성의 문법적 토대를 마련한다.
  • 자바의 다중 상속이 없는 이유?
    • 두 곳에서 동시에 상속을 받으면 같은 변수가 올 수 있는 문제점을 배제
class Human {
    // String name
}
class Person {
    String name; // 이름
    String mobile; // 전화번호
}

// tightly coupled
class Student extends Person{
    String dept; // 학과
}

class Teacher extends Person{
    String subject; // 과목
}

class Staff extends Person{
    int salary; // 월급
}

 

Object 클래스

  • 모든 클래스의 부모 클래스
  • 기존 Object에 있는 메소드들을 오버라이딩해서 사용
    • equals() : 해당 인스턴스를 매개변수로 전달받는 참조 변수와 비교하여 결과 반환
    • toString() : 인스턴스에 대한 정보를 문자열로 반환
    • clone() : 해당 인스턴스를 복제해, 새로운 인스턴스를 생성하고 반환한다.
      • clone()은 필드만 복제하기 때문에, 배열같은 경우 오버라이딩을 통해 재정의해야한다.

 

Constructor 상속은 어떻게?

  • 기본적으로 생성자는 상속되지 않는다.
  • super와 super()
    • super : 현재 사용하는 객체의 referenct -> type이 상위 타입
      • this와 마찬가지로, 부모 클래스 멤버와 자식 클래스 멤버 이름이 같을 경우 super 키워드로 구별
    • super() : 상위 클래스의 생성자 호출
      • 부모 클래스의 멤버를 초기화하려면, 자식 클래스의 생성자에서 부모 클래스의 생성자까지 호출해야 한다.
      • 기본 생성자가 아닌 다른 생성자를 선언했으면, 컴파일러가 자동으로 부모 클래스의 멤버를 초기화줄 수 없다.
      • 생성자를 따로 선언하고, 기본 생성자가 없으면 자식 클래스에서 super()호출 시 에러 발생
      • 되도록 기본 생성자까지 명시적으로 선언해주기
class Parent {
    int a;
    Parent() { a = 10; }
    Parent(int n) { a = n; }
}
 
class Child extends Parent {
    int b;
    Child() {
        super();
        b = 20;
    }

 

 

동적 바인딩(dynamic binding)

  •  객체에 대한 type이 상위 타입이라 할지라도, 만약 override된 method에 하위에 존재한다면 overriding 된 method를  사용
  • 다형성을 사용하여 메소드를 호출할 때 발생하는 현상
  • 실행 시간(runtime), 파일을 실행하는 시점에 결정된다.
  • 실제 참조 객체는 서브 클래스 -> 서브 클래스 메소드 호출

정적 바인딩(static binding)

  • 컴파일(compile) 시간에 의해 결정된다.
  • 변수의 타입이 super 클래스여서 super클래스의 메소드 호출
class SuperClass {

    // static method
    static int staticCall(String msg){
        System.out.println(msg);
        return 100;
    }

    // fields
    int a = staticCall("1번입니다."); // 4번째 출력 : line 3 실행
    static int b = staticCall("2번입니다."); // 1번째 출력
    // static : 프로그램 시작 시 최초에 한 번 생성만 되고 초기화된다.
    // 인스턴스를 생성하지 않아도 바로 사용 가능

    // constructor
    public SuperClass(){  // 생성자 전에 필드 공간이 만들어 져야 한다. -> line 10
        staticCall("3번입니다."); // 5번째 출력 : 필드 공간 생성 후 실행 -> line 23 복귀
    }

    // constructor overloading
    public SuperClass(int i){
        this(); // 자신의 클래스가 가지고있는 다른 생성자를 호출 -> line 16
        staticCall("4번입니다."); // 6번째 출력 -> line 40으로 복귀
    }

    // method
    public void myFunc(){
        System.out.println("5번입니다."); // -> 9번째 출력
    }
}

class InheritanceTest extends SuperClass {
    // fields
    int c = staticCall("6번입니다."); // -> 7번째 출력 -> line 40 복귀
    static int d = staticCall("7번입니다."); // 2번째 출력

    // constructor
    public InheritanceTest(){ // 객체 생성
        super(100); // 상위 클래스의 생성자(100) 호출 -> line 21
        staticCall("8번입니다."); // 생성자 전에 필드 공간 생성 -> line 34 -> 8번째 출력
        super.myFunc(); // -> 상위 클래스의 myFunc 메소드 실행
    }

    @Override
    public void myFunc(){
        System.out.println("9번입니다."); // 10번째 출력
    }

    public static void main(String[] args) {
        System.out.println("10번입니다."); // 3번째 출력 : static -> main 실행
        SuperClass obj = new InheritanceTest(); // 객체 생성 -> line 38
        obj.myFunc(); // obj의 타입 SuperClass 이지만 동적바인딩으로 line 45

        // 객체에 대한 type이 상위 타입이라 할지라도
        // 만약 override된 method에 하위에 존재한다면
        // method는 overriding 된 method를 사용한다.
        // 동적 바인딩(dynamic binding)
    }
}

// 2->7->10->1->3->4->6->8->5->9

 

abstract 제어자

  • 추상 메소드를 만들 때 사용

 

추상 클래스(Abstract Class)

  • 추상 메소드가 1개라도 클래스 내부에 존재하면, 해당 클래스는 추상 클래스
  • 추상 메소드는 선언만 -> 메소드가 하는 일이 정의되지 않았다.
  • 추상 클래스는 인스턴스를 생성할 수 없다.
  • 자식 클래스에서 오버라이딩 해서 사용
public abstract class UpperClass {
    // field
    String name;
    int age;

    // method
    public abstract void printAll();
        // abstract method
}

class subClass extends UpperClass{

    @Override
    public void printAll(){
        // TODO Auto-generated method stub
    }
}

 

인터페이스(Interface)

  • 추상 클래스의 특별한 케이스
  • 모든 메소드가 추상 메소드이다.
  • 모든 필드는 public static final -> 안에 들어가 있는 필드는 모두 상수
    • public 어디에서나 접근 가능, static 전역, final 상수화
  • 추상 메소드와는 다르게, 다중 implements 가능
interface myInterface {
    // fields
    //public static final
    int kk=0;
    String aa = "Hello";

    // abstract methods
    public abstract void printAll();
    public abstract void myPrint();
}

class MyClass implements myInterface{
    // 상속이랑 같은 개념을 사용한다.
    // is - A 관계 성립!!
    // 인터페이스 안에 있는 값들을 확장해서 새로운 클래스(인터페이스)를 구현한다는 의미
    // 인터페이스 안에서 내가 구현한 해당 인터페이스의 모든 내용들을 오버라이딩 해줘야한다.
    // generate 사용 -> 오버라이드 메소드
    @Override
    public void printAll() {

    }

    @Override
    public void myPrint() {

    }
}

 

 

인터페이스, 클래스 구현 예시

abstract class Myclass extends Human implements Aniaml
// Myclass에서 Human 상속, Animal interface를 구현한다는 뜻

abstract class Myclass extends Human implements Aniaml, MyInterface
// 인터페이스는 다중 구현 가능

형변환(type conversion)

  • 묵시적 형변환 : (컴파일러) 자동 변환
    • double num1 = 10
    • System.out.print(num1) // 10.0
  • 명시적 형변환(type casting) : 캐스트 연산자(괄호) 사용
    • int result = 1 / 4; // int(0.25) = 0
    • System.out.print(double(result)) // 0.0

 

삼항 연산자(ternary operator)

  • true : 반환값1
  • false : 반환값2
조건식 ? 반환값1 : 반환값2

 

 

루프와 제어

  • continue : 루프 내에서 사용하여 해당 루프의 나머지 부분은 건너 뛰고, 바로 다음의 조건식으로 넘어가게 해준다.
  • break : 루프 내에서 해당 반복문을 완전 종료

 

static 제어자

  • 해당 변수를 클래스 변수로 만들어준다.
  • 메소드에 사용하면 해당 메소드를 클래스 메소드로 만들어준다.
  • 초기화 블록에도 사용 가능
  • 프로그램 시작 시 최초에 한 번 생성만 되고 초기화된다.
  • 인스턴스를 생성하지 않아도 바로 사용 가능
  • 해당 클래스의 모든 인스턴스가 공유

 

클래스의 필드(field)

  • 필드 : 클래스에 포함된 변수(variable)
  • 선언 위치에 따라 구분된다.
  • 1. 클래스 변수(static variable) : 클래스 영역에서 static 키워드를 가지는 변수
    • 해당 클래스의 모든 인스턴스가 공유해야 하는 값을 유지하기 위해 사용
  • 2. 인스턴스 변수(instance variable) : static 키워드를 가지지 않은 변수
    • 인스턴스마다 가져야하는 고유의 값을 유지하기 위해 사용
  • 3. 지역 변수(local variable) : 메소드나 생성자, 초기화 블록 내에 위치한 변수
  • 클래스 변수 + 인스턴스 변수 : 컴파일러가 자동으로 초기화
  • 지역 변수는 초기화하지 않으면 오류 발생
  • 필드의 초기화 
    • 1. 명시적 초기화 : 필드 선언과 동시에 초기화
    • 2. 생성자를 이용한 초기화 : 객체 생성과 동시에 필드 초기화
      • 인스턴스 생성 전까지 필드 초기화 불가능
    • 3. 초기화 블록을 이용한 초기화 (초기화 블록 : main 메소드 호출 이전에 실행)
      • 초기화 블록은 생성자 보다 먼저 호출
      • 1. 인스턴스 초기화 블록 : 생성자와 거의 차이 없어서 잘 사용 X
      • 2. 클래스 초기화 블록 : 처음 메모리에 로딩될 때 단 한 번만 실행 
        • 필드의 초기화 순서
        • 클래스 변수 : 기본값 -> 명시적 초기화 -> 클래스 초기화 블록
        • 인스턴스 변수 : 기본값 -> 명시적 초기화 -> 인스턴스 초기화 블록 -> 생성자
class Car {
    static int modelOutput; // 클래스 변수
    String modelName;       // 인스턴스 변수
 
    void method() {
        int something = 10; // 지역 변수
    }
}
변수 생성 시기 소멸 시기 저장 메모리 사용 방법
클래스 변수 클래스가 메모리에 올라갈 때 프로그램 종료 메소드 영역 클래스 이름.변수이름
인스턴스 변수 인스턴스가 생성될 때 인스턴스 소멸 힙 영역 인스턴스이름.변수이름
지역 변수 블록 내에서 변수 선언문이 실행될 때 블록을 벗어날 때 스택 영역 변수이름
public class MyClass {
    // field
    int aaa;
    static int bbb = staticCall();

    // default constructor : class 확장성과 관계성이 있음.
    public MyClass(){

    }

    // static block
    static {
        // main이 실행되기 직전에 다른 library 같은 것들을 loading할 필요가 있을 때 사용한다.
        System.out.println("static block");
    }

    static int staticCall(){
        System.out.println("호출되었어요!");
        return 100;
    }

    public static void main(String[] args){
        System.out.println("main 호출");
    }
}

 

 

클래스 메소드와 인스턴스 메소드

  • 1. 클래스 메소드(static method) : static 키워드를 가지는 메소드
    • 인스턴스를 생성하지 않아도 바로 사용 가능
    • 메소드 내부에서 인스턴스 변수를 사용할 수 없다.
  • 2. 인스턴스 메소드(instance method) : static 키워드가 없는 메소드
class Method {
    int a = 10, b = 20;                            // 인스턴스 변수
    int add() { return a + b; }                    // 인스턴스 메소드

    static int add(int x, int y) { return x + y; } // 클래스 메소드
}
 
public class Member02 {
    public static void main(String[] args) {
        System.out.println(Method.add(20, 30)); // 클래스 메소드의 호출
        Method myMethod = new Method();         // 인스턴스 생성
        System.out.println(myMethod.add());     // 인스턴스 메소드의 호출
    }
}

ouput 
50
30

this와 this()

  • this : 현재 사용하는 객체의 reference (자기자신 참조)
    • 생성자의 매개변수 이름과 인스턴스 변수를 구분하기 위해 사용한다.
    • this를 사용해서 인스턴스 변수에 접근한다.
  • this() : 자신의 클래스가 가지고 있는 다른 생성자 호출 
    • 생성자 내부에서만 사용 가능
class Car {
    private String modelName;
    private int modelYear;
    private String color;
    private int maxSpeed;
    private int currentSpeed;
 
    Car(String modelName, int modelYear, String color, int maxSpeed) {
        this.modelName = modelName;
        this.modelYear = modelYear;
        this.color = color;
        this.maxSpeed = maxSpeed;
        this.currentSpeed = 0;
    }
    ...
}
    Car() {
        this("소나타", 2012, "검정색", 160); // 다른 생성자를 호출함.
    }

상수(constant)

  • final 키워드 사용
    • final은 다른 주소를 가리킬 수 없는 것이기 때문에
    • reference type의 변수에서는 그 대상 인스턴스 객체 값 수정 가능
    • final한 참조 타입 변수는 다른 주소를 가리킬 수 없을 뿐, 그 대상 인스턴스 객체의 값을 수정하지 못한다는 의미가 아니다.
    • final 배열은 값 변경, 정렬 가능
  • final int score = 00;
  • 선언과 동시에 초기화 되어야 한다.
  • 상수는 전부 대문자 사용한다 + Snake notation(_ 사용)
    • final int MY_SCORE=100;
  • 1. 변수 앞에 붙으면 상수 처리
  • 2. class 앞에 붙으면 상속 불가능
  • 3. method 앞에 붙으면 오버라이딩 불가능
final class Car { // 이 클래스는 상속을 통해 서브 클래스를 생성할 수 없음.
    final int VAR; // 이 필드는 상수화되어 값을 변경할 수 없음.
    final void brake() { // 이 메소드는 오버라이딩을 통해 재정의할 수 없음.
        final double MAX_NUM = 10.2; // 이 지역 변수는 상수화되어 값을 변경할 수 없음.
    }
}

 

String

  • String class : reference type 
  • primitive type 처럼 사용 가능
// 실행 fn + command + shift + f11
public class Student{
	// fields (변수)
	String stuName; // String -> class -> reference Type -> 문자
	String stuNum; // 학번(00231123) : 연산이 필요하면 int, 아니면 사용하기 편한 String
	int stuAge; // 나이 - 숫
	
	// methods (함수)
	public static void main(String args[]) {
		System.out.println("hello");
	}
}

 

StringBuffer, String, StringBuilder

  • String : 힙 영역에 있는 String Constant pool에 문자열이 저장된다. += 연산을 통하여 새로운 값으로 정의될 때, 기존의 값을 메모리에 유지하고 새로운 메모리 주소에 저장된다.
    • string은 immutable하기 때문에 멀티스레드 환경에서 안전성 보장
  • StringBuffer : 내부적으로 버퍼(buffer)라고 하는 독립적인 공간을 가진다. append를 통하여 새로운 값으로 정의되면, 기존의 값이 있는 주소에 버퍼에 있는 값을 메모리에 저장한다.
    • method별로 동기화 지원 -> 멀티스레드 환경에 적합
  • StringBuilder : StringBuffer와 내부 동작은 동일하지만, 동기화 보장 X
@Override
@IntrinsicCandidate
public StringBuilder append(String str) {
    super.append(str);
    return this;
}

@Override
@IntrinsicCandidate
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

 

String 생성 방식 

  • 1. new 연산자
  • 2. 리터럴
    • String Constant pool(상수 풀)
      • Java 8부터 Perm(Permanent Generation) 영역에서 Heap 영역으로 이동
      • Java 8부터 Perm 영역 삭제 후 MetaSapce 영역이 대신하고 있다.
      • Perm 영역은 실행 시간(Runtime)에 가변적으로 변경할 수 없는 고정된 사이즈이기 때문에 intern 메소드 호출은 저장할 공간이 부족하게 만들 수 있었다. -> out of memory
        • intern() : String 클래스의 메소드. String과 동등한 객체가 이미 상수풀에 존재하면 그 객체를 그대로 리턴한다.
      • heap 영역으로 들어가게 된 상수풀은 Garbage Collection의 대상이 되었다.

 

자바 프로그램 실행 과정

  • 1.자바 소스코드를 컴파일러가 JVM이 이해할 수 있는 코드(byte code)로 변환
  • 2.바이트 코드를 JVM의 클래스 로더에게 전달
  • 3.클래스 로더는 동적로딩(Dynamic loading)을 통해 필요한 클래스들을 로딩 및, 링크하여 런타임 데이터 영역(JVM의 메모리)에 올린다.
    • 클래스 로더 세부 동작 
      • 로드 : 클래스 파일을 가져와서 JVM의 메모리에 로드
      • 검증 : 자바 언어 명세 및 JVM 몇세에 명시된 대로 구성되어 있는지 검사
      • 준비 : 클래스가 필요로 하는 메모리를 할당
      • 분석 : 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 래퍼런스로 변경
      • 초기화 : 클래스 변수들을 적절한 값으로 초기화한다. (static 필드)
  • 4.실행엔진(Execution engine)은 JVM 메모리에 올라온 바이트 코드들을 명령어 단위로 하나씩 가져와서 실행한다. 
    • 자바 인터프리터 : 바이트 코드 명령어를 한줄씩 해석하고 실행  
    • JIT 컴파일러 : 바이트 코드 전체를 컴파일하고 바이너리코드로 변경해서 직접 실행하는 방식
  • 5. 해석된 바이트 코드는 메모리 영역에 배치되어 실질적 수행이 이루어진다. JVM은 필요에 따라 스레드 동기화나 가비지 컬렉션같은 메모리 관리 작업을 수행한다.

 

자바 컴파일러(Java compiler)

  • 자바를 가지고 작성한 자바 소스 코드를 자바 가상 머신이 이해할 수 있는 자바 바이트 코드로 변환한다.
  • javac.exe

 

자바 바이트 코드(Java bytecode)

  • 자바 가상 머신이 이해할 수 있는 언어로 변환된 자바 소스 코드
  • 명령어 크기 1 byte

 

자바 가상 머신(JVM)

  • 자바 바이트 코드를 실행하기 위한 가상 기계
  • 각 운영체제에 맞는 JVM을 설치해야 한다.

 

 

자바 가상 머신 구성요소

  • 자바 인터프리터 : 자바 컴파일러에 의해 변환된 자바 바이트 코드를 읽고 해석하는 역할
  • 클래스 로더(class loader)
    • 자바는 동적으로 클래스를 읽어오기 때문에, 동적으로 클래스를 로딩해주는 역할
  • JIT 컴파일러(Just In Time Compiler)
    • 프로그램이 실행 중인 런타임에 실제 기계어로 변환해 주는 컴파일러
    • 동적 번역을 통해, 프로그램의 실행 속도를 향상시켜 준다.
    • JIT 컴파일러는 자바 컴파일러가 생성한 바이트 코드를 바로 런타임에 기계어로 변환
  • 가비지 컬렉터(Garbage Collector)
    • 더 이상 사용하지 않는 메모리를 자동으로 회수
    • 개발자가 메모리 관리를 하지 않아도 되는 편의성
    • 실행 순서 : 참조되지 않은 객체들 탐색 후 삭제 -> 삭제된 객체의 메모리 반환 -> 힙 메모리 재사용

 


JVM이 관리하는 메모리 구조

  • 자바가 실행되면, JVM은 운영체제로 부터 해당 프로그램을 수행할 수 있도록 필요한 메모리를 할당 받는다.
  • 용도에 따라
    • 1. 메소드(method) 영역
      • 클래스에 대한 정보와 함께 클래스 변수(static variable)가 저장되는 영역
    • 2. 힙(heap) 영역
      • 모든 인스턴스 변수가 저장되는 영역
      • new 키워드를 사용한 인스턴스가 생성되면, 해당 인스턴스의 정보를 힙 영역에 저장한다.
      • 힙 영역은 메모리의 낮은 주소에서 높은 주소의 방향으로 할당된다.
    • 3. 스택(stack) 영역
      • 메소드가 호출될 때 메소드의 스택 프레임이 저장되는 영역
        • 스택 프레임(stack frame) : 메소드의 호출 정보
      • 메소드가 호출되면, 메소드 호출과 관계되는 지역변수와 매개변수를 스택에 저장
      • 메소드가 호출되면 함께 할당되고, 호출이 완료되면 소멸한다.

 

JVM - Runtime Data Areas

  • JVM이 운영체제 위에서 실행되면서 할당받는 메모리 영역

1. PC 레지스터(register)

  • 프로그램 실행 포인터를 관리하는 영역

 

2. Native method stack(네이티브 메서드 스택)

  • 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행시키는 영역

 

3. Method area

  • Class 자체에 대한 정보
  • Class를 처음 사용하는 시점에 memory에 올라간다.
  • class의 static field

 

4. heap Area

  • new keyword으로 생성되는 모든 인스턴스가 저장된다.
  • String constant pool : string pool을 heap 안에 가지고 있고, 여기에서 문자열을 관리한다.

 

5. call stack area

  • method가 호출되면 method를 위한 공간이 스택에 쌓인다.
  • 그리고 메소드 안에 사용하는 local variable(지역 변수) 같은 것들이 이 공간에 위치한다.

 

자바의 탄생

  • 썬 마이크로시스템즈(Sun Microsystems)에서 제임스 고슬링(James Gosling)이 고안
  • 가전제품에서 사용할 목적으로 만들었지만, 인터넷과 웹의 출현으로 인터넷을 목적으로 개발
  • 제임스 고슬링의 목표 : Write Once, Run Anywhere(한 번 쓰고 어느 곳에서도 실행)

 

자바의 특징

  • 객체지향 언어
    • 객체들을 먼저 만들고, 하나씩 조립, 연결해서 전체 프로그램 완성
    • 객체를 만들기 전, 클래스 작성
    • 캡슐화, 상속성, 다형성
  • 높은 이식성, OS에 독립적
    • 서로 다른 실행환경에서 프로그램을 옮겨 실행 가능
    • 자바 실행환경(JRE)이 설치되어 있는 모든 운영체제에서 실행 가능

  • 인터프리터 언어
    • C언어는 컴파일 언어 // C -> 컴파일 -> machine code
    • Javascript는 인터프리터 언어 // 소스코드 -> (js)엔진 -> 중간코드 생성 -> 한줄씩 machine code
    • 자바 = 컴파일 언어 + 인터프리터 언어
    • ex. Student.java - 컴파일(javac.exe Student.java) - Student.class(byte code)
      • interpret(java.exe) Student 실행 - JVM 기동
      • 1. class loader 호출
      • 2. class file 검사 + 악성코드 check
      • 3. main() 호출 // 없으면 Main method not found

  • 메모리 자동 관리
    • 개발자가 직접 메모리 접근이 불가능하고, 자바가 메모리 직접 관리
    • 객체 생성 시 자동으로 메모리 영역을 찾아서 할당하고, 사용이 완료되면 가비지 컬렉터(Garbage Colletor)를 실행시켜 자동으로 사용하지 않는 객체를 제거한다.
    • 높은 안정성
  • 쉬운 멀티 스레드 구현
    • 자바는 스레드 생성 및 제어와 관련된 라이브러리 API를 제공하기 때문에 운영체제와 상관없이 멀티 스레드를 쉽게 구현 가능하다.
  • 동적 로딩(Dynamic Loading) 지원
    • 실행시 모든 클래스 로딩이 아닌, 필요한 시점에 클래스를 로딩할 수 있는 장점
    • 메모리의 효율적인 사용과 속도를 위해 필요한 클래스를 동적 로딩
  • 분산 환경 지원
    • TCP/IP 라이브러리가 포함되어 있다.
    • http, http 프로토콜을 지원한다.
  • 풍부한 오픈소스 라이브러리
    • 자바는 오픈소스(Open source) 언어이고, 사용하는 라이브러리나 오픈소스의 양이 당야하다.

JRE(Java Runtime Environment) 자바 실행 환경

  • Java class Library + JVM

 

JDK(Java Developement Kit) 자바 개발 도구

  • 유틸리티(개발 도구)
  • JRE + utility
  • JDK 1.1 -> JDK -> 1.2 -> ... -> JDK 1.5(Java5) -> Java6 -> ... -> 자주 사용되는 Java 8과 Java 11
  • 점점 함수형 언어 관련 기능 업데이트 중

 

Java 8

  • 2014년 Java SE 8 업데이트1.
  • 1.람다 표현식(lambda expression) : 함수형 프로그래밍
  • 2.스트림 API(Stream API) : 데이터의 추상화
  • 3.java.time 패키지 : Joda-Time을 이용한 새로운 날짜와 시간 API
  • 4.나즈혼(Nashorn) : 자바스크립트의 새로운 엔진, 성능과 메모리 관리 면에서 개선

 

람다 표현식(labmda expression)

  • 메소드를 하나의 식으로 표현
  • 식별자 없이 실행 가능한 함수 표현식 -> 익명 함수(anonymous function)
  • 클래스와 객체를 생성하지 않아도 메소드 사용 가능
  • 코드의 가독성을 높여준다.
new Thread(new Runnable() {
    public void run() {
        System.out.println("전통적인 방식의 일회용 스레드 생성");
    }
}).start();
 
new Thread(()->{
    System.out.println("람다 표현식을 사용한 일회용 스레드 생성");
}).start();

 

스트림 API(Stream API)

  • 자바에서 많은 양의 데이터 저장에 배열, 컬렉션 사용
  • 배열, 컬렉션 등에 접근하기 위해 반복문이나 반복자(iterator) 사용
  • 가독성과 재사용성 단점, 정형화된 패턴 부재로 데이터마다 다른 방법으로 접근해야 한다는 단점
  • 스트림 API는 데이터를 추상화하여 다양한 방식으로 저장된 데이터를 읽고 쓰기 위한 공통된 방법 제공
String[] arr = new String[]{"넷", "둘", "셋", "하나"};
 
// 배열에서 스트림 생성
Stream<String> stream1 = Arrays.stream(arr);
stream1.forEach(e -> System.out.print(e + " "));
System.out.println();
 
// 배열의 특정 부분만을 이용한 스트림 생성
Stream<String> stream2 = Arrays.stream(arr, 1, 3);
stream2.forEach(e -> System.out.print(e + " "));

 

java.time 패키지

  • JDK 1.1부터 Calendar 클래스 제공. 하지만 문제점이 존재
    • Calendar 인스턴스는 불변 객체가 아니라서 값이 수정될 수 있는 단점
    • 윤초(leap second)와 같은 특별 상황 고려X

 


call by value VS call by reference

  • call by value : 값에 의한 호출
    • 함수 호출 시 전달되는 변수 값을 복사해서 함수 인자로 전달한다.
  • call by reference : 참조에 의한 호출
    • 인자로 전달되는 변수의 래퍼런스를 전달
  • 자바는 call by value으로 값을 넘긴다. 
  • reference type의 경우에는 해당 객체의 주소 값을 복사하여 사용한다.

 

Java Naming rule

  • Class Name : Parscal notation 사용
    • ex. SampleProject
  • Source code Name : (public) class 이름을 따서 만든다.
    • 하나의 java 파일 안에 여러 class가 나올 수 있다. -> public class는 1개

변수의 종류

  • 1. 기본형(primitive type) 변수
    • 실제 연산에 사용되는 변수
    • 자바에서 기본으로 제공해주는 타입들
    • 정수형, 실수형, 문자형, 논리형

 

  • 2. 참조형(reference type) 변수
    • primitive 변수를 이용해서 사용자가 직접 만들어 사용하는 변수
    • 클래스, 인터페이스, 배열, 열거 타입
    • 빈 객체를 의미하는 null 존재

 

접근 제어자(Access modifier)

  • Public
    • (패키지에 상관없이) 제약없이 사용이 가능하다.
  • protected
    • 부모 클래스에서는 public
    • 외부에서는 private
    • 다른 패키지인 경우, 상속 관계 있으면 사용 가능
  • pacakge(default)
    • 키워드를 사용하지 않았을 경우 default로 사용
    • 같은 패키지 이내에서만 사용 가능
  • private
    • 같은 클래스 안에서만 사용 가능
package com.kakao.test;

public class Student {
	// 결론적으로 field는 특별한 이유가 없는 한 싹다 private
	// class 내부의 필드는 보호해야하는 정
	private String stuName; // information hiding
	private String strNum;
	
	public String getStuName() {
		return this.stuName;
	}
	
	/**
	 * @param stuName
	 */
	public void setStuName(String stuName) {
		this.stuName = stuName;
	}
	
	
	public String getStrNum() {
		return strNum;
	}

	public void setStrNum(String strNum) {
		this.strNum = strNum;
	}

	public Student(){
		
	}
	// method는 행위를 하는 작업이기 때문에 특별한 이유가 없는 한 
	// 외부에서 사용할 수 있도록 public으로 설정한다. 
}

 


래퍼 클래스(Wrapper Class)

  • Primitive(기본 타입) type의 데이터를 객체로 취급해야 하는 경우가 생길 때 사용
  • 기본 타입 데이터를 객체로 포장해주는 클래스
  • 래퍼 클래스는 인스턴스에 저장된 값을 변경할 수 없기 때문에, 새로운 인스턴스 생성 후 생성된 인스턴스 값만 참조 가능
  • 박싱(Boxing) : 기본 타입 데이터를 래퍼 클래스의 인스턴스로 변환하는 과정
  • 언박싱(UnBoxing) : 래퍼 클래스의 인스턴스에 저장된 값을 다시 기본 타입의 데이터로 꺼내는 과정
  • JDK 1.5부터 컴파일러가 자동으로 박싱, 언박싱 처리 -> 오토 박싱, 오토 언박싱

 


제너릭(generic)

  • 데이터의 타입(data type)을 일반화(generalize) 하는 것
  • 클래스나 메소드에서 사용할 내부 데이터 타입을 컴파일 시에 미리 지정하는 방법
    • 객체의 타입 안정성 증가
    • 반환 값에 대한 타입 검사 비용 절감
  • JDK 1.5 이전까지는 Object를 사용했기 때문에, 원하는 타입으로 변환할 때 오류 발생 가능성이 있었다.
  • 제네릭 도입 이후 타입 변환과 같은 번거로운 작업 생략 가능
  • 타입 변수(type variable) : 임의의 참조형 타입을 의미한다.
    • 제네릭 클래스를 생성할 때, 타입 변수 자리에 사용할 실제 타입 명시 필요
    • 타입 변수 자리에는 기본 클래스가 아닌, 래퍼 클래스를 사용
    • Java SE 7부터는, 타입 추정이 가능한 경우, 타입 생략 가능
MyArray<Integer> myArr = new MyArray<Integer>();
MyArray<Integer> myArr = new MyArray<>();
import java.util.*;

class LandAnimal { public void crying() { System.out.println("육지동물"); } }
class Cat extends LandAnimal { public void crying() { System.out.println("냐옹냐옹"); } }
class Dog extends LandAnimal { public void crying() { System.out.println("멍멍"); } }
class Sparrow { public void crying() { System.out.println("짹짹"); } } 

class AnimalList<T> {
	ArrayList<T> al = new ArrayList<T>();
	
	void add(T animal) { al.add(animal); }
	T get(int index) { return al.get(index); }
	boolean remove(T animal) { return al.remove(animal); }
	int size() { return al.size(); }
}

public class prog {
	public static void main(String[] args) {
		AnimalList<LandAnimal> landAnimal = new AnimalList<>();	// Java SE 7부터 생략가능함.
		
		landAnimal.add(new LandAnimal());
		landAnimal.add(new Cat());
		landAnimal.add(new Dog());
		// landAnimal.add(new Sparrow());	// 오류가 발생함.
		
		for (int i = 0; i < landAnimal.size() ; i++) {
			landAnimal.get(i).crying();
		}
	}
}

 


컬렉션 프레임워크(Collection Framework)

  • 다수의 데이터를 쉽고 효과적으로 처리할 수 있는 표준화된 방법을 제공하는 클래스의 집합
  • 데이터를 저장하는 자료구조와 데이터를 처리하는 알고리즘을 구조화하여 클래스로 구현해 놓은 것
  • 인터페이스를 사용하여 구현
    • List, Set, Map

 

 

스트림(Stream)

  • 파일이나 콘솔의 입출력을 직접 다루지 않고, 스트림이라는 흐름 사용
  • 실제 입력이나 출력이 표현된 데이터의 이상화된 흐름
  • java.io 
    • InputStream
    • OutputStream
  • 보조 스트림 : 실제 데이터를 주고받지는 않지만, 다른 스트림의 기능을 향상시키거나 새로운 기능을 추가
    • 여러 개 Stream을 결합해서 확장 가능 

 

람다 표현식(lambda expression)

  • 메소드를 하나의 식으로 표현한 것
  • 객체를 생성하지 않아도, 메소드 사용 가능
  • Java SE 8 부터 람다 표현식이 생겼고, 함수형 프로그래밍 가능
  • 유의사항
    • 매개변수 타입의 추론이 가능한 경우 생략 가능
    • 매개변수가 하나일 때 괄호 생략 가능
    • 함수의 몸체가 하나의 명령문일 때 중괄호 생략 가능
    • 함수의 몸체가 하나의 return 문일 때 중괄호 생략 불가능 
    • return문 대신에 표현식 사용 가능
int min(int x, int y) {
    return x < y ? x : y;
}

// lambda expression
// (매개변수 목록) -> {함수 몸체}
(x, y) -> x < y ? x : y;
new Thread(new Runnable() {
    public void run() {
        System.out.println("전통적인 방식의 일회용 스레드 생성");
    }
}).start();
 
new Thread(()->{
    System.out.println("람다 표현식을 사용한 일회용 스레드 생성");
}).start();

 

 

함수형 인터페이스(functional interface)

  • 람다 표현식을 하나의 변수에 대입할 때 사용하는 참조 변수의 타입
  • 추상 클래스와 다르게, 하나의 추상 메소드만 가진다.
  • 어노테이션을 사용해 함수형 인터페이스 명시
@FunctionalInterface
interface Calc { // 함수형 인터페이스의 선언
    public int min(int x, int y);
}
 
public class Lambda02 {
public static void main(String[] args){
        Calc minNum = (x, y) -> x < y ? x : y; // 추상 메소드의 구현
        System.out.println(minNum.min(3, 4));  // 함수형 인터페이스의 사용
    }
}

 

스트림 API

  • Java SE 8부터 생긴 개념
  • 배열이나 컬렉션에 접근하기 위해서는 반복문이나 반복자(iterator)를 사용해야 한다. -> 가독성 저하, 코드 재사용 불가능
  • 정형화된 데이터의 단점을 스트림 API은 데이터를 추상화해서 다뤄 다양한 방식으로 저장된 데이터를 읽고 쓰기 가능하다.
  • 스트림 API 특징
    • 외부 반복을 통해 작업하는 컬렉션과 다르게 내부 반복을 통해 작업 수행
    • 재사용이 가능한 컬렉션과 다르게 한 번 사용 가능
    • 원본 데이터 변경 X
    • 연산은 필터-맵(filter-map) 기반의 API를 사용해서 성능 최적화
    • parallelStream() 메소드를 통해 손쉬운 병렬 처리 지원
  • 동작 흐름
    • 1. 스트림의 생성
    • 2. 스트림의 중개 연산 (스트림의 변환)
    • 3. 스트림의 최종 연산 (스트림의 사용)

 

Optional Class

  • primitive 타입의 객체를 포장해주는 래퍼 클래스
  • Optional 인스턴스는 모든 타입의 참조 변수를 저장할 수 있다.
  • 예상치 못한 NullPointerException 예외를 제공되는 메소드로 간단히 회피 가능
  • null 값 예외 처리 가능

 

Optional 객체 생성

  • of() 메소드 : null 이 아닌 명시된 값을 가지는 Optional 객체 반환
  • ofNullable() 메소드 사용 
    • 명시된 값이 null이 아니면 명시된 값을 가지는 Optional 객체를 반환하고, 명시된 값이 null이면 비어있는 Optional 객체 반환 
    • null 가능성이 있을 때 사용

JDBC(Java Database Connectivity)

- Java class와 Interface의 집합

- Java 프로그램이 DB에 의존하지 않도록, 공통된 Interface를 제공하는 JDBC 이용


 

JDBC 연결

(1) JDBC driver loading

- 사용하려는 데이터베이스에 맞는 JDBC driver class 등록

- Class라는 class가 존재

- driver Manager class 이용

// 1. JDBC driver Loading
// MySQL 8.0 부터는 아래의 Class 이용
Class.forName("com.mysql.cj.jdbc.Driver");
System.out.println("드라이버 로딩 성공");

 

(2) DBMS와 연결

- 실제로 데이터베이스와 연결된다.

- 성공하면 Connection instance가 생성된다 

- 세션을 통해 생성되는 과정 때문에 부하가 많이 걸린다.

- 자원을 다 사용한 후, 해제 해주어야 한다.(close)

- Database의 Session이 닫힐 수 있도록 쿼리ㅓ 작성

- JDBC URL 

String jdbcURL = "jdbc:mysql://localhost:3306/sqldb?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false";
con = DriverManager.getConnection(jdbcURL, "user", "password");
System.out.println("데이터 베이스 연결 성공!");

 

(3) Statement 생성

1. 일반 statement

2. preparedStatement : 1번의 개량형

3. callable statement 

- 3번은 stored procedure를 호출할 때 사용한다.

- 1, 2번은 구문으로 실행한다.

String sql = "SELECT userId, name, addr FROM usertbl";
pstmt = con.prepareStatement(sql);

 

 

(4) Query 실행

- statement를 이용해서 SQL query를 DBMS에 전달하고 실행한다.

1. execute() 

2. executeQuery() -> SELECT

3. executeUpdate() -> INSERT, UPDATE, DELETE

- 1번 X, 2, 3번 사용

rs = pstmt.executeQuery();

 

 

(5) 결과쿼리(ResultSet)

- 쿼리문을 실행한 결과 record를 가리키는 포인터

- rs.next()를 통해서 다음 행으로 넘어갈 수 있다. -> 가능하면 true, 불가능하면 false return

- rs는 쿼리를 실행시켜서 현재 데이터베이스에 있는 데이터를 그대로 가져와서 자바 프로그램에 전달해준다. 실시간으로 바뀐 데이터는 전달해주지 않는다.

- scrollable cursor은 연동이 되기 때문에 데이터베이스에 직접 접근해야해서 부하가 많이 걸린다.

ResultSet rs = pstmt.executeQuery();

- rs.getString() : String으로 타입 변환(DB의 데이터타입을 Java의 데이터타입으로 변환)

rs.getString(”name”);  // 홍길동을 java string 형태로 가져온다.
rs.getString(2); // 홍길동
// 5. 결과처리
while(rs.next()){ // rs 쭉 실행하기 -> 위에서부터 밑에까지 쭉 내려가세요
    String id = rs.getString(1);
    String name = rs.getString(2);
    String addr = rs.getString(3);
    System.out.println(id+" "+name+" "+addr);
}

Connection pool

- 동시에 많은 사용자에 대한 데이터베이스 쿼리를 제공하기 위해 사용한다.

- connection을 많은 사용자와 공유하게 되면? -> 트랜젝션 발생

- pooling 기법을 사용해서 해결한다.

 

 

pooling

- 속도 향상(생성과 소멸 과정X -> 반납 대여 과정)

- 자원의 효율성

- connection 수를 제어한다.

- 직접 구현하는 것이 아니라, Apache Commons의 DBCP 사용

 

 

Apache Commons 

- 재사용 가능한 자바 기반의 컴포넌트를 모아놓은 통합 프로젝트

- dbcp : Database connection pooling services

 

Thread 

- 생성

- start()

- sleep()

- stop() 사용 금지 -> 직접 구현 권장 : stop() 스레드 종료 , suspend() 스레드 일시 정지, resume() 일시중지 스레드 재시작

- interrupt() : interrupted(), isInterrupted()

- yield() : 스레드가 자신에게 주어진 실행시간을 모두 쓰지 않고, 다른 스레드에게 양보한다. -> 응답성을 높이기 위해 사용

 


sleep() Method 

- sleep(long millisecond) : 일정 시간동안 Thread를 중지 시킨다.

- 지정된 시간 후 자동으로 실행 대기 상태가 된다.

- 일시 정지 상태에서 Interrupt() 호출 시, InterruptException이 발생하면서 깨어난다.

- static method

 

 

join() Method

- 스레드는 각자 독립적으로 실행되지만, 다른 스레드가 종료된 이후 실행해야하는 경우가 있다.

- 실행 대기 상태로 가기 위해서는 join() 메소드를 멤버로 가지는 스레드가 종료되거나, 매가 값으로 주어진 시간이 지나야 한다.

- join()에 인자를 주지 않는 경우, 호출하는 스레드가 무한히 기다리는 상황이 생길 수 있다. -> ex. thread.join(100);

- insatnce method

 

상태 전이도 - sleep()

 

상태 전이도 - yield()

- 우선순위가 동일한 다른 스레드에게 실행을 양보해주고 실행 대기 상태로 이동

- 프로그램의 응답성을 높여준다.

 

상태 전이도 - join()


interrupt() Method

- stop() : 스레드 강제 중지, 편하지만 deprecated(사용금지)

- strat() : 스레드 시작

 

 

Thread 실행 후, 작업이 끝나기 전에 해당 Thread를 중지 시키고 싶은 경우

- interrupt() 이용

- 직접 중지 시키지 않고, 스레드의 내부 상태(Interrupted state)를 변경 시켜준다.

 

 

Thread Interrupt Method

1. interrupted() // static : 현재 실행중인 스레드가 Interrupt가 걸렸는지 알려준다.

- 상태 값 조사 후, false로 값 변경

- 2번과 다르게 값 변경이 이뤄지기 때문에 주의해서 사용해준다.

 

2. isInterrupted() // non static : 특정 스레드가 Interrupt가 잡혔는지 알려준다. 

- 현재 상태 값만 return true or false

 

 

+ Recent posts