Java 내부 클래스 및 정적 중첩 클래스


1765

Java에서 내부 클래스와 정적 중첩 클래스의 주요 차이점은 무엇입니까? 디자인 / 구현이이 중 하나를 선택하는 역할을합니까?


65
Joshua Bloch의 답변은 효과적인 Java 읽기 item 22 : Favor static member classes over non static
Raymond Chenon에서

4
기록을 위해, 그것은 같은 책의 제 3 판에있는 항목 24입니다.
ZeroCool

답변:


1696

로부터 자바 튜토리얼 :

중첩 클래스는 정적 및 비 정적의 두 가지 범주로 나뉩니다. static으로 선언 된 중첩 클래스를 정적 ​​중첩 클래스라고합니다. 정적이 아닌 중첩 클래스를 내부 클래스라고합니다.

정적 중첩 클래스는 다음과 같이 클래스 이름을 사용하여 액세스합니다.

OuterClass.StaticNestedClass

예를 들어 정적 중첩 클래스의 객체를 만들려면 다음 구문을 사용하십시오.

OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

내부 클래스의 인스턴스 인 객체는 외부 클래스의 인스턴스 내에 존재합니다. 다음 클래스를 고려하십시오.

class OuterClass {
    ...
    class InnerClass {
        ...
    }
}

InnerClass의 인스턴스는 OuterClass의 인스턴스에만 존재할 수 있으며 둘러싸는 인스턴스의 메서드와 필드에 직접 액세스 할 수 있습니다.

내부 클래스를 인스턴스화하려면 먼저 외부 클래스를 인스턴스화해야합니다. 그런 다음이 구문을 사용하여 외부 개체 내에 내부 개체를 만듭니다.

OuterClass outerObject = new OuterClass()
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

참조 : Java Tutorial-중첩 클래스

완전성을 위해 , 인스턴스를 묶지 않는 내부 클래스 와 같은 것도 있습니다 .

class A {
  int t() { return 1; }
  static A a =  new A() { int t() { return 2; } };
}

여기서, new A() { ... }정적 콘텍스트 내에서 정의 된 클래스 와 둘러싸 인스턴스가 없다.


130
당신이 직접 정적 중첩 클래스를 가져올 수 있다는 마음, 당신은 (파일의 상단에) 할 수있는, 즉 : import OuterClass.StaticNestedClass; 다음 클래스를 참조 단지 OuterClass한다.
Camilo Díaz Repka

4
@Martin 내부 클래스를 생성하는이 관용구에 대한 특정 기술적 이름이 OuterClass.InnerClass innerObject = outerObject.new InnerClass();있습니까?
Geek

7
개인 정적 중첩 클래스의 사용은 무엇입니까? OuterClass.StaticNestedClass와 같이 외부에서 인스턴스를 생성 할 수 없다고 생각합니다. nestedObject = new OuterClass.StaticNestedClass ();
RoboAlex

1
@ Ilya Kogan : 정적 또는 비 정적 인 부모 클래스 필드에 액세스 할 수 있음을 알았습니다 (자식 클래스가 비 정적 클래스 인 경우). 그 기능을 몇 번 활용했지만 어떤 종류의 메모리 모델인지 궁금합니다. 그들은 따라왔다? OOP 개념이 별도의 개념으로 적용됩니까? 그들이 OOP 내에서 실제로 적합한 곳에 없다면. 나에게 친구 수업 인 것 같습니다 :)
Mubashar

4
@martin, 나는이 스레드에 엄청나게 늦게 온다는 것을 알고 있지만 : 그것은 변수 a입니다. 그것은 클래스의 정적 필드입니다. A. 'new A () {int t () {리턴 2; }} '은 다음과 같이 단순히 정적 필드에 다른 객체를 할당 한 경우보다 더 정적입니다. class B {static void main (string s) {Aa = new A ()}} (A & B in same package) 이것은 A를 정적 클래스로 만들지 않습니다. 링크 된 스레드에 인용 된 참조에서 "정적 컨텍스트"라는 문구는 매우 모호합니다. 사실, 이것은 그 스레드의 많은 의견에서 언급되었습니다.
GrantRobertson

599

자바 튜토리얼은 말한다 :

용어 : 중첩 클래스는 정적 및 비 정적의 두 가지 범주로 나뉩니다. static으로 선언 된 중첩 클래스를 정적 ​​중첩 클래스라고합니다. 정적이 아닌 중첩 클래스를 내부 클래스라고합니다.

일반적으로 "nested"와 "inner"라는 용어는 대부분의 프로그래머가 상호 교환 적으로 사용하지만 내부 및 정적을 모두 포함하는 올바른 "nested class"라는 용어를 사용합니다.

클래스는 무한 으로 중첩 될 수 있습니다 . 예를 들어, 클래스 A는 클래스 D를 포함하는 클래스 C를 포함하는 클래스 B를 포함 할 수 있습니다. 그러나 일반적으로 설계가 좋지 않기 때문에 둘 이상의 클래스 중첩 수준은 거의 없습니다.

중첩 클래스를 생성 할 수있는 세 가지 이유가 있습니다.

  • 조직 : 때로는 클래스를 다른 클래스의 네임 스페이스로 정렬하는 것이 가장 합리적입니다. 특히 다른 컨텍스트에서 사용되지 않을 때
  • 액세스 : 중첩 클래스는 포함 클래스의 변수 / 필드에 특수하게 액세스 할 수 있습니다 (정확하게 내부 또는 정적 여부에 관계없이 중첩 클래스의 종류에 따라 변수 / 필드가 달라짐).
  • 편의성 : 모든 새 유형에 대해 새 파일을 작성해야하는 것은 번거 롭습니다. 특히 유형이 한 컨텍스트에서만 사용되는 경우에는 더욱 그렇습니다.

Java 에는 네 가지 종류의 중첩 클래스가 있습니다. 간단히 말해 다음과 같습니다.

  • static class : 다른 클래스의 정적 멤버로 선언
  • 내부 클래스 : 다른 클래스의 인스턴스 멤버로 선언
  • 로컬 내부 클래스 : 다른 클래스의 인스턴스 메소드 내에서 선언
  • 익명의 내부 클래스 : 로컬 내부 클래스와 비슷하지만 일회성 객체를 반환하는 표현식으로 작성

좀 더 자세하게 설명하겠습니다.


정적 클래스

정적 클래스는 포함하는 클래스의 인스턴스와 관련이 없으므로 이해하기 가장 쉬운 종류입니다.

정적 클래스는 다른 클래스의 정적 멤버로 선언 된 클래스입니다. 그냥 다른 정적 멤버처럼, 이러한 클래스는 네임 스페이스로 포함하는 클래스 그 용도에 불과 걸이 정말 예 : 클래스 염소는 클래스의 정적 멤버로 선언 코뿔소 패키지에 피자 이름으로 알려져있다 pizza.Rhino.Goat은 .

package pizza;

public class Rhino {

    ...

    public static class Goat {
        ...
    }
}

솔직히 정적 클래스는 클래스가 이미 패키지에 의해 네임 스페이스로 나뉘어져 있기 때문에 가치가없는 기능입니다. 정적 클래스를 만드는 유일한 이유는 그러한 클래스가 포함하는 클래스의 전용 정적 멤버에 액세스 할 수 있기 때문이지만 정적 클래스 기능이 존재하는 데는 이것이 절름발이입니다.


내부 클래스

내부 클래스는 다른 클래스의 비 정적 멤버로 선언 된 클래스입니다.

package pizza;

public class Rhino {

    public class Goat {
        ...
    }

    private void jerry() {
        Goat g = new Goat();
    }
}

정적 클래스와 마찬가지로 내부 클래스는 포함하는 클래스 이름 pizza.Rhino.Goat 로 규정 된 것으로 알려져 있지만 포함 클래스 내부에서는 간단한 이름으로 알 수 있습니다. 그러나, 내부 클래스의 모든 인스턴스가 포함 된 클래스의 특정 인스턴스에 묶여 : 위의 염소 에서 만든 제리 , 암시 적으로 연결되어 코뿔소의 경우 제리 . 그렇지 않으면, 염소 를 인스턴스화 할 때 관련 Rhino 인스턴스를 명시 적으로 만듭니다 .

Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();

( 이상한 구문 에서 내부 유형을 염소 로 참조한다는 점에 유의 하십시오. Java는 코뿔소 부분 에서 포함 유형을 유추합니다 . 예, 새로운 rhino.Goat () 도 나에게 더 의미가 있습니다.)

이것이 우리에게 무엇을 가져 옵니까? 내부 클래스 인스턴스는 포함하는 클래스 인스턴스의 인스턴스 멤버에 액세스 할 수 있습니다. 이러한 둘러싸 인스턴스 멤버는 내부 클래스 내에 칭한다 통해 , 그들의 간단한 이름하지 통해 ( 내부 클래스는 내부 클래스 인스턴스가 아닌 연관된 함유 클래스 인스턴스를 참조) :

public class Rhino {

    private String barry;

    public class Goat {
        public void colin() {
            System.out.println(barry);
        }
    }
}

내부 클래스 에서 포함 클래스 의이 클래스를 Rhino.this 로 참조 할 수 있으며 이를 사용 하여 멤버를 참조 할 수 있습니다 ( 예 : Rhino.this.barry) .


현지 이너 클래스

로컬 내부 클래스는 메서드 본문에 선언 된 클래스입니다. 이러한 클래스는 포함 메소드 내에서만 알려져 있으므로 인스턴스화 할 수 있으며 포함 메소드 내에서 멤버에 액세스 할 수 있습니다. 장점은 로컬 내부 클래스 인스턴스가 포함 된 메서드의 최종 로컬 변수에 연결되어 액세스 할 수 있다는 것입니다. 인스턴스가 포함하는 메소드의 최종 로컬을 사용하는 경우 변수가 범위를 벗어난 경우에도 변수는 인스턴스 작성시 보유한 값을 유지합니다 (이는 사실상 Java의 조잡하고 제한된 클로저 버전입니다).

로컬 내부 클래스는 클래스 또는 패키지의 멤버가 아니므로 액세스 수준으로 선언되지 않습니다. (단, 자체 클래스의 멤버는 일반 클래스와 같은 액세스 레벨을 갖습니다.)

로컬 내부 클래스는 인스턴스 메서드에 선언되어있는 경우, 내부 클래스의 인스턴스를 포함하는 방법의 보유 인스턴스에 연결되어 인스턴스의 생성시에, 그래서 포함하는 클래스의 인스턴스 멤버는 인스턴스처럼 액세스 할 수 있습니다 내부 클래스. 로컬 내부 클래스는 이름을 통해 간단하게 인스턴스화 됩니다 . 예를 들어 로컬 내부 클래스 Cat 은 예상대로 new this.Cat ()가 아닌 new Cat () 로 인스턴스화됩니다 .


익명의 내부 클래스

익명의 내부 클래스는 구문 적으로 편리한 로컬 내부 클래스를 작성하는 방법입니다. 가장 일반적으로, 로컬 내부 클래스는 포함 메소드가 실행될 때마다 최대 한 번만 인스턴스화됩니다. 로컬 내부 클래스 정의와 단일 인스턴스화를 하나의 편리한 구문 형식으로 결합 할 수 있다면 좋을 것입니다. 클래스의 이름을 생각할 필요가 없다면 도움이 될 것입니다. 코드에 포함 된 이름이 더 좋습니다). 익명의 내부 클래스는 다음 두 가지를 모두 허용합니다.

new *ParentClassName*(*constructorArgs*) {*members*}

이것은 ParentClassName 을 확장하는 명명되지 않은 클래스의 새 인스턴스를 반환하는 표현식 입니다. 자신 만의 생성자를 제공 할 수 없습니다. 오히려, 단순히 수퍼 생성자를 호출하는 암시 적으로 제공되므로 제공된 인수는 수퍼 생성자에 맞아야합니다. (부모가 여러 생성자를 포함하는 경우, "가장 간단한"것을 "가장 단순"이라고하며, 자세히 배우고 싶지 않은 다소 복잡한 규칙 집합에 의해 결정됩니다. NetBeans 또는 Eclipse가 말하는 것에주의하십시오.)

또는 구현할 인터페이스를 지정할 수 있습니다.

new *InterfaceName*() {*members*}

이러한 선언은 Object를 확장하고 InterfaceName을 구현하는 명명되지 않은 클래스의 새 인스턴스를 만듭니다 . 다시, 당신은 당신 자신의 생성자를 제공 할 수 없습니다; 이 경우 Java는 암묵적으로 수행 할 작업을 생성하지 않습니다 (이 경우 생성자 인수는 절대 존재하지 않습니다).

익명의 내부 클래스에 생성자를 제공 할 수는 없지만 초기화 블록 (메서드 외부에 배치 된 {} 블록)을 사용하여 원하는 설정을 계속 수행 할 수 있습니다.

익명의 내부 클래스는 하나의 인스턴스로 로컬 내부 클래스를 만드는 덜 유연한 방법이라는 점을 명심하십시오. 다중 인터페이스를 구현 하거나 Object 이외의 클래스를 확장하는 동안 인터페이스를 구현 하거나 자체 생성자를 지정 하는 로컬 내부 클래스를 원한다면 일반 명명 된 로컬 내부 클래스를 작성해야합니다.


39
좋은 이야기 고마워 그래도 한 가지 실수가 있습니다. Rhino.this.variableName으로 인스턴스 내부 클래스에서 외부 클래스의 필드에 액세스 할 수 있습니다.
Thirler

2
익명의 내부 클래스에 대해 자체 생성자를 제공 할 수는 없지만 이중 괄호 초기화를 사용할 수 있습니다. c2.com/cgi/wiki?DoubleBraceInitialization
Casebash

30
좋은 설명이지만 정적 내부 클래스가 가치가 없다는 것에 동의하지 않습니다. 정적 내부 클래스의 사용에 크게 의존하는 빌더 패턴의 큰 변형은 rwhansen.blogspot.com/2007/07/… 을 참조하십시오 .
Mansoor Siddiqui 2016 년

9
또한 정적 내부 클래스는 쓸모가 없다는 데 동의하지 않습니다. 내부 클래스에 열거 형을 원하면 내부 클래스를 정적으로 만들어야합니다.
누군가 어딘가에

9
개인 정적 중첩 클래스도 매우 유용합니다. 클래스를 갖고 싶지만 공개하고 싶지는 않습니다. LinkedList <T>의 Entry <T> 또는 액티비티 내부의 AsyncTasks (Android) 등과 같습니다.
Lorenzo Dematté

150

위의 답변에서 실제 차이점이 명확하지 않다고 생각합니다.

먼저 용어를 올바르게 얻으십시오.

  • 중첩 클래스는 소스 코드 수준에서 다른 클래스에 포함 된 클래스입니다.
  • 정적 수정 자로 선언하면 정적 입니다.
  • 정적이 아닌 중첩 클래스를 내부 클래스라고합니다. (비 정적 중첩 클래스를 유지합니다.)

마틴의 대답은 지금까지입니다. 그러나 실제 질문은 중첩 클래스를 정적 ​​선언의 목적은 무엇입니까?

당신이 사용하는 정적 중첩 클래스를 그냥 그들이 함께 또는 중첩 된 클래스가 독점적으로 둘러싸는 클래스에 사용되는 경우 국소 속하는 경우 함께 클래스를 유지하려는 경우. 정적 중첩 클래스와 다른 모든 클래스 사이에는 의미 상 차이가 없습니다.

정적이 아닌 중첩 클래스 는 다른 짐승입니다. 익명의 내부 클래스와 마찬가지로 이러한 중첩 클래스는 실제로 클로저입니다. 즉, 주변 범위와 둘러싼 인스턴스를 캡처하여 액세스 할 수있게합니다. 아마도 예가 그것을 분명히 할 것입니다. 컨테이너의 스텁을 참조하십시오.

public class Container {
    public class Item{
        Object data;
        public Container getContainer(){
            return Container.this;
        }
        public Item(Object data) {
            super();
            this.data = data;
        }

    }

    public static Item create(Object data){
        // does not compile since no instance of Container is available
        return new Item(data);
    }
    public Item createSubItem(Object data){
        // compiles, since 'this' Container is available
        return new Item(data);
    }
}

이 경우 하위 항목에서 상위 컨테이너로의 참조를 원합니다. 비 정적 중첩 클래스를 사용하면 약간의 작업없이 작동합니다. 구문을 사용하여 컨테이너의 엔 클로징 인스턴스에 액세스 할 수 있습니다 Container.this.

다음과 같은 추가 하드 코어 설명 :

Java 바이트 코드를 보면 컴파일러가 (정적이 아닌) 중첩 클래스에 대해 생성하는 것이 훨씬 명확해질 수 있습니다.

// class version 49.0 (49)
// access flags 33
public class Container$Item {

  // compiled from: Container.java
  // access flags 1
  public INNERCLASS Container$Item Container Item

  // access flags 0
  Object data

  // access flags 4112
  final Container this$0

  // access flags 1
  public getContainer() : Container
   L0
    LINENUMBER 7 L0
    ALOAD 0: this
    GETFIELD Container$Item.this$0 : Container
    ARETURN
   L1
    LOCALVARIABLE this Container$Item L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 1
  public <init>(Container,Object) : void
   L0
    LINENUMBER 12 L0
    ALOAD 0: this
    ALOAD 1
    PUTFIELD Container$Item.this$0 : Container
   L1
    LINENUMBER 10 L1
    ALOAD 0: this
    INVOKESPECIAL Object.<init>() : void
   L2
    LINENUMBER 11 L2
    ALOAD 0: this
    ALOAD 2: data
    PUTFIELD Container$Item.data : Object
    RETURN
   L3
    LOCALVARIABLE this Container$Item L0 L3 0
    LOCALVARIABLE data Object L0 L3 2
    MAXSTACK = 2
    MAXLOCALS = 3
}

보시다시피 컴파일러는 숨겨진 필드를 만듭니다 Container this$0. 이것은 엔 클로징 인스턴스를 지정하기 위해 Container 유형의 추가 매개 변수가있는 생성자에서 설정됩니다. 소스에서이 매개 변수를 볼 수는 없지만 컴파일러는 내재적으로 중첩 된 클래스에 대해이를 생성합니다.

마틴의 예

OuterClass.InnerClass innerObject = outerObject.new InnerClass();

따라서 (바이트 코드)와 같은 호출로 컴파일됩니다.

new InnerClass(outerObject)

완전성을 위해 :

익명 클래스 이름이없고 나중에 참조 할 수없는 정적이 아닌 중첩 클래스의 완벽한 예입니다.


17
"정적 중첩 클래스와 다른 모든 클래스 사이에는 의미 상 차이가 없습니다." 중첩 클래스를 제외하고는 부모의 개인 필드 / 방법을 볼 수 있고 부모 클래스는 중첩의 개인 필드 / 방법을 볼 수 있습니다.
Brad Cupit

정적이 아닌 내부 클래스가 잠재적으로 대규모 메모리 누수를 유발하지 않습니까? 마찬가지로 리스너를 만들 때마다 누출이 발생합니까?
G_V

3
@G_V 내부 클래스의 인스턴스가 외부 클래스에 대한 참조를 유지하기 때문에 메모리 누수가 발생할 가능성이 있습니다. 이것이 실제 문제인지 여부는 외부 클래스와 내부 클래스의 인스턴스에 대한 참조가 어디서 어떻게 사용되는지에 달려 있습니다.
jrudolph

94

위의 답변 중 어느 것도 응용 프로그램 디자인 측면에서 중첩 클래스와 정적 중첩 클래스의 실제 차이점을 설명하지 않습니다.

오버뷰

중첩 된 클래스 는 비 정적 또는 정적 일 수 있으며 각 경우 에 다른 클래스 내에 정의 된 클래스 입니다. 중첩 클래스는 클래스를 둘러싸고있다 역할 만 존재해야 중첩 된 클래스는 다른 클래스 (뿐만 아니라 바깥 쪽)에 의해 유용 경우, 최고 수준의 클래스로 선언되어야한다.

Nonstatic Nested class : 포함하는 클래스의 엔 클로징 인스턴스와 암시 적으로 연결되므로 엔 클로징 인스턴스의 메서드 및 액세스 변수를 호출 할 수 있습니다. 비 정적 중첩 클래스의 일반적인 용도 중 하나는 Adapter 클래스를 정의하는 것입니다.

정적 중첩 클래스 : 둘러싸는 클래스 인스턴스에 액세스 할 수없고 메소드를 호출 할 수 없으므로 중첩 클래스가 둘러싸는 클래스의 인스턴스에 액세스 할 필요가없는 경우 사용해야합니다. 정적 중첩 클래스의 일반적인 용도는 외부 객체의 구성 요소를 구현하는 것입니다.

결론

따라서 디자인 관점에서 두 가지의 주요 차이점은 정적이 아닌 중첩 클래스는 컨테이너 클래스의 인스턴스에 액세스 할 수 있지만 정적은 할 수 없다는 것 입니다.


: 당신의 결론에서 "정적 할 수없는 동안", 컨테이너의 정적 인스턴스조차도? 확실한?
VdeX

정적 중첩 클래스의 일반적인 용도는 RecyclerView 및 ListView의 ViewHolder 디자인 패턴입니다.
Hamzeh Soboh

1
많은 경우에, 짧은 대답이 더 명확하고 좋습니다. 이것은 그러한 예입니다.
Eric Wang

32

간단히 말해서 Java는 클로저를 제공하지 않기 때문에 주로 중첩 클래스가 필요합니다.

중첩 클래스는 다른 엔 클로징 클래스의 본문 내에 정의 된 클래스입니다. 정적 및 비 정적의 두 가지 유형이 있습니다.

이들은 클래스의 멤버로 취급되므로 네 가지 액세스 지정자 중 하나를 지정할 수 있습니다 private, package, protected, public. 우리는 선언 public또는 패키지 전용으로 만 최상위 클래스를 사용할 수 있습니다 .

내부 클래스 일명 스택이 아닌 클래스는 비공개로 선언 된 경우에도 최상위 클래스의 다른 멤버에 액세스 할 수 있지만 정적 중첩 클래스는 최상위 클래스의 다른 멤버에 액세스 할 수 없습니다.

public class OuterClass {
    public static class Inner1 {
    }
    public class Inner2 {
    }
}

Inner1정적 내부 클래스이며 Inner2정적이 아닌 내부 클래스입니다. 그들 사이의 주요 차이점은 객체를 독립적으로 Inner2만들 수있는 외부가없는 인스턴스를 만들 수 없습니다 Inner1.

Inner 클래스를 언제 사용 하시겠습니까?

상황을 생각 Class A하고 Class B, 관련 Class B액세스에 요구 사항을 Class A회원들과 Class B만 관련이 있습니다 Class A. 내부 수업이 그림에 들어옵니다.

내부 클래스의 인스턴스를 만들려면 외부 클래스의 인스턴스를 만들어야합니다.

OuterClass outer = new OuterClass();
OuterClass.Inner2 inner = outer.new Inner2();

또는

OuterClass.Inner2 inner = new OuterClass().new Inner2();

정적 Inner 클래스를 언제 사용 하시겠습니까?

정적 내부 클래스가 둘러싸는 클래스 / 상위 클래스의 인스턴스와 관계가 없음을 알 때 정적 내부 클래스를 정의합니다. 내부 클래스가 외부 클래스의 메서드 또는 필드를 사용하지 않는 경우 공간 낭비 일 뿐이므로 정적으로 만드십시오.

예를 들어 정적 중첩 클래스의 객체를 만들려면 다음 구문을 사용하십시오.

OuterClass.Inner1 nestedObject = new OuterClass.Inner1();

정적 중첩 클래스의 장점은 포함하는 클래스 / 상위 클래스의 개체가 필요하지 않다는 것입니다. 이를 통해 응용 프로그램이 런타임에 생성하는 객체 수를 줄일 수 있습니다.


3
당신은 의미 OuterClass.Inner2 inner = outer.new Inner2();했습니까?
Erik Kaplun

4
static inner용어의 모순입니다.
user207421

그리고 내부 클래스는 '비 스택 클래스'라고도하지 않습니다. 코드가 아닌 텍스트에는 코드 서식을 사용하지 말고 텍스트에는 코드 서식을 사용하십시오.
user207421

30

다음은 Java 내부 클래스와 정적 중첩 클래스의 주요 차이점과 유사점입니다.

그것이 도움이되기를 바랍니다!

이너 클래스

  • 인스턴스와 정적 메서드 및 필드 모두 외부 클래스에 액세스 할 수 있습니다.
  • 인스턴스를 묶는 클래스의 인스턴스와 연결되어 있으므로 인스턴스화하려면 먼저 외부 클래스의 인스턴스가 필요합니다 ( 키워드 위치 참고 ).

    Outerclass.InnerClass innerObject = outerObject.new Innerclass();
  • 정적 멤버 자체를 정의 할 수 없습니다

  • 클래스 또는 인터페이스 선언을 가질 수 없습니다

정적 중첩 클래스

  • 외부 클래스 인스턴스 메서드 또는 필드에 액세스 할 수 없습니다

  • 인스턴스화하는 클래스의 인스턴스와 연관되지 않았습니다 .

    OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();

유사점

  • 내부 클래스 모두 외부 클래스개인 필드 및 메소드 에도 액세스 할 수 있습니다.
  • 또한 외부 클래스내부 클래스개인 필드 및 메소드 에 액세스 할 수 있습니다
  • 두 클래스 모두 개인, 보호 또는 공개 액세스 수정자를 가질 수 있습니다.

중첩 클래스를 사용해야하는 이유

Oracle 문서에 따르면 몇 가지 이유가 있습니다 ( 전체 문서 ).

  • 한 장소에서만 사용되는 클래스를 논리적으로 그룹화하는 방법입니다 . 클래스가 다른 클래스에만 유용 할 경우 해당 클래스에 클래스를 포함시키고 두 클래스를 함께 유지하는 것이 논리적입니다. 이러한 "헬퍼 클래스"를 중첩하면 패키지가 더욱 간소화됩니다.

  • 캡슐화가 증가합니다. A와 B라는 두 가지 최상위 클래스를 고려하십시오. 여기서 B는 그렇지 않으면 비공개로 선언 된 A의 멤버에 액세스해야합니다. 클래스 A 내에 클래스 B를 숨기면 A의 구성원을 비공개로 선언하고 B가 액세스 할 수 있습니다. 또한 B 자체는 외부 세계에서 숨길 수 있습니다.

  • 보다 읽기 쉽고 유지 관리가 쉬운 코드로 이어질 수 있습니다. 최상위 클래스 내에 작은 클래스를 중첩하면 코드가 사용되는 위치에 더 가깝게 배치됩니다.


26

일반적으로 따르는 규칙은 다음과 같습니다.

  • 최상위 클래스 내의 정적 클래스중첩 클래스입니다.
  • 최상위 클래스의 비 정적 클래스내부 클래스 이며 두 가지 형식이 더 있습니다.
    • 로컬 클래스 -메소드 또는 생성자 본문과 같이 블록 내에 선언 된 명명 된 클래스
    • 익명 클래스 -표현식과 명령문으로 인스턴스가 작성된 이름없는 클래스

그러나 기억해야 할 몇 가지 다른 은 다음과 같습니다.

  • 최상위 수준 클래스와 정적 중첩 클래스는 정적 중첩 클래스의 경우 외부 [부모] 클래스의 개인 정적 필드 / 방법에 대한 정적 참조를 만들 수 있고 그 반대도 마찬가지라는 점을 제외하면 의미 적으로 동일합니다.

  • 내부 클래스는 외부 [parent] 클래스의 둘러싸는 인스턴스의 인스턴스 변수에 액세스 할 수 있습니다. 그러나 모든 내부 클래스에 엔 클로징 인스턴스가있는 것은 아닙니다. 예를 들어 정적 초기화 블록에서 사용되는 익명 클래스와 같은 정적 컨텍스트의 내부 클래스는 그렇지 않습니다.

  • 익명 클래스는 기본적으로 부모 클래스를 확장하거나 부모 인터페이스를 구현하며 다른 클래스를 확장하거나 더 이상 인터페이스를 구현하기위한 추가 절이 없습니다. 그래서,

    • new YourClass(){}; 방법 class [Anonymous] extends YourClass {}
    • new YourInterface(){}; 방법 class [Anonymous] implements YourInterface {}

어떤 질문을 언제 사용해야하는지 더 큰 질문이 남아 있다고 생각합니다. 글쎄, 그것은 주로 어떤 시나리오를 다루고 있는지에 달려 있지만 @jrudolph의 대답을 읽는 것이 결정을 내리는 데 도움이 될 수 있습니다.


15

중첩 클래스 : 클래스 내부 클래스

유형 :

  1. 정적 중첩 클래스
  2. 비 정적 중첩 클래스 [내부 클래스]

차:

비 정적 중첩 클래스 [내부 클래스]

정적이 아닌 중첩 클래스에서 내부 클래스의 객체는 외부 클래스의 객체 내에 존재합니다. 따라서 외부 클래스의 데이터 멤버는 내부 클래스에 액세스 할 수 있습니다. 따라서 내부 클래스의 객체를 만들려면 먼저 외부 클래스의 객체를 만들어야합니다.

outerclass outerobject=new outerobject();
outerclass.innerclass innerobjcet=outerobject.new innerclass(); 

정적 중첩 클래스

내부 클래스의 정적 중첩 클래스 객체에는 "정적"이라는 단어가 객체를 만들 필요가 없기 때문에 외부 클래스의 객체가 필요하지 않습니다.

class outerclass A {
    static class nestedclass B {
        static int x = 10;
    }
}

x에 액세스하려면 다음 내부 메소드를 작성하십시오.

  outerclass.nestedclass.x;  i.e. System.out.prinltn( outerclass.nestedclass.x);

13

내부 클래스의 인스턴스는 외부 클래스의 인스턴스가 작성 될 때 작성됩니다. 따라서 내부 클래스의 멤버와 메소드는 외부 클래스의 인스턴스 (오브젝트)의 멤버와 메소드에 액세스 할 수 있습니다. 외부 클래스의 인스턴스가 범위를 벗어나면 내부 클래스 인스턴스도 존재하지 않습니다.

정적 중첩 클래스에는 구체적인 인스턴스가 없습니다. 정적 메소드와 마찬가지로 처음 사용할 때로 드됩니다. 메소드와 변수가 외부 클래스의 인스턴스에 액세스 할 수없는 완전히 독립적 인 엔티티입니다.

정적 중첩 클래스는 외부 객체와 결합되지 않고 더 빠르며 이러한 클래스의 인스턴스를 만들 필요가 없으므로 힙 / 스택 메모리를 사용하지 않습니다. 따라서 경험상 가능한 범위가 제한된 (비공개> = 클래스> = 보호> = 공개) 정적 중첩 클래스를 정의한 다음 내부 클래스로 변환 ( "정적"식별자 제거)하여 느슨하게하는 것이 좋습니다. 실제로 필요한 경우 범위.


2
첫 문장이 잘못되었습니다. ' 내부 클래스 인스턴스 '와 같은 것은 없으며 외부 클래스가 인스턴스화 된 후 언제든지 인스턴스를 만들 수 있습니다. 두 번째 문장은 첫 번째 문장부터 오지 않습니다.
user207421 2016 년

11

특정 상황에서 유용 할 수있는 중첩 정적 클래스 사용에 대한 미묘한 점이 있습니다.

클래스가 생성자를 통해 인스턴스화되기 전에 정적 속성이 인스턴스화되는 반면 중첩 된 정적 클래스 내부의 정적 속성은 클래스의 생성자가 호출 된 후까지 또는 적어도 속성이 처음 참조 된 후에도 인스턴스화되지 않는 것 같습니다. 그들은 '최종'으로 표시됩니다.

이 예제를 고려하십시오.

public class C0 {

    static C0 instance = null;

    // Uncomment the following line and a null pointer exception will be
    // generated before anything gets printed.
    //public static final String outerItem = instance.makeString(98.6);

    public C0() {
        instance = this;
    }

    public String makeString(int i) {
        return ((new Integer(i)).toString());
    }

    public String makeString(double d) {
        return ((new Double(d)).toString());
    }

    public static final class nested {
        public static final String innerItem = instance.makeString(42);
    }

    static public void main(String[] argv) {
        System.out.println("start");
        // Comment out this line and a null pointer exception will be
        // generated after "start" prints and before the following
        // try/catch block even gets entered.
        new C0();
        try {
            System.out.println("retrieve item: " + nested.innerItem);
        }
        catch (Exception e) {
            System.out.println("failed to retrieve item: " + e.toString());
        }
        System.out.println("finish");
    }
}

'nested'및 'innerItem'이 모두 'static final'로 선언되었지만. 중첩 된 innerItem의 설정은 클래스가 인스턴스화 된 후에야 (또는 중첩 된 정적 항목이 처음 참조 될 때까지) 발생하지 않습니다. 내가 참조하는 행을 주석 처리하고 주석 처리를 제거하면 알 수 있습니다. 위. 'outerItem'에 대해서도 마찬가지입니다.

적어도 이것이 내가 Java 6.0에서보고있는 것입니다.


10

이 용어는 서로 바꿔서 사용됩니다. 당신이 그것에 대해 정말로 놀람을 원한다면, 당신 "내부 클래스"를 정의하여 정적 인스턴스를 참조하는 정적 내부 클래스를 참조 할 수 있습니다. 코드에서 다음과 같은 것을 가질 수 있습니다.

public class Outer {
    public class Inner {}

    public static class Nested {}
}

그것은 실제로 널리 받아 들여지는 정의는 아닙니다.


2
'정적 내부'는 용어의 모순입니다.
user207421

5
내부 클래스를 정적이 아닌 중첩 클래스로 정의하는 것은 규칙이 아니라 JLS입니다. docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Lew Bloch

1
그리고이 용어들은 '교환 가능하게'사용 되지 않습니다 .
user207421

위의 예에서 정적이 왜 ide에서 오류를 발생
시키는가

10

인스턴스를 만드는 경우 정적이 아닌 내부 클래스의 인스턴스는 정의 된 외부 클래스의 객체를 참조하여 생성됩니다. 이는 인스턴스가 닫힘을 의미합니다. 그러나 정적 내부 클래스의 인스턴스는 외부 클래스의 객체 참조가 아닌 외부 클래스의 참조로 생성됩니다. 이는 인스턴스를 닫지 않았 음을 의미합니다.

예를 들면 다음과 같습니다.

class A
{
  class B
  {
    // static int x; not allowed here…..    
  }
  static class C
  {
    static int x; // allowed here
  }
}

class Test
{
  public static void main(String str)
  {
    A o=new A();
    A.B obj1 =o.new B();//need of inclosing instance

    A.C obj2 =new A.C();

    // not need of reference of object of outer class….
  }
}

1
'정적 내부'는 용어의 모순입니다. 중첩 클래스는 정적이거나 내부입니다.
user207421

9

여기에 추가 할 것이 많지 않다고 생각합니다. 대부분의 대답은 정적 중첩 클래스와 내부 클래스의 차이점을 완벽하게 설명합니다. 그러나 중첩 클래스와 내부 클래스를 사용할 때는 다음 문제를 고려하십시오. 답변의 몇에서 언급 된 바와 같이 내부 클래스는없이 인스턴스화 할 수없는 수단 및 그 둘러싸는 클래스의 인스턴스 그들은 것을 HOLD 포인터 사실 때문에 GC의에 메모리 오버 플로우 또는 스택 오버 플로우 예외로 이어질 수있는 그들의 둘러싸는 클래스의 인스턴스를 더 이상 사용하지 않더라도 둘러싸는 클래스를 가비지 수집 할 수 없습니다. 이를 명확하게하려면 다음 코드를 확인하십시오.

public class Outer {


    public  class Inner {

    }


    public Inner inner(){
        return new Inner();
    }

    @Override
    protected void finalize() throws Throwable {
    // as you know finalize is called by the garbage collector due to destroying an object instance
        System.out.println("I am destroyed !");
    }
}


public static void main(String arg[]) {

    Outer outer = new Outer();
    Outer.Inner inner = outer.new Inner();

    // out instance is no more used and should be garbage collected !!!
    // However this will not happen as inner instance is still alive i.e used, not null !
    // and outer will be kept in memory until inner is destroyed
    outer = null;

    //
    // inner = null;

    //kick out garbage collector
    System.gc();

}

에 대한 주석을 제거하면 // inner = null;프로그램이 " I destroyed! "로 표시되지만이 주석을 유지하면 그렇지 않습니다.
그 이유는 흰색 내부 인스턴스가 여전히 참조 되었기 때문에 GC가이를 수집 할 수없고 외부 인스턴스도 참조하지 않기 때문에 (포인터가 있기 때문에) 수집되지 않습니다. 프로젝트에 이러한 개체가 충분하고 메모리가 부족할 수 있습니다.
인스턴스 관련이 아니라 클래스 관련이기 때문에 내부 클래스 인스턴스를 가리 키지 않는 정적 내부 클래스와 비교합니다. Inner 클래스를 정적으로 만들고 인스턴스화하면 위의 프로그램은 " I destroyed! "를 인쇄 할 수 있습니다Outer.Inner i = new Outer.Inner();




8

음 ... 내부 클래스는 중첩 클래스입니다. 익명 클래스와 내부 클래스를 의미합니까?

편집 : 실제로 내부 대 익명을 의미하는 경우 내부 클래스는 다음과 같은 클래스 내에 정의 된 클래스입니다.

public class A {
    public class B {
    }
}

익명 클래스는 익명으로 정의 된 클래스의 확장이므로 실제 "클래스는 다음과 같이 정의되지 않습니다.

public class A {
}

A anon = new A() { /* you could change behavior of A here */ };

추가 편집 :

Wikipedia 에 차이가 있다고 주장 는 Java에 하지만 8 년 동안 Java와 함께 일해 왔으며 처음으로 그런 구별을 들었습니다 ... 클레임을 뒷받침 할 언급이 없습니다 ... 내부 클래스는 클래스 내에서 정의 된 클래스 (정적 또는 비정의)이며 중첩은 동일한 것을 의미하는 또 다른 용어 일뿐입니다.

정적 클래스와 비 정적 중첩 클래스 사이에는 미묘한 차이가 있습니다 ... 기본적으로 비 정적 내부 클래스는 인스턴스 클래스와 엔 클로징 클래스의 메소드에 대한 암시 적 액세스를 갖습니다 (따라서 정적 컨텍스트에서 생성 할 수 없으므로 컴파일러가됩니다) 오류). 반면에 정적 중첩 클래스는 인스턴스 필드 및 메소드에 대한 암시 적 액세스 권한이 없으며 정적 컨텍스트로 구성 될 수 있습니다.


3
Java 문서에 따르면 내부 클래스와 정적 중첩 클래스에는 차이가 있습니다. 정적 중첩 클래스에는 둘러싸는 클래스에 대한 참조가 없으며 주로 조직 목적으로 사용됩니다. 더 자세한 설명은 Jegschemesch의 답변을 참조하십시오.
mipadi

1
나는 의미상의 차이가 대부분 역사적이라고 생각합니다. C #-> Java 1.1 컴파일러를 작성할 때 Java 언어 참조는 매우 명시 적입니다. 중첩 클래스는 정적이며 내부 클래스는 정적이 아니므 로이 $ 0입니다. 어쨌든 그것은 혼란스럽고 더 이상 문제가되지 않아서 기쁩니다.
Tomer Gabel

2
JLS는 docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3 에서 "내부 클래스"를 정의 하므로 정적이 아닌 "내부"를 갖는 것은 불가능합니다 자바에서 "클래스. "Nested"는 "같은 것을 의미하는 또 다른 용어"가 아니며 "내부 클래스가 클래스 내에 정의 된 클래스 (정적 또는 비정의)"라는 사실이 아닙니다. 그것은 부정확 한 정보입니다.
Lew Bloch

6

Java 및 / 또는 중첩 클래스 초보자 인 타겟팅 학습자

중첩 클래스는 다음 중 하나 일 수 있습니다.
1. 정적 중첩 클래스.
2. 비 정적 중첩 클래스. ( 내부 클래스 라고도 함 ) =>이 점을 기억하십시오


1. 내부 수업
예 :

class OuterClass  {
/*  some code here...*/
     class InnerClass  {  }
/*  some code here...*/
}


내부 클래스는 중첩 클래스의 하위 집합입니다.

  • 내부 클래스는 특정 유형의 중첩 클래스입니다.
  • 내부 클래스는 중첩 클래스의 하위 집합입니다
  • 당신은 말할 수있는 내부 클래스는 중첩 클래스,하지만 당신은 할 수 없습니다 중첩 클래스는 내부 클래스라고 말할 .

이너 클래스의 전문 분야 :

  • 내부 클래스의 인스턴스는 "비공개"로 표시된 멤버를 포함하여 외부 클래스의 모든 멤버에 액세스 할 수 있습니다.


2. 정적 중첩 클래스 :
예 :

class EnclosingClass {
  static class Nested {
    void someMethod() { System.out.println("hello SO"); }
  }
}

사례 1 : 비 클로징 클래스에서 정적 중첩 클래스 인스턴스화

class NonEnclosingClass {

  public static void main(String[] args) {
    /*instantiate the Nested class that is a static
      member of the EnclosingClass class:
    */

    EnclosingClass.Nested n = new EnclosingClass.Nested(); 
    n.someMethod();  //prints out "hello"
  }
}

사례 2 : 둘러싸는 클래스에서 정적 중첩 클래스 인스턴스화

class EnclosingClass {

  static class Nested {
    void anotherMethod() { System.out.println("hi again"); } 
  }

  public static void main(String[] args) {
    //access enclosed class:

    Nested n = new Nested(); 
    n.anotherMethod();  //prints out "hi again"
  }

}

정적 클래스의 특기 :

  • 정적 내부 클래스는 외부 클래스의 정적 멤버에만 액세스 할 수 있고 비 정적 멤버에는 액세스 할 수 없습니다.

결론 :
질문 : Java에서 내부 클래스와 정적 중첩 클래스의 주요 차이점은 무엇입니까?
답 : 위에서 언급 한 각 클래스의 세부 사항을 살펴보십시오.



6

내부 클래스중첩 정적 클래스Java의 는 모두 Java의 최상위 클래스라고하는 다른 클래스 내에 선언 된 클래스입니다. Java 용어에서 중첩 클래스 정적을 선언하면 정적 중첩 클래스가 아닌 클래스를 간단히 내부 클래스라고하는 Java의 중첩 정적 클래스라고합니다.

Java의 내부 클래스는 무엇입니까?

최상위 수준이 아니거나 다른 클래스 내에서 선언 된 클래스는 중첩 클래스라고하며 중첩되지 않은 클래스 중 정적이 아닌 클래스는 Java의 내부 클래스라고합니다. Java에는 세 가지 종류의 내부 클래스가 있습니다.

1) 로컬 내부 클래스-코드 블록 또는 메소드 내부에 선언됩니다.
2) 익명의 내부 클래스-참조 할 이름이없고 클래스가 생성되는 곳에서 초기화되지 않은 클래스입니다.
3) 멤버 내부 클래스-외부 클래스의 비 정적 멤버로 선언됩니다.

public class InnerClassTest {
    public static void main(String args[]) {      
        //creating local inner class inside method i.e. main() 
        class Local {
            public void name() {
                System.out.println("Example of Local class in Java");

            }
        }      
        //creating instance of local inner class
        Local local = new Local();
        local.name(); //calling method from local inner class

        //Creating anonymous inner class in Java for implementing thread
        Thread anonymous = new Thread(){
            @Override
            public void run(){
                System.out.println("Anonymous class example in java");
            }
        };
        anonymous.start();

        //example of creating instance of inner class
        InnerClassTest test = new InnerClassTest();
        InnerClassTest.Inner inner = test.new Inner();
        inner.name(); //calling method of inner class
    }

     //Creating Inner class in Java
    private class Inner{
        public void name(){
            System.out.println("Inner class example in java");
        }
    }
}

Java에서 중첩 정적 클래스 란 무엇입니까?

중첩 정적 클래스는 클래스 내에서 멤버로 선언되어 정적으로 만들어지는 또 다른 클래스입니다. 중첩 정적 클래스는 외부 클래스의 멤버로 선언되며 다른 멤버와 마찬가지로 비공개, 공개 또는 보호 될 수 있습니다. 내부 클래스에 비해 중첩 정적 클래스의 주요 이점 중 하나는 중첩 정적 클래스 인스턴스가 외부 클래스의 둘러싸는 인스턴스에 연결되지 않는다는 것입니다. Java로 중첩 정적 클래스의 인스턴스를 만들기 위해 Outer 클래스의 인스턴스가 필요하지 않습니다. .

1) private을 포함하여 외부 클래스의 정적 데이터 멤버 에 액세스 할 수 있습니다 .
2) 정적 중첩 클래스는 정적이 아닌 (인스턴스) 데이터 멤버 또는 메소드에 액세스 할 수 없습니다 .

public class NestedStaticExample {
    public static void main(String args[]){  
        StaticNested nested = new StaticNested();
        nested.name();
    }  
    //static nested class in java
    private static class StaticNested{
        public void name(){
            System.out.println("static nested class example in java");
        }
    }
}

참조 : 예제가있는 Java의 내부 클래스 및 중첩 정적 클래스


2
"정적 중첩 클래스는 정적이 아닌 (인스턴스) 데이터 멤버 또는 메서드에 액세스 할 수 없습니다." 잘못되어 혼란을 초래 합니다. 해당 인스턴스 정보에 액세스 할 인스턴스를 생성하는 경우 프라이빗 인스턴스 정보에 절대적으로 액세스 할 수 있습니다. 내부 클래스와 같은 엔 클로징 인스턴스는 없지만 엔 클로징 클래스의 인스턴스 전용 멤버에는 액세스 할 수 있습니다.
TJ Crowder

5

나는 여기 사람들이 포스터에 주목해야한다고 생각한다. 예를 들면 다음과 같습니다.

 public static class A {} //ERROR

 public class A {
     public class B {
         public static class C {} //ERROR
     }
 }

 public class A {
     public static class B {} //COMPILE !!!

 }

따라서 정적 클래스는 포함하는 클래스에 의존하지 않습니다. 그래서 그들은 정상적인 수업에서는 할 수 없습니다. (일반 클래스에는 인스턴스가 필요하기 때문에).


2
이것은 모두 넌센스입니다. 이 모든 것은 내부 클래스가 정적 클래스를 포함 할 수 없다는 것입니다. 다음 문장과 같이 '포함하는 클래스에 의존하지 않습니다'에 대한 부분은 의미가 없습니다.
user207421

5

클래스 내에서 정적 멤버 클래스를 선언하면 최상위 중첩 클래스 또는 정적 중첩 클래스라고합니다. 다음과 같이 설명 할 수 있습니다.

class Test{
    private static int x = 1;
        static class A{
        private static int y = 2;
        public static int getZ(){
            return B.z+x;
        }
    }
    static class B{
        private static int z = 3;
        public static int getY(){
            return A.y;
        }
    }
}

class TestDemo{
     public static void main(String[] args){
        Test t = new Test();
        System.out.println(Test.A.getZ());
        System.out.println(Test.B.getY());
    }
}

비 정적 멤버 클래스를 클래스 내부에 선언하면 내부 클래스라고합니다. 내부 클래스는 다음과 같이 설명 할 수 있습니다.

    class Test{
        private int i = 10;
        class A{
            private int i =20;
            void display(){
            int i = 30;
            System.out.println(i);
            System.out.println(this.i);
            System.out.println(Test.this.i);
        }
    }
}

"클래스 내에서 정적 멤버 클래스를 선언 할 때 최상위 중첩 클래스라고 합니다." " 최상위 클래스 는 중첩 클래스가 아닌 클래스입니다." "최상위 중첩 클래스"와 같은 것은 없습니다.
Radiodef

3

다음은 static nested classand 의 예입니다 inner class.

OuterClass.java

public class OuterClass {
     private String someVariable = "Non Static";

     private static String anotherStaticVariable = "Static";  

     OuterClass(){

     }

     //Nested classes are static
     static class StaticNestedClass{
        private static String privateStaticNestedClassVariable = "Private Static Nested Class Variable"; 

        //can access private variables declared in the outer class
        public static void getPrivateVariableofOuterClass(){
            System.out.println(anotherStaticVariable);
        }
     }

     //non static
     class InnerClass{

         //can access private variables of outer class
         public String getPrivateNonStaticVariableOfOuterClass(){
             return someVariable;
         }
     }

     public static void accessStaticClass(){
         //can access any variable declared inside the Static Nested Class 
         //even if it private
         String var = OuterClass.StaticNestedClass.privateStaticNestedClassVariable; 
         System.out.println(var);
     }

}

OuterClassTest :

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

        //access the Static Nested Class
        OuterClass.StaticNestedClass.getPrivateVariableofOuterClass();

        //test the private variable declared inside the static nested class
        OuterClass.accessStaticClass();
        /*
         * Inner Class Test
         * */

        //Declaration

        //first instantiate the outer class
        OuterClass outerClass = new OuterClass();

        //then instantiate the inner class
        OuterClass.InnerClass innerClassExample =  outerClass. new InnerClass();

        //test the non static private variable
        System.out.println(innerClassExample.getPrivateNonStaticVariableOfOuterClass()); 

    }

}

3

위의 답변 중 어느 것도 응용 프로그램 디자인 측면에서 중첩 클래스와 정적 중첩 클래스의 차이점을 실제로 보여주지 않습니다. 정적 중첩 클래스와 내부 클래스의 주요 차이점은 외부 클래스 인스턴스 필드에 액세스하는 기능입니다.

다음 두 가지 예를 살펴 보겠습니다.

정적 중첩 클래스 : 정적 중첩 클래스를 사용하는 좋은 예는 빌더 패턴입니다 ( https://dzone.com/articles/design-patterns-the-builder-pattern ).

BankAccount의 경우 정적 중첩 클래스를 사용합니다. 주로

  1. 외부 클래스 전에 정적 중첩 클래스 인스턴스를 작성할 수 있습니다.

  2. 빌더 패턴에서 빌더는 BankAccount를 작성하는 데 사용되는 헬퍼 클래스입니다.

  3. BankAccount.Builder는 BankAccount 와만 연관됩니다. 다른 클래스는 BankAccount.Builder와 관련이 없습니다. 이름 규칙을 사용하지 않고 함께 구성하는 것이 좋습니다.
public class BankAccount {

    private long accountNumber;
    private String owner;
    ...

    public static class Builder {

    private long accountNumber;
    private String owner;
    ...

    static public Builder(long accountNumber) {
        this.accountNumber = accountNumber;
    }

    public Builder withOwner(String owner){
        this.owner = owner;
        return this; 
    }

    ...
    public BankAccount build(){
            BankAccount account = new BankAccount(); 
            account.accountNumber = this.accountNumber;
            account.owner = this.owner;
            ...
            return account;
        }
    }
}

내부 클래스 : 내부 클래스의 일반적인 용도는 이벤트 핸들러를 정의하는 것입니다. https://docs.oracle.com/javase/tutorial/uiswing/events/generalrules.html

MyClass의 경우 주로 다음과 같은 이유로 내부 클래스를 사용합니다.

  1. 내부 클래스 MyAdapter는 외부 클래스 멤버에 액세스해야합니다.

  2. 이 예에서 MyAdapter는 MyClass 와만 연관되어 있습니다. 다른 클래스는 MyAdapter와 관련이 없습니다. 이름 규칙을 사용하지 않고 함께 구성하는 것이 좋습니다

public class MyClass extends Applet {
    ...
        someObject.addMouseListener(new MyAdapter());
    ...
    class MyAdapter extends MouseAdapter {
        public void mouseClicked(MouseEvent e) {
            ...// Event listener implementation goes here...
            ...// change some outer class instance property depend on the event
        }
    }
}

2

다이어그램

여기에 이미지 설명을 입력하십시오

static nestednon-static nested클래스 의 주요 차이점은 비 정적 외부 클래스 멤버에 액세스 할 수 static nested 없다는 것입니다


0

정적 클래스라는 클래스가 없습니다. 정적 수정자는 내부 클래스 (중첩 클래스라고 함)와 함께 사용하면 외부 클래스의 정적 멤버이므로 다른 정적 멤버와 마찬가지로 액세스 할 수 있다는 의미입니다. 외부 클래스의 인스턴스. (정적으로 정적의 이점은 무엇입니까?)

중첩 클래스와 일반 내부 클래스의 차이점은 다음과 같습니다.

OuterClass.InnerClass inner = new OuterClass().new InnerClass();

먼저 Outerclass를 인스턴스화 한 다음 Inner에 액세스 할 수 있습니다.

그러나 클래스가 중첩되면 구문은 다음과 같습니다.

OuterClass.InnerClass inner = new OuterClass.InnerClass();

정적 키워드를 정적 키워드의 일반적인 구현으로 사용합니다.


1
"...이 의미하는 외부 클래스의 정적 멤버라고합니다 ....": 정적 중첩 클래스를 외부 클래스의 "멤버 클래스"로 생각하는 것은 올바르지 않지만 정적 필드와의 유사점은 방법은 거기서 끝납니다. 정적 중첩 클래스는 외부 클래스에 속하지 않습니다. 중요한 모든 방법에서 정적 중첩 클래스는 패키징 편의를 위해 클래스 정의가 외부 클래스의 내부에 중첩되어있는 독립형 최상위 클래스입니다. 중첩 클래스와 외부 클래스 사이에 논리적 연관성이 있기를 바랍니다. ... 필요하지는 않지만).
scottb

1
'정적 내부'는 용어의 모순입니다. 정적 클래스는 첫 번째 중첩 수준에 존재하며 정의에 따라 내부 클래스가 아닙니다. 매우 혼란.
user207421

0

Java 프로그래밍 언어를 사용하면 다른 클래스 내에 클래스를 정의 할 수 있습니다. 이러한 클래스를 중첩 클래스라고하며 여기에 설명되어 있습니다.

class OuterClass {
...
class NestedClass {
    ...
    }
}

중첩 클래스는 정적 및 비 정적의 두 가지 범주로 나뉩니다. static으로 선언 된 중첩 클래스를 정적 ​​중첩 클래스라고합니다. 정적이 아닌 중첩 클래스를 내부 클래스라고합니다. 우리가 명심해야 할 한 가지는 비 정적 중첩 클래스 (내부 클래스)가 비공개로 선언 된 경우에도 포함 클래스의 다른 멤버에 액세스 할 수 있다는 것입니다. 정적 중첩 클래스는 정적 클래스 인 경우 둘러싸는 클래스의 다른 멤버에만 액세스 할 수 있습니다. 외부 클래스의 비 정적 멤버에 액세스 할 수 없습니다. 클래스 메서드 및 변수와 마찬가지로 정적 중첩 클래스는 외부 클래스와 연결됩니다. 예를 들어 정적 중첩 클래스의 객체를 만들려면 다음 구문을 사용하십시오.

OuterClass.StaticNestedClass nestedObject =
 new OuterClass.StaticNestedClass(); 

내부 클래스를 인스턴스화하려면 먼저 외부 클래스를 인스턴스화해야합니다. 그런 다음이 구문을 사용하여 외부 개체 내에 내부 개체를 만듭니다.

OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();

중첩 클래스를 사용하는 이유

  1. 한 곳에서만 사용되는 클래스를 논리적으로 그룹화하는 방법입니다.
  2. 캡슐화가 증가합니다.
  3. 더 읽기 쉽고 유지 보수가 쉬운 코드로 이어질 수 있습니다.

소스 : Java ™ 학습서-중첩 클래스


-1

차이점은 정적 인 중첩 클래스 선언을 둘러싸는 클래스 외부에서 인스턴스화 할 수 있다는 것입니다.

내부 클래스 라고도하는 정적 이 아닌 중첩 클래스 선언이 있는 경우 경우 Java는 둘러싸는 클래스를 통한 경우를 제외하고 인스턴스화 할 수 없습니다. 내부 클래스에서 생성 된 객체는 외부 클래스에서 생성 된 객체에 연결되므로 내부 클래스는 외부의 필드를 참조 할 수 있습니다.

그러나 정적 인 경우 링크가 존재하지 않고 외부 필드에 액세스 할 수 없으며 (다른 객체와 같은 일반 참조를 제외하고) 중첩 클래스를 자체적으로 인스턴스화 할 수 있습니다.


1
사실이 아닙니다. 둘러싸는 클래스의 범위 밖에서 내부 클래스를 만드는 특별한 구문이 있습니다.
user207421

-1

정적 로컬 클래스와 비 정적 내부 클래스를 비교하는 것은 매우 간단합니다.
차이점 :
정적 로컬 클래스 :
외부 클래스의 정적 멤버에만 액세스 할 수 있습니다.
정적 이니셜 라이저를 가질
수 없음 선언 된 함수 외부에서 직접 액세스 할 수 없음


-2

Java 코드에서 발생할 수있는 다양한 가능한 올바른 오류 시나리오를 설명했습니다.

    class Outter1 {

        String OutStr;

        Outter1(String str) {
            OutStr = str;
        }

        public void NonStaticMethod(String st)  {

            String temp1 = "ashish";
            final String  tempFinal1 = "ashish"; 

            //  below static attribute not permitted
            // static String tempStatic1 = "static";    

            //  below static with final attribute not permitted         
            // static final String  tempStatic1 = "ashish";  

            // synchronized keyword is not permitted below          
            class localInnerNonStatic1 {            

                synchronized    public void innerMethod(String str11) {
                    str11 = temp1 +" sharma";
                    System.out.println("innerMethod ===> "+str11);
                }

                /* 
        //  static method with final not permitted
          public static void innerStaticMethod(String str11) { 

                    str11 = temp1 +" india";
                    System.out.println("innerMethod ===> "+str11);
                }*/
            }

            // static class not permitted below
            //  static class localInnerStatic1 {   }                            

        }

        public static  void StaticMethod(String st)     {

            String temp1 = "ashish";
            final String  tempFinal1 = "ashish"; 

            // static attribute not permitted below
            //static String tempStatic1 = "static";     

            //  static with final attribute not permitted below
            // static final String  tempStatic1 = "ashish";                         

            class localInnerNonStatic1 {
                public void innerMethod(String str11) {
                    str11 = temp1 +" sharma";
                    System.out.println("innerMethod ===> "+str11);
                }

                /*
    // static method with final not permitted
    public static void innerStaticMethod(String str11) {  
                    str11 = temp1 +" india";
                    System.out.println("innerMethod ===> "+str11);
                }*/
            }

            // static class not permitted below
            //  static class localInnerStatic1 {   }    

        }

        // synchronized keyword is not permitted
        static  class inner1 {          

            static String  temp1 = "ashish";
            String  tempNonStatic = "ashish";
            // class localInner1 {

            public void innerMethod(String str11) {
                str11 = temp1 +" sharma";
                str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }

            public static void innerStaticMethod(String str11) {
                //  error in below step
                str11 = temp1 +" india";    
                //str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }
            //}
        }

        //synchronized keyword is not permitted below
        class innerNonStatic1 {             

//This is important we have to keep final with static modifier in non
// static innerclass below
            static final String  temp1 = "ashish";  
            String  tempNonStatic = "ashish";
            // class localInner1 {

            synchronized    public void innerMethod(String str11) {
                tempNonStatic = tempNonStatic +" ...";
                str11 = temp1 +" sharma";
                str11 = str11+ tempNonStatic +" sharma";
                System.out.println("innerMethod ===> "+str11);
            }

            /*
            //  error in below step
            public static void innerStaticMethod(String str11) {   
                            //  error in below step
                            // str11 = tempNonStatic +" india";                     
                            str11 = temp1 +" india";
                            System.out.println("innerMethod ===> "+str11);
                        }*/
                    //}
                }
    }

1
분명히 코드 부분입니다. 그리고 눈치 채지 못한 경우 : 코드 예제를 읽기가 매우 어렵습니다. 거대한 데스크탑 모니터에서도 가로 스크롤 막대가 있습니다. 대신에 - 그들은 코멘트하는 것은 위 또는 아래에 귀하의 의견을 가하고 고려 뒤에 .
GhostCat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.