책을 읽으면서 새로 알게된 부분 / 추상적으로 알던 부분을 정리하려고 노력했다.

CS를 잘 모르거나 자바를 진짜 처음보는 초심자에게는 책 내용 이해하기가 너무 힘들 것 같은데 기초...가 맞나? 싶다

현재 시점에서 책을 보며 정리하기를 정말 잘했다고 생각한다.

5장: 참조 타입

JVM Runtime Data Area

오라클 레퍼런스 - Run-Time Data Areas

Method Area

  • 클래스 로더에 의해 로드된 클래스/인터페이스 관련 메타데이터(바이트 코드, 시그니처, 런타임 상수 풀 등)가 저장됨
  • 모든 스레드가 공유
  • HotSpot VM에서 Java 7까지는 PermGen, Java 8부터 Metaspace로 관리됨

Run-Time Constant Pool : 컴파일 타임에 알려진 숫자 리터럴, 런타임에 해석되거나 결정되어야 하는 메서드/필드 참조 등 여러 종류의 상수가 들어있음

Heap Area

  • 힙은 모든 클래스 인스턴스(객체) 및 배열의 메모리가 할당되는 런타임 데이터 영역
  • 모든 스레드가 공유
  • GC 돌아감

Stack

각 JVM 스레드는 스레드 생성과 동시에 만들어지는 자기만의 JVM 스택을 가진다

  • 각 스레드마다 존재하는 메서드 호출 실행을 기록
  • 스택 프레임이 쌓인다 → 메서드 상태 정보 저장
    • Local Variables
    • Operand Stacks — 메서드 내 계산을 하기 위한 스택
    • Dynamic Linking — 현재 메서드가 속한 클래스의 런타임 상수 풀 참조
    • Return values for methods / dispatch exceptions
      • Normal Method Invocation Completion : 정상적으로 메서드 호출 완료
      • Abrupt Method Invocation Completion : 비정상적으로 메서드 호출 완료

PC Register

자바 가상 머신은 동시에 많은 실행 스레드를 가질 수 있음 → 각 JVM 스레드는 자신만의 pc(program counter) 레지스터를 가진다. 즉, 스레드가 어디까지 실행했는지 기록하고 있음

Native Method Stacks

자바가 아닌 네이티브 코드(C/C++ 등)로 작성된 메서드(JNI)를 실행할 때 사용되는 스택

  • 스레드 별로 할당됨

알게된 기능

  • System.arraycopy — 배열 복사(shallow copy) 네이티브 메서드임 즉, JNI로 구현되어 있음

열거 타입

열거 상수는 열거 객체로 생성된다.

예를 들어, 열거 타입 Week은 MONDAY부터 SUNDAY까지 있는데 메서드 영역에 생성된 열거 상수가 해당 Week 객체를 각각 참조한다.

java.lang.Enum 클래스 상속

  • ordinal() → enum 상수가 선언된 순서(0부터 시작)를 정수로 반환하는 메서드

6장: 클래스

객체 지향 프로그래밍 : 현실 세계의 물건(객체)처럼, 프로그램을 데이터(상태)와 그 데이터를 다루는 기능(행동)을 한 덩어리로 묶은 객체들로 나누고, 그 객체들이 서로 메시지를 주고받으며 협력하게 만들어 코드를 더 이해하기 쉽고, 수정/확장하기 쉽게 만드는 프로그래밍 방식

 

객체 모델링 : 현실 세계의 객체를 소프트웨어 객체로 설계하는 것

 

메서드 → 객체의 상호작용 수단

 

객체 간 관계

  • 집합 관계
  • 사용 관계 → 객체 간 상호작용
  • 상속 관계 : 상위 / 하위. 일반적으로 상위 객체는 종류, 하위 객체는 구체적인 사물에 해당

정보

  • 캡슐화 : 객체의 속성(데이터)과 행동(메서드)을 하나로 묶고, 내부 구현은 숨긴 채 필요한 것만 외부에 공개하는 것
  • 한 소스 파일에 여러 개 클래스가 있으면 → 컴파일 후 바이트 코드 파일은 클래스 선언한 개수만큼 생긴다
  • 필드 초기값 지정되지 않으면 default 벨류 들어감
  • 도트(.) 연산자

메서드

varargs(...) : 파라미터 개수를 모를 때 사용 (파라미터를 배열로 받는 방식 대신)

  • 맨 마지막 파라미터만 가능
  • 내부적으로 배열로 처리됨 (즉, 배열 타입임)
int sum(int ... values) {
    int s = 0;
    for (int val : values) s += val;
    return s;
}

// 둘 다 가능
sum(1, 2, 3, 4, 5);
sum(new int[] { 1, 2, 3, 4, 5 });

메서드 호출할 때, 컴파일러가 인자 타입을 메서드 파라미터 타입에 맞춰 자동 타입 변환을 하는 경우가 있음 (widening conversion, upcasting, autoboxing/unboxing)

static

정적 멤버

  • 정적 필드
    • 생성자에서 초기화 작업 불가
    • 필드 선언과 동시에 초기값을 주거나, static block 을 이용해 초기화 작업
  • 정적 메서드

클래스 로더가 클래스를 로딩해서 메서드 메모리 영역에 적재 → 클래스별로 관리됨

접근 제한자 (Access Modifier)

어디에서 이 멤버(클래스/필드/메서드/생성자)에 접근할 수 있나

접근제한자 최상위 클래스(top-level) 중첩 클래스(nested) 필드 생성자 메서드
public
protected
default
private

적용 대상

  • protected 같은 패키지면 누구나, 또는 다른 패키지라도 상속받은 클래스에서 접근 가능
  • default 는 같은 패키지에서만 접근 가능
  • private 은 같은 클래스 내부에서만 접근 가능 (같은 클래스의 다른 인스턴스 접근 가능)

어노테이션

코드에 붙이는 메타데이터 → 컴파일러/도구/프레임워크가 어노테이션을 읽고 동작을 바꾸게 만들 수 있음

@Target — 타겟

어노테이션을 적용할 수 있는 대상 지정하는 데에 사용

java.lang.annotation.ElementType 열거 상수로 정의되어 있음

오라클 레퍼런스 - ElementType

ElementType 설명(붙일 수 있는 위치) 예시
TYPE 클래스/인터페이스/enum/record 선언 @A class C {}
FIELD 필드 선언(enum 상수 포함) @A int x; / @A ENUM_CONST
METHOD 메서드 선언 @A void m() {}
PARAMETER 파라미터 선언(메서드/생성자) void m(@A int x) {}
CONSTRUCTOR 생성자 선언 @A C() {}
LOCAL_VARIABLE 로컬 변수 선언 @A int t = 0;
ANNOTATION_TYPE 어노테이션 타입 선언 @A @interface X {}
PACKAGE 패키지 선언 @A package p;
TYPE_PARAMETER 타입 파라미터 선언 class C<@A T> {}
TYPE_USE 타입이 사용되는 위치 모두(변수 타입/캐스트/제네릭 인자/throws 등) List<@A String> xs; / (@A String)s / throws @A IOException
MODULE 모듈 선언 @A module m {}
RECORD_COMPONENT 레코드 컴포넌트 record R(@A int x) {}

@Retention — 유지 정책

java.lang.annotation.RetentionPolicy

Java Platform, Standard Edition Java API Reference

  • SOURCE : 소스상에만 어노테이션 정보 유지. 컴파일 후에는 사라짐 즉, 바이트 코드(.class)에는 남지 않는다.
  • CLASS : 바이트 코드에는 어노테이션 정보가 남아있음. 근데, 실행 중일 때 VM에선 유지되지 않아서 리플렉션으로 조회할 수 없음
  • RUNTIME : .class에도 기록되고, 실행 중에도 유지되어서 리플렉션으로 조회 가능

(여기서 리플렉션은 실행 중에 JVM이 들고 있는 클래스/메서드/필드 정보(메타데이터)를 조회/조작할 수 있는 기능)

 

CLASS는 왜 필요한가? → 라이브러리 같은 jar 파일에는 소스 파일이 아닌 .class 파일만 있음 IDE 같은게 이걸 읽어서 정보를 얻을 수 있음

 

Lombok이 제공하는 어노테이션들을 살펴보면, SOURCECLASS가 사용되고 있음을 볼 수 있다.

  • @GetterSOURCE 이다. 메서드 만들고 바이트 코드에서는 어노테이션 사라짐
  • @NonNullCLASS 이다. 컴파일 때 null-check 메서드가 삽입되는데, 문서적인 역할(documentary role)도 가지고 있다고 함