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


217

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


답변:


271

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

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

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

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

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


바, 나는 의견 에 대한 앵커 링크 를 얻을 수없는 것 같지만 , 그 의견 :#comment113712_253507
Zach Lysobey

1
@matt b 정적 중첩 클래스가 Outer 클래스의 인스턴스 멤버에 액세스 할 수없는 경우 Outer 클래스의 인스턴스 멤버와 어떻게 상호 작용합니까?
Geek

1
@Geek가 발견 얼마나 @mattb 그러나, 태양 페이지 모순 : A static nested class interacts with the instance members of its outer class (and other classes) just like any other top-level class : 워드 프로세서 전에 그냥 단락 것을 말한다면 어떻게 가능 Static nested classes do not have access to other members of the enclosing class 어쩌면 그들은이 말씀을 전합니다 : A nested (non-static) class interacts with the instance members of its outer class (and other classes) just like any other top-level class
tonix

1
@DavidS 링크 주셔서 감사합니다! 그래, 내가 틀렸다, 지금 내 의견을 읽고 내 문구가 잘못되었음을 알 수 있습니다. 당신의 말처럼 An inner class interacts with the instance members through an implicit reference to its enclosing class, 그리고 또 다른 흥미로운 특성 아웃이 점 non-static inner classes뿐만 아니라로 anonymous inner classeslocal classes defined inside a block: 그들은 모두 가질 수 없습니다no-arg 원인 생성자 컴파일러 암시 위해 모든 생성자의 인수 순서를 앞에 추가합니다은 포함하는 인스턴스의 참조를 전달합니다 수업. 꽤 간단합니다.
tonix

1
정적 내부 클래스를 사용하여 전용 생성자가있는 외부 클래스를 인스턴스화 할 수 있습니다. 빌더 패턴에서 사용됩니다. 당신은 내부 클래스와 똑같이 할 수 없습니다.
seenimurugan

47

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

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


4
나는 틀릴 수 있지만 내부 클래스가 아닌 정적 중첩 클래스의 예처럼 보입니다. 또한 예제에서 중첩 클래스의 주변 클래스에있는 인스턴스 변수에 액세스 할 수 없도록 지정합니다.
ColinD

Colin의 권리-C #에는 내부 클래스가 없으며 중첩 클래스가 있습니다. C #의 정적 중첩 클래스는 Java의 정적 중첩 클래스와 동일하지 않습니다.
Jon Skeet

2
중첩 유형은 C #이 Java에 비해 매우 올바른 영역 중 하나입니다. 나는 항상 의미 론적 / 논리적 정확성에 감탄한다.
nawfal

3
@nawfal : 예, C # 언어가 얼마나 잘 디자인되고 지정되었는지에 대해 경탄합니다.
Jon Skeet

1
@JonSkeet 당신은 그 낄낄 거림에 대한 기사 또는 블로그가 있습니까? 나는 "niggles"로 찾은 것을 통해 가고
싶습니다

27

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


'외부'클래스가 최종적이므로 전혀 인스턴스화 할 수없는 경우이 인수가 의미가 있습니까? 외부 클래스에 대한 참조를 보유 / 유지하는 것은 쓸모가 없기 때문에 후자가 최종입니다.
getsadzeg

10

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

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


8

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

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


7

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

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

이러한 종류의 사용법에 대한 예제는 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;
    }
}


4

간단한 예 :

package test;

public class UpperClass {
public static class StaticInnerClass {}

public class InnerClass {}

public static void main(String[] args) {
    // works
    StaticInnerClass stat = new StaticInnerClass();
    // doesn't compile
    InnerClass inner = new InnerClass();
}
}

비 정적 인 경우 상위 클래스의 인스턴스에서 클래스를 인스턴스화 할 수 없습니다 (메인이 정적 함수 인 예에서는 아닙니다)


StaticInnerClass는 사실 정적 중첩 / 내부 클래스가 아닙니다. 최상위 정적 클래스입니다.
theRiley

2

정적 대 일반의 이유 중 하나는 클래스 로딩과 관련이 있습니다. 부모 생성자에서 내부 클래스를 인스턴스화 할 수 없습니다.

추신 : 나는 항상 '중첩'과 '내부'가 상호 교환 가능하다는 것을 이해했습니다. 용어에 미묘한 뉘앙스가있을 수 있지만 대부분의 Java 개발자는 둘 중 하나를 이해할 것입니다.


1

정적 내부 클래스가 아닌 경우 메모리 누수가 발생할 수 있지만 정적 내부 클래스는 메모리 누수를 방지합니다. 외부 클래스에 상당한 데이터가 있으면 응용 프로그램의 성능이 저하 될 수 있습니다.


'정적 내부'는 용어의 모순입니다.
Lorne의 후작

1
@EJP는, 쳇 ... 사람들이 정말 얻을 오프 누군가가 "정적 내부 클래스"를 언급 언제든지이 밖으로을 지정하여 ...
Sakiboy

0

성능 차이에 대해서는 잘 모르지만 정적 중첩 클래스는 둘러싸는 클래스의 인스턴스의 일부가 아닙니다. 내부 클래스가 아닌 경우 정적 중첩 클래스를 만드는 것이 더 간단합니다.

Java에서 항상 변수를 최종 변수로 만드는 이유와 약간 비슷합니다. 최종 변수가 아닌 경우 재미있는 변수가 있다는 것을 알고 있습니다. 정적 중첩 클래스 대신 내부 클래스를 사용하는 경우 적절한 이유가 있습니다.


내부 클래스는 '클로징 클래스의 인스턴스의 일부'도 아닙니다.
Lorne의 후작

내부 클래스는 엔 클로징 클래스에 따라 존재하며 엔 클로징 클래스의 멤버에 대한 친밀한 액세스 권한이 있으므로 실제로는 엔 클로징 클래스의 일부입니다. 사실, 그것은 회원입니다.
theRiley

0

비 정적 클래스가 아닌 정적 중첩 클래스를 사용하면 공간이 절약 될 수 있습니다. 예를 들어 : Comparator클래스 내부를 구현 한다고 Student라고 말합니다.

public class Student {
  public static final Comparator<Student> BY_NAME = new ByName();
  private final String name;
  ...
  private static class ByName implements Comparator<Student> {
    public int compare() {...}
  }
}

그런 다음 static새 학생 인스턴스가 생성 될 때마다 새 클래스를 인스턴스화하지 않고 Student 클래스에 하나의 비교기가 있습니다.


-1

내부 계급의 장점

  1. 한 번 사용
  2. 캡슐화 지원 및 향상
  3. 가독성
  4. 개인 필드 액세스

외부 클래스가 없으면 내부 클래스가 존재하지 않습니다.

class car{
    class wheel{

    }
}

내부 클래스에는 네 가지 유형이 있습니다.

  1. 정상적인 내부 클래스
  2. 메서드 로컬 이너 클래스
  3. 익명의 내부 클래스
  4. 정적 내부 클래스

포인트 ---

  1. 정적 내부 클래스에서 외부 클래스의 정적 멤버에만 액세스 할 수 있습니다.
  2. 내부 클래스 내부에서 정적 멤버를 선언 할 수 없습니다.
  3. 외부 클래스의 정적 영역에서 일반 내부 클래스를 호출하기 위해.

    Outer 0=new Outer(); Outer.Inner i= O.new Inner();

  4. 외부 클래스의 인스턴스 영역에서 일반 내부 클래스를 호출하기 위해.

    Inner i=new Inner();

  5. 외부 클래스 외부에서 일반 내부 클래스를 호출하기 위해.

    Outer 0=new Outer(); Outer.Inner i= O.new Inner();

  6. inside Inner class이 클래스는 내부 클래스를 가리 킵니다.

    this.member-current inner class outerclassname.this--outer class

  7. 내부 클래스 적용 가능한 수정자는-public, default,

    final,abstract,strictfp,+private,protected,static

  8. outer $ inner는 내부 클래스 이름의 이름입니다.

  9. 인스턴스 메소드 내부의 내부 클래스 다음 외부 클래스의 정적 및 인스턴스 필드에 액세스 할 수 있습니다.

정적 메소드 내부의 10.inner 클래스는 정적 필드에만 액세스 할 수 있습니다.

외부 클래스.

class outer{

    int x=10;
    static int y-20;

    public void m1() {
        int i=30;
        final j=40;

        class inner{

            public void m2() {
                // have accees x,y and j
            }
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.