[ Java ] - Class Loader(2)

NaHyun_kkiimm·2024년 3월 26일
0

Java

목록 보기
1/3
post-thumbnail

클래스 로딩 시점

  • java -verbose:class 클래스명.java 명령어로 확인해보자 : 클래스 로딩 디버거
  • 터미널 경로를 해당 클래스가 있는 파일 경로로 변경해야 한다.

1) 인스턴스 생성

(1) 생성하지 않는 경우

public class test {
    public static void main(String[] args) {
    }
}

class Temp {
}

[ 실행 결과 ]

  • Temp 클래스가 로드되지 않는 결과가 나온다.

(2) 생성하는 경우

public class test {
    public static void main(String[] args) {
        Temp tmp = new Temp();
    }
}

class Temp {
}

[ 실행 결과 ]

  • Temp 클래스가 로드된 것을 확인할 수 있다.

Q) 위와 같은 결과가 나온 이유

클래스가 로딩되는 방식은 크게 2가지가 있다.

  • 명시적 로딩 : import 키워드 사용하여 클래스를 명시적으로 로드한다.
  • 암시적 로딩 : 클래스 인스턴스를 생성하거나(new)하거나
    클래스의 정적 멤버에 접근할 때 암시적으로 로드된다.

  • 첫 번째 코드 : Temp 클래스를 명시적으로 로드하지 않기 때문에 암시적 로딩에 의존하게 된다.
    하지만, Temp 클래스의 인스턴스를 생성하거나 정적 멤버에 접근하지 않았기에 암시적 로딩마저 일어나지 않아, Temp 클래스는 로드되지 않는다.
  • 두 번째 코드 : Temp 클래스의 인스턴스를 생성하기 때문에 암시적 로딩이 일어나 Temp 클래스가 로드된다.

2) static 변수(정적 변수) 호출

public class test {
    public static void main(String[] args) {
        String value = Temp.value;
    }
}

class Temp extends Parent{
    static String value="value";
}

class Parent {
}

[ 실행 결과 ]

  • 부모 객체(Parent)를 먼저 로드하고, 자식 객체(Temp)를 그 다음 로드하는 결과가 나온다.

Q) 왜 부모 클래스가 먼저 로드되는 걸까?

자바 상속의 특징 중 일부를 확인해보자

  • 자식은 부모의 요소를 전부 가져온다. (단, 생성자는 제외)
  • 상속받지 않는 클래스들은 모두 최상위 클래스 java.lang.Object 클래스를 묵시적으로 상속받는다.
    즉, 자식 클래스(Temp)는 부모 클래스인 (Parent) 클래스를 먼저 로드하게 된다.

※ static 변수로 선언된 모든 자원들은 클래스 로딩시 생성되고, JVM이 종료되면 그 값은 메모리에서도 종료된다.


3) static final 상수 호출

public class test {
    public static void main(String[] args) {
        String value = Temp.value;
    }
}

class Temp extends Parent{
    static final String value="value";
}

class Parent {
}

[ 실행 결과 ]

  • Temp 클래스가 로드되지 않음에 따라 부모 클래스(Parent) 또한 로드되지 않는 결과가 나온다.

Q) 위와 같은 결과가 나온 이유

static final String value는 컴파일 타임 상수
즉, 런타임 때 클래스 로더를 통해 로딩되지 않아도 그 값을 알 수 있는 값이기 때문이다.


4) static 메서드 호출

public class test {
    public static void main(String[] args) {
        Temp.getInstance();
    }
}

class Temp{
    static void getInstance() {
    }
}

[ 실행 결과 ]

  • Temp클래스가 로드되었다.

5) 내부 클래스

public class test {

    public static void main(String[] args) {
        System.out.println(new Holder().new Inner());
    }

}

class Holder {
    class Inner {
    }
}

[ 실행 결과 ]

  • Holder클래스와 Holder클래스의 내부 클래스(Inner)가 로드되었다.

Q) 위와 같은 결과가 나온 이유

외부 클래스(Holder)의 내부 클래스(Inner)를 사용하기 위해선 외부 클래스를 먼저 인스턴스화해야 하기에 Holder클래스가 먼저 로드되고, 그 다음으로 Inner클래스가 로드된다.


6) 내부 클래스의 static 메서드

public class test {

    public static void main(String[] args) {
        Holder.Inner inner = new Holder.Inner();
        System.out.println(inner);
    }

}

class Holder {
    static class Inner {
    }
}

[ 실행 결과 ]

  • 5) 때와는 달리 Holder클래스가 로드되지 않았다.

Q) 5)와 달리 6)의 결과가 나온 이유

static 클래스는 static 변수나 static 메서드 등 처럼 JVM 동작 시, 한 번만 로드되는 개념으로 받아드려선 안 된다.

아래 예시를 보았을 때, static 참조 변수 static String str은 실행되면 한 번만 로드되기에 str1str2는 같은 객체를 가리키게 된다.

또한, 클래스는 객체로 만들 때마다 메모리의 다른 위치에 저장되기에 Inner inner1Inner inner2는 각자 다른 객체를 가리키며 false가 나오게 된다.

이러한 메커니즘대로라면 static class의 참조 변수는 같은 객체를 가리켜 true가 나온다고 생각할 수 있지만, 결과적으로 false가 나온다.
이 말은 즉슨, static classstatic 변수와 달리 동작 시, 한 번만 로드되는 개념이 아니라는 것이다.

[ 예시 ]

public class test {

    static String str = new String("Hello");

    static class InnerStatic {
    }

    class Inner {
    }

    public static void main(String[] args) {
        String str1 = str;
        String str2 = str;
        System.out.println(str1 == str2);
        
        test.Inner inner1 = new test().new Inner();
        test.Inner inner2 = new test().new Inner();
        System.out.println(inner1 == inner2);

        InnerStatic tmp1 = new InnerStatic();
        InnerStatic tmp2 = new InnerStatic();
        System.out.println(tmp1 == tmp2);
    }
}

// true
// false
// false

7) static 내부 class의 static 변수 호출

public class test {

    public static void main(String[] args) {
        System.out.println(Holder.Inner.num);
    }

}

class Holder {
    static class Inner {
        static int num=1;
    }
}

[ 실행 결과 ]

  • static변수를 갖는 Holder의 내부 클래스 Inner만 로드되는 결과를 볼 수 있다.

Q) 만약, 6번을 설명하기 위해 사용한 예시의 InnerStatic처럼 static내부 클래스에 static String str=new String("hello");를 넣고 이를 참조하는 2개의 객체 변수를 비교했을 때 결과값은 무엇이 나올까?

A) static 클래스가 아니기에 한 번만 로드된다. 때문에 2개의 변수는 같은 객체를 참조하게 된다.


후기

처음 시작할 땐 이렇게 자세히까지 알아야하나 싶었는데 확실히 코드에 적용시켜 공부하니 중요한 내용이었음을 깨닫게 되었다.
"세상에 나쁜 공부는 없다" 오늘도 1승 획득


참고

☕ 내부 클래스(Inner Class) 장점 & 종류 총정리

☕ 클래스는 언제 메모리에 로딩 & 초기화 되는가 ❓

profile
이 또한 지나가리라

0개의 댓글

관련 채용 정보