[TIL] 2월 16일

yeon·2021년 2월 16일
0

자바의 정석 12장 지네릭스, 열거형, 애너테이션

열거형(enums) (691p)

관련된 상수를 같이 묶어놓은 것

열거형의 정의와 사용

  • 열거형 상수는 "=="로 비교할 수 있다.
  • <, > 와 같은 비교 연산자는 사용 불가
    • compareTo() 사용 가능
    • 비교 대상이 같으면 0, 왼쪽이 크면 양수, 오른쪽이 크면 음수 반환
  • 사실, 열거형 상수 하나하나가 객체이다.

java.lang.Enum 클래스 (693p)

  • 모든 열거형의 조상
  • Enum 클래스에 정의된 메서드
    • values() : 열거형의 모든 상수를 배열로 반환
    • ordinal() : 열거형 상수가 정의된 순서(0부터 시작)를 정수로 반환
    • name() : 열거형 상수의 이름을 문자열로 반환
    • valueOf(Cloass enum Type, String name) : 지정된 열거형에서 name과 일치하는 열거형 상수 반환

열거형에 멤버 추가하기 (695p)

  • 열거형의 생성자는 묵시적으로 private, 외부에서 호출 불가

  • 예시

    enum Direction {
    		EAST(1), SOUTH(5), WEST(-1), NORTH(10);
    		
    		private final int value;
    		Direction (int value) {
    			this.value = value;
    		}
    
    		public int getValue() {
    			return value;
    		}
    }
    • 열거형의 인스턴스 변수는 반드시 final 이어야 하는건 아니지만, value는 열거형 상수의 값을 저장하므로 final로 선언
    • 열거형의 생성자 : 접근제어자를 추가하진 않았지만 묵시적으로 private이다. 외부에서 호출 불가
    • EAST, SOUTH, WEST, NORTH 하나하나가 Direction의 객체이다.
  • 예제

    public class EnumEx2 {
        public static void main(String[] args) {
            for (Direction d : Direction.values()) {
                System.out.printf("%s=%d%n", d.name(), d.getValue());
            }
    
            Direction d1 = Direction.EAST;
            Direction d2 = Direction.of(1);
    
            System.out.printf("%s : %d%n", d1.name(), d1.getValue());
            System.out.printf("%s : %d%n", d2.name(), d2.getValue());
    
            System.out.println(Direction.EAST.rotate(1));
        }
    }
    
    enum Direction {
        EAST(1, ">"), SOUTH(2, "V"), WEST(3, "<"), NORTH(4, "^");
    
        private static final Direction[] DIR_ARR = Direction.values();
        private final int value;
        private final String symbol;
    
        Direction(int value, String symbol) {
            this.value = value;
            this.symbol = symbol;
        }
    
        public int getValue() {
            return value;
        }
    
        public String getSymbol() {
            return symbol;
        }
    
        public static Direction of(int dir) {
            if (dir < 1 || dir > 4) {
                throw new IllegalArgumentException("Invalid value :" + dir);
            }
            return DIR_ARR[dir - 1];
        }
    
        // 방향을 회전시키는 메서드. num의 값만큼 90도씩 시계방향으로 회전한다.
        public Direction rotate(int num) {
            num = num % 4;
    
            if (num < 0) {
                num += 4;   // num이 음수일때는 시계반대 방향으로 회전
            }
            return DIR_ARR[(value - 1 + num) % 4];
        }
    }
    • Direction[] DIR_ARR = Direction.values();
      • values() : 열거형에 있는 값들을 배열로 반환
    • Direction of() 메서드
      • 유효성 검사
      • 0~3 범위를 벗어나면 예외가 발생하도록 함

미션3 코드 수정 후 피드백 내용

  • enum을 선언할 때는 한줄에 하나씩 선언한다.

    public enum Color {
    		WHITE('p'),
    		BLACK('P');
    ...
    }

JVM (호눅스 수업 복습)

JVM이란

  • 컴퓨터에게 자바 프로그램을 동작하게 하는 가상머신
  • 소프트웨어로 구현된 하드웨어 (software implementation of a physical machine)
  • Write Once, Run Anywhere
  • 자바 어플리케이션은 JVM하고만 상호작용해서 OS와 하드웨어에 독립적이다.

    → 다른 OS에서도 실행 가능

    단, JVM은 운영체제에 종속적이여서 해당 OS에서 실행 가능한 JVM이 필요하다.

  • Java byte코드로 컴파일될 수 있는 다른 언어도 실행가능

JDK와 JRE

  • JDK : 자바 개발 도구(Java Development Kit) 개발자용
    • JRE + 개발에 필요한 실행파일 (javac.exc 등)
  • JRE : 자바 실행 환경(Java Runtime Environment) 일반 사용자용
    • 자바로 작성된 응용프로그램이 실행되기 위한 최소 환경
    • JVM + Java API (자바 클래스 라이브러리)

JDK의 bin 디렉토리에 있는 주요 실행 파일들

  • javac.exe : 자바 컴파일러, 자바 소스코드를 바이트 코드로 컴파일한다.
  • java.exe : 자바 인터프리터, 컴파일러가 생성한 바이트 코드를 해석하고 실행한다.
  • javap.exe : 역어셈블러, 컴파일된 클래스 파일을 원래의 소스로 변환한다.
  • javedoc.exe : 자동 문서 생성기, 소스파일에 있는 주석(/** */)을 이용하여 Java API 문서와 같은 형식의 문서 생성
  • jar.exe : 압축 프로그램, 클래스파일과 프로그램 실행에 관련된 파일을 하나의 jar파일(.jar)로 압축하거나 압축 해제

JVM architecture

호눅스 수업과 아래의 두 블로그를 참고하여 내용정리함

The JVM Architecture Explained - DZone Java

[Java] 클래스로더란?

자바 프로그램을 실행하면

  1. 컴파일러가 자바파일을 class 파일로 컴파일한다.
  2. class 파일이 JVM에 올라간다.
  3. JVM에 class 파일을 로드하고 실행한다.(load & execute)

JVM은 세가지의 subsystem(부분 시스템)으로 이루어짐

  • Class Loader Subsystem
  • Runtime Data Area
  • Execution Engine

Class Loader Subsystem

  • 클래스 파일을 실행하면 class loader가 클래스 파일을 메모리에 로딩한다.
  • 동적으로 클래스 로딩 가능 → 모든 파일을 로딩하는 것이 아니라 필요할때 로딩한다.
  1. Loading : 클래스 정보(FQCN)를 메모리에 로딩
  • FQCN : Fully Qualified Class Name
    • 패키지명까지 포함되어 있는 식별자
  • 메소드 영역에 올라간다.

(1) Bootstrap Class Loader

  • 가장 높은 우선순위가 부여되는 loader, 최상위 클래스 로더이다.

  • rt.jar에 담긴 JDK클래스 파일을 로딩한다.

    • rt.jar 파일이란?

      rt는 runtime을 의미한다.

      rt.jar는 코어 자바클래스(자바 런타임 환경에서)의 콜렉션이다.

      JVM에서 rt.jar파일에 담긴 플래스파일들을 런타임시 메모리에 올린다. String 클래스, System 클래스와 같은 것들이 rt.jar에 포함되어 있다.

(2) Extension Class Loader

  • jre/lib/ext 폴더나 java.ext.dirs 환경 변수로 지정된 폴더에 있는 클래스 파일을 로딩한다.

(3) Application Class Loader

  • 자가 어플리케이션 구동을 위해 직접 작성한 대부분 클래스는 이 어플리케이션 클래스 로더에 의해 로딩된다.
  1. Linking
  • 클래스 파일 검사
  • 정적 변수를 기본값으로 저장
  1. Initialization
  • 정적 변수 초기값으로 저장
  • static block (static { }) 실행

Runtime Data Area

  1. Method Area (메소드 영역)
  • 클래스 정보 저장, static 변수 포함
  • JVM 하나당 메소드 영역 하나
  • 공유되는 자원임
  1. Heap Area (힙 영역)
  • new 로 생성되는 객체들이 저장됨
  • 인스턴스 변수, 배열이 저장됨
  • 하나의 JVM당 하나의 Heap 영역
  • 멀티 스레드 환경에서 Method 영역과 Heap 영역을 공유해서 not thread-safe 하다.
  1. Stack Area
  • 각 스레드당 하나씩 생성
  • 지역 변수는 stack memory에서 생성됨
  • 스레드들이 자원을 공유하지 않아서 thread-safe 하다
  1. PC Registers
  • 스레드마다 생성됨
  • 현재 실행중인 instruction(지시)를 가르키는 주소를 가짐
  • instruction이 실행되고 나면, 다음 instrunction이 업데이트 된다.

Execution Engine

  • Execution Engine은 바이트 코드를 읽고 하나씩 실행시킨다. (piece by piece)
    • 바이트 코드는 Runtime Data Area에 배치된다. 메소드 영역에
  1. Interpreter
  • 인터프리터는 바이트 코드를 빠르게 해석하지만, 실행이 느리다.
  • 하나의 메서드가 여러번 호출될때마다 매번 해석해야한다는 단점이 있다.
  1. JIT Compiler
  • 바이트 코드를 하드웨어 기계어로 변환해주는 컴파일러
  • 인터프리터의 단점을 보완한 것이 JIT compiler이다.
  • 반복되는 코드가 있으면 JIT compiler를 사용한다.
  1. Garbage Collector
  • heap에서 쓸모 없어진 것들을 제거한다.

바이트 코드는 어디에 저장되나?

  • 메소드 영역에

정적 변수는 어디에, 언제 저장되나?

  • 클래스 로더가 로딩을 하는 순간 메소드 영역에 저장된다.

인스턴스 변수는 어디에 저장되나?

  • heap 영역에 저장된다. 지역변수는 stack에 저장됨

JVM이 동작하는 것을 학습하기 위한 예제 - 코드의 실행순서를 예측해보자

public class Hello {
    public static int age = 25;

    static {
        System.out.println("static!");
    }
    public Hello(){
        System.out.println("Hello init");
    }

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

</> 실행 결과
static!
Hello
  • Hello.java파일을 실행하면 컴파일러가 Hello.class파일로 컴파일 하고

    → Hello.class 파일이 JVM에 올라가고

    → class loader가 클래스 파일을 메모리에 로드하고

    → Liking : 이때, static 변수 age가 기본값으로 저장됨 (age = 0)

    → initialization : age가 초기값으로 저장됨(age = 25), static block 실행 ( static! 출력)

    → Hello 출력

  • 생성자는 객체를 생성할때 실행되므로 위의 상황에서는 실행되지 않는다.

  • 아래의 예시는 class loader가 동적으로 클래스파일을 로딩한다는 것을 추가로 보여준다.

    public class Hello {
        public static int age = 25;
    
        static {
            System.out.println("static!");
        }
    
        public Hello() {
            System.out.println("Hello init");
        }
    
        public static void main(String[] args) {
            Hello h = new Hello();
            System.out.println("Hello");
            Hell.foo();
        }
    }
    
    class Hell {
        static {
            System.out.println("static hell");
        }
    
        static void foo() {
            System.out.println("foo");
        }
    }
    
    </> 실행 결과
    static!
    Hello init
    Hello
    static hell
    foo
    • Hello의 static 블록 먼저 출력 (static!)

      → Hello h = new Hello(); 로 객체 생성해서 생성자 호출 (Hello init 출력)

      → Hello 출력

      → Hell의 static 블록 출력 (클래스 로더가 처음부터 모든 클래스를 로드하지 않고 필요할때마다 동적으로 로드한다.)

      static hell 출력

      → foo() 메소드 호출(foo 출력)


rotate : 회전하다(시키다)

convert : 전환시키다

corresponding : ~에 해당(상응)하는)


오늘 한일

  • 어제 수업때 다룬 JVM에 대해 학습하고 정리했다.
    • 영어로 된 글을 보며 정리하다가 해석이 어려운 부분에서 한글로 설명된 글을 찾아보며 정리하다보니 시간이 오래걸렸다. 그래도 계속 영어로 된 글들을 찾아보고 학습하자
  • 자바의 정석 enum 파트 학습
  • 미션3 피드백 받은 것들 코드 수정

2개의 댓글

comment-user-thumbnail
2021년 2월 16일

java.exe : 자바 컴파일러, 자바 소스코드를 바이트 코드로 컴파일한다.
java.exe : 자바 인터프리터, 컴파일러가 생성한 바이트 코드를 해석하고 실행한다.
오타 발견! ㅋㅋㅋ

1개의 답글