• 카테고리

    질문 & 답변
  • 세부 분야

    기타 (개발 · 프로그래밍)

  • 해결 여부

    미해결

클래스의 로드 시점

22.03.28 21:58 작성 조회수 638

2

안녕하세요! 강의 너무나 잘 듣고 있습니다.

public class Settings {
    private Settings() {
    }
 
    private static class SettingsHolder {
        private static final Settings INSTANCE = new Settings();
    }
 
    public static Settings getInstance() {
        return SettingsHolder.INSTANCE;
    }
}

로드 시점에 관한 질문입니다.  getInstance가 호출 될때 SettingsHolder가 JVM에 로드된다고 말씀하셨습니다. 자바는 잘 모르지만, 동적으로 로드가 된다고 해석했습니다.

 

public class Settings {
    private static final Settings INSTANCE = new Settings();
 
    private Settings() {
    }
 
    public static Settings getInstance() {
        return INSTANCE;
    }
}

그렇다면  이른 초기화 방식도, 마치 SettingsHolder가 그러하듯, 필요로 할 때 동적으로 로드 될 순 없나요? 필요로 할 때 로드된다면 SettingsHolder를 필요로 하지 않을 테니 말이죠.

 

그럼에도 불구하고 static inner class를 사용하는 건 반드시 이유가 있을 테니.. 하여 제 나름대로 찾아보고 테스트해 본 결과 자바 파일에 정의된 기본 클래스들은 실행 시 로드됨을 확인했습니다. 모든 클래스가 실행 시 로드되는진 확실하진 않지만 이와 관련된 JVM의 로드 정책에 대해서 간략하게 설명 부탁드립니다. :)  

답변 5

·

답변을 작성해보세요.

7

Settings에 getInstance()라는 static 메소드 말고 다른 메소드도 있다고 가정을 하고 생각해 보시면 어떤 차이가 있는지 이해할 수 있을 것 같습니다. 편의상 Settings를 A, 그 안에 들어있는 홀더를 B라고 했을 때 B는 A가 아무리 사용되더라도 로딩이 되지 않고 오로지 A에서 getInstance를 호출했을 때 그때 B의 인스턴스를 만들게 되니까 초기화 지연 기법이라고 한 것입니다.

그리고 초기화 지연 기법이 의미가 있으려면 그렇게 생성하는 인스턴스가 생성하는데 오래 걸리거나, 많은 리소스를 필요로 하는 경우인데 위의 예제에선 오히려 코드만 복잡하게 할 뿐 Holder를 쓰지 않아도 됩니다.

저 역시 홀더가 반드시 좋다고 설명한 수업이 아닙니다. 초기화 지연 기법이 필요하다면 그렇게 할 수도 있다고 설명한거죠.

"그렇다면 아래와 같이 Holder를 사용하지 않는 싱글톤 구현 클래스또한  "최초로 사용될 때" 로딩되므로 이른 초기화라고 말할 수 있나요?" 네 해당 코드는 이른 초기화가 맞긴 한데 "최초로 사용될 때" 로딩되기 때문이 아니라.. 해당 클래스가 로딩 되는 시점에 인스턴스가 생기기 때문이죠.

홀더를 사용한 코드가 초기화 지연 기법인 이유는 A라는 클래스가 또다른 static 메소드를 호출 할 때 이미 로딩이 됐더라도, A라는 타입의 인스턴스는 생기지 않고, 오직 getInstance가 호출 됐을 때 B라는 홀더가 로딩되면서 그 안에서 A인스턴스가 생기기 때문입니다. A 클래스가 로딩 될 때가 아니라 이미 로딩된 다음에 나중에 A 인스턴스가 생겼으니까요.

그런데 다시 말하지만, 홀더가 항상 좋다고 설명한 것도 아니고 그냥 이런 특징이 있으니 필요한 경우엔 이렇게 쓸 수도 있다는 것입니다.

1

"관심사 밖이다"라는 표현이 어떤 뜻인지 잘 모르겠지만, 내부 정적 클래스도 다른 클래스와 마찬가지로 최초로 사용이 될 때 로딩이 됩니다.

2번 질문에 대해서는 다시 또 classpath에 대해 학습하시고 글을 남기시면 리뷰해 드리겠습니다. 구체적으로 클래스패스란 무엇이며 어떻게 설정하는지 학습하시면 될 것 같습니다.

1

JVM의 클래스로딩에 대해서 먼저 공부를 하신 다음 요약하시면 제가 리뷰를 해드리겠습니다.

0

--님의 프로필

--

질문자

2022.03.30

답변 감사합니다.

"내부 정적 클래스도 다른 클래스와 마찬가지로 최초로 사용이 될 때 로딩이 됩니다."  제가 궁금한 부분을 정확히 말씀해주셨습니다. 내부 정적 클래스도 다른 클래스들과 마찬가지로 최초로 사용될 때 로딩, 초기화 과정을 거친다는 말씀이시겠죠? 그렇다면 아래와 같이 Holder를 사용하지 않는 싱글톤 구현 클래스또한  "최초로 사용될 때" 로딩되므로 이른 초기화라고 말할 수 있나요?

public class Settings {
    private static final Settings INSTANCE = new Settings();
 
    private Settings() {
    }
 
    public static Settings getInstance() {
        return INSTANCE;
    }
}

 

강의에서 제가 이해한바로는 아래와 같은 싱글톤 구현 기법은 사용되지 않음에도 불구하고 초기화가 일어나므로 자원의 낭비가 될 수 있다고 이해했습니다. 그런데 두 방법 모두 필요에 의해 최초로 사용될 때 로딩된다면 holder를 사용하지 않는 싱글톤 방식이 자원의 낭비라고 말 할 수 있는지 궁금합니다.

 

초기화에 관한 문서를 찾아봐도 top-level 클래스가 사용되지 않음에도 불구하고 초기화 되는 조건은 찾지 못했습니다. 

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

  • T is a class and an instance of T is created.
  • T is a class and a static method declared by T is invoked.
  • A static field declared by T is assigned.
  • A static field declared by T is used and the field is not a constant variable (§4.12.4).
  • T is a top-level class, and an assert statement (§14.10) lexically nested within T is executed.

 

저는 제 생각이 항상 옳다고 생각하지 않는 사람입니다.

많은 개발자들이 holder를 사용하데엔 분명 이유가 있다고 생각하며 기선님이 말씀해주신 자원 낭비를 방지하는 목적도 이해가 됩니다. 다만.. 지금 단계에서 holder가 불필요하다가 아닌 holder를 사용하지 않은 것과 사용 한 것의 차이가 명확히 이해되지 않습니다.

0

--님의 프로필

--

질문자

2022.03.29

1. 자바의 클래스 로더는 세 가지 종류가 있더군요

 

1. bootstrap class loader

2. extension class loader

3. system class loader

 

제 질문과 관련된 세 번째 로더 system class loader는 classpath에 존재하는 클래스의 초기화를 담당하며 일반적으로 개발자가 정의한 클래스는 classpath 내에 존재하게 되므로 로드 시점에 아래와 같이 싱글톤 인스턴스를 만드는 방법은 이른 초기화라는 것이 이제는 납득이 됩니다.

public class Settings {
    private static final Settings INSTANCE = new Settings();
 
    private Settings() {
    }
 
    public static Settings getInstance() {
        return INSTANCE;
    }
}

 

https://stackoverflow.com/questions/24538509/does-the-java-classloader-load-inner-classes

여담으로 stackoverflow에서 좋은 글을 발견한 것 같아 공유합니다.

 

제 나름 정리하면 기본적으로 class Loader는 요청이 올 때 클래스를 로딩하는 것이고 system class loader 또한 프로그램이 로딩될 때  특정 위치에 있는 클래스를 로드하는 것을 요청받았 을뿐 내부 정적 클래스는 system class loader의 관심사 밖이다 정도로 이해하면 될까요?

 

2. 어딘가에선 classpath가 환경변수라고 하는데 제 기준 환경변수는 jdk의 경로입니다. 만약 그렇다면 jdk의 경로만으로 system class loader 제가 정의한 클래스의 위치를 어떻게 아는거죠?