[java] Java의 정적 중첩 클래스, 왜?

Java 코드를보고 있었고 LinkedList정적 중첩 클래스를 사용한다는 것을 알았습니다 Entry.

public class LinkedList<E> ... {
...

 private static class Entry<E> { ... }

}

일반적인 내부 클래스가 아닌 정적 중첩 클래스를 사용하는 이유는 무엇입니까?

내가 생각할 수있는 유일한 이유는 Entry가 인스턴스 변수에 액세스 할 수 없기 때문에 OOP 관점에서 캡슐화가 더 우수하다는 것입니다.

그러나 다른 이유, 아마도 성능이있을 수 있다고 생각했습니다. 무엇일까요?

노트. 나는 내 용어가 정확하기를 희망하며 정적 내부 클래스라고 불렀지 만 이것이 잘못되었다고 생각합니다 : http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html



답변

링크하는 Sun 페이지는이 둘 사이에 몇 가지 주요 차이점이 있습니다.

중첩 클래스는 둘러싸는 클래스의 멤버입니다. 정적이 아닌 중첩 클래스 (내부 클래스)는 비공개로 선언 된 경우에도 포함 클래스의 다른 멤버에 액세스 할 수 있습니다. 정적 중첩 클래스는 둘러싸는 클래스의 다른 멤버에 액세스 할 수 없습니다.

참고 : 정적 중첩 클래스는 다른 최상위 클래스와 마찬가지로 외부 클래스 (및 다른 클래스)의 인스턴스 멤버와 상호 작용합니다. 실제로 정적 중첩 클래스는 패키징 편의를 위해 다른 최상위 클래스에 중첩 된 최상위 클래스입니다.

LinkedList.Entry최상위 클래스 사용할 필요는 없습니다 LinkedList( 동일한 개념 Entry과 같이 정적 중첩 클래스가있는 다른 인터페이스도 있습니다 Map.Entry). 또한 LinkedList의 멤버에 액세스 할 필요가 없기 때문에 정적 인 것이 좋습니다. 훨씬 더 깔끔한 방법입니다.

으로 존 소총 지적 , 난 당신이 중첩 클래스는 정적 인로 시작하는 것입니다 사용하고 정말 당신의 사용에 따라 비 정적해야하는 경우 다음 결정하는 경우가 더 좋은 아이디어라고 생각합니다.


답변

내 마음에, 질문은 당신이 내부 클래스를 볼 때마다 다른 방법이어야합니다. 실제로 명시적이고 명확하지 않은 IMO가 아닌 복잡성과 암시 적 참조를 가진 내부 클래스이어야합니다. 포함하는 클래스의?

C # 팬으로 편향되어 있습니다. C #에는 중첩 유형이 있지만 내부 클래스와 동등한 것은 없습니다. 나는 아직 내부 클래스를 놓쳤다 고 말할 수 없다. 🙂


답변

여기에 고려해야 할 명백한 메모리 보존 문제가 있습니다. 비 정적 내부 클래스는 ‘외부’클래스에 대한 암시 적 참조를 유지하므로 내부 클래스의 인스턴스가 강력하게 참조되면 외부 인스턴스도 강력하게 참조됩니다. 외부 클래스가 가비지 수집되지 않은 경우 참조하지 않는 것처럼 보이기 때문에 헤드 스크래치가 발생할 수 있습니다 .


답변

정적이 아닌 내부 클래스에는 외부 클래스의 인스턴스를 가리키는 숨겨진 필드가 있습니다. 따라서 Entry 클래스가 정적이 아닌 경우 필요하지 않은 액세스 권한 외에 3 개가 아닌 4 개의 포인터가 있습니다.

일반적으로 C의 “struct”와 같이 데이터 멤버의 컬렉션으로 작동하는 클래스를 정의하는 경우 정적으로 만드는 것이 좋습니다.


답변

정적 내부 클래스는 빌더 패턴에서 사용됩니다. 정적 내부 클래스는 전용 생성자 만있는 외부 클래스를 인스턴스화 할 수 있습니다. 따라서 정적 내부 클래스를 사용하여 전용 생성자 만있는 외부 클래스를 인스턴스화 할 수 있습니다. 내부 클래스에 액세스하기 전에 외부 클래스의 객체를 만들어야하므로 내부 클래스와 동일한 작업을 수행 할 수 없습니다.

class OuterClass {
    private OuterClass(int x) {
        System.out.println("x: " + x);
    }

    static class InnerClass {
        public static void test() {
            OuterClass outer = new OuterClass(1);
        }
    }
}

public class Test {
    public static void main(String[] args) {
        OuterClass.InnerClass.test();
        // OuterClass outer = new OuterClass(1); // It is not possible to create outer instance from outside.
    }
}

x를 출력합니다 : 1


답변

정적 중첩 클래스는 외부 클래스 멤버에 액세스 할 수 없으므로 다른 외부 클래스와 같습니다.

패키징 편의를 위해 가독성을 위해 정적 중첩 클래스를 하나의 외부 클래스로 묶을 수 있습니다. 이 외에 정적 중첩 클래스의 다른 유스 케이스는 없습니다.

이러한 종류의 사용법에 대한 예제는 Android R.java (자원) 파일에서 찾을 수 있습니다. 안드로이드의 Res 폴더에는 레이아웃 (스크린 디자인 포함), 드로어 블 폴더 (프로젝트에 사용되는 이미지 포함), 값 폴더 (문자열 상수 포함) 등이 있습니다.

모든 폴더가 Res 폴더의 일부인 경우 Android 도구는 내부 폴더 각각에 대한 많은 정적 중첩 클래스를 내부에 포함하는 R.java (자원) 파일을 생성합니다.

다음은 android에서 생성 된 R.java 파일의 모양과 느낌입니다.
여기에서는 패키징 편의를 위해서만 사용합니다.

/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.techpalle.b17_testthird;

public final class R {
    public static final class drawable {
        public static final int ic_launcher=0x7f020000;
    }
    public static final class layout {
        public static final int activity_main=0x7f030000;
    }
    public static final class menu {
        public static final int main=0x7f070000;
    }
    public static final class string {
        public static final int action_settings=0x7f050001;
        public static final int app_name=0x7f050000;
        public static final int hello_world=0x7f050002;
    }
}


답변

에서 http://docs.oracle.com/javase/tutorial/java/javaOO/whentouse.html :

둘러싸는 인스턴스의 비공개 필드 및 메서드에 액세스해야하는 경우 비 정적 중첩 클래스 (또는 내부 클래스)를 사용하십시오. 이 액세스가 필요하지 않은 경우 정적 중첩 클래스를 사용하십시오.