Java에서 내부 클래스와 정적 중첩 클래스 간의 주요 차이점은 무엇입니까? 설계/구현이 이들 중 하나를 선택하는 데 중요한 역할을합니까?
중첩 클래스는 정적 및 비 정적이라는 두 가지 범주로 구분됩니다. 정적으로 선언 된 중첩 클래스는 단순히 정적 중첩 클래스라고합니다. 비 정적 중첩 클래스는 내부 클래스라고합니다.
정적 중첩 클래스는 포함하는 클래스 이름을 사용하여 액세스합니다.
OuterClass.StaticNestedClass
예를 들어 정적 중첩 클래스에 대한 객체를 만들려면 다음 구문을 사용합니다.
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
내부 클래스의 인스턴스 인 객체는 외부 클래스의 인스턴스 내에 존재합니다. 다음 클래스를 고려하십시오.
class OuterClass {
...
class InnerClass {
...
}
}
InnerClass의 인스턴스는 OuterClass의 인스턴스 내에 만 존재할 수 있으며 둘러싸는 인스턴스의 메서드와 필드에 직접 액세스 할 수 있습니다.
내부 클래스를 인스턴스화하려면 먼저 외부 클래스를 인스턴스화해야합니다. 그런 다음이 구문을 사용하여 외부 객체 내에 내부 객체를 만듭니다.
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
참조 : 자바 튜토리얼 - 중첩 클래스
완전성을 위해, 내부 클래스 without 둘러싸는 인스턴스 :와 같은 것도 있습니다.
class A {
int t() { return 1; }
static A a = new A() { int t() { return 2; } };
}
new A() { ... }
은 정적 컨텍스트에 정의 된 내부 클래스이며 내부 인스턴스를 포함하지 않습니다.
용어 : 중첩 클래스는 정적 및 비 정적의 두 가지 범주로 나뉩니다. static으로 선언 된 중첩 클래스를 정적 중첩 클래스라고합니다. 정적이 아닌 중첩 클래스를 내부 클래스라고합니다.
일반적으로 "nested"와 "inner"라는 용어는 대부분의 프로그래머가 상호 교환 적으로 사용하지만 내부 및 정적을 모두 포함하는 "nested class"라는 올바른 용어를 사용합니다.
클래스는 중첩 될 수 있습니다 ad infinitum 클래스 A는 클래스 D를 포함하는 클래스 C를 포함하는 클래스 B를 포함 할 수 있습니다. 그러나 일반적으로 설계가 좋지 않기 때문에 둘 이상의 클래스 중첩 수준은 거의 없습니다.
중첩 클래스를 생성 할 수있는 세 가지 이유가 있습니다.
Java에는 네 종류의 중첩 클래스가 있습니다. 간단히 말해 다음과 같습니다.
좀 더 자세하게 설명하겠습니다.
정적 클래스는 포함하는 클래스의 인스턴스와 관련이 없으므로 이해하기 가장 쉬운 종류입니다.
정적 클래스는 다른 클래스의 정적 멤버로 선언 된 클래스입니다. 다른 정적 멤버와 마찬가지로 이러한 클래스는 포함 클래스를 네임 스페이스로 사용하는 행거입니다. eg 클래스 Goat 패키지에서 pizza 클래스의 Rhino 클래스의 정적 멤버로 선언 된 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 에 의해 규정 된 것으로 알려져 있지만 포함 클래스 내부에서는 간단한 것으로 알 수 있습니다. 이름. 그러나 내부 클래스의 모든 인스턴스는 포함 클래스의 특정 인스턴스에 연결됩니다. 위의 Goat jerry jerry 의 Rhino instance this 에 암시 적으로 연결되어 있습니다. 그렇지 않으면 Goat 를 인스턴스화 할 때 관련 Rhino 인스턴스를 명시 적으로 만듭니다.
Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();
(이상한 new 구문에서 내부 유형을 Goat 로 참조한다는 점에 유의하십시오. Java rhino 부분의 유형을 포함하고 있으며 yes new rhino.Goat () 나에게도 더 의미가 있습니다.)
이것이 우리에게 무엇을 가져 옵니까? 내부 클래스 인스턴스는 포함하는 클래스 인스턴스의 인스턴스 멤버에 액세스 할 수 있습니다. 이 둘러싸는 인스턴스 멤버는 내부 클래스 내부에서 참조됩니다 via 단순한 이름이 아니라 via this ( this 내부 클래스에서 연결된 포함 클래스 인스턴스가 아닌 내부 클래스 인스턴스를 나타냅니다) :
public class Rhino {
private String barry;
public class Goat {
public void colin() {
System.out.println(barry);
}
}
}
내부 클래스에서 포함 클래스의 this 을 Rhino.this 로 참조 할 수 있으며 this 구성원을 나타내는 eg Rhino.this.barry .
로컬 내부 클래스는 메서드 본문에 선언 된 클래스입니다. 이러한 클래스는 포함 메소드 내에서만 알려져 있으므로 인스턴스화 할 수 있으며 포함 메소드 내에서 멤버에 액세스 할 수 있습니다. 장점은 로컬 내부 클래스 인스턴스가 포함 된 메서드의 최종 로컬 변수에 연결되어 액세스 할 수 있다는 것입니다. 인스턴스가 포함하는 메소드의 최종 로컬을 사용하는 경우 변수가 범위를 벗어난 경우에도 변수는 인스턴스 작성시 보유한 값을 유지합니다 (이것은 사실상 Java의 조잡하고 제한된 클로저 버전입니다).
로컬 내부 클래스는 클래스 또는 패키지의 멤버가 아니므로 액세스 수준으로 선언되지 않습니다. (단, 자체 클래스의 멤버는 일반 클래스와 같은 액세스 레벨을 갖습니다.)
로컬 내부 클래스가 인스턴스 메소드에서 선언되면 내부 클래스의 인스턴스화는 인스턴스 작성시 포함 메소드의 this 에 의해 보유 된 인스턴스에 연결됩니다. 포함하는 클래스의 인스턴스 멤버는 인스턴스 내부 클래스와 같이 액세스 할 수 있습니다. 로컬 내부 클래스는 간단히 인스턴스화됩니다 via 이름, eg 로컬 내부 클래스 Cat 는 new Cat () 로 인스턴스화되지만 예상대로 this this.Cat ()이 아닙니다.
익명의 내부 클래스는 구문 적으로 편리한 로컬 내부 클래스를 작성하는 방법입니다. 가장 일반적으로, 로컬 내부 클래스는 포함 메소드가 실행될 때마다 최대 한 번만 인스턴스화됩니다. 로컬 내부 클래스 정의와 단일 인스턴스화를 하나의 편리한 구문 형식으로 결합 할 수 있다면 좋을 것입니다. 클래스의 이름을 생각할 필요가 없다면 도움이 될 것입니다. 코드에 포함 된 이름이 더 좋습니다). 익명의 내부 클래스는 다음 두 가지를 모두 허용합니다.
new *ParentClassName*(*constructorArgs*) {*members*}
이것은 ParentClassName 로 확장되는 명명되지 않은 클래스의 새 인스턴스를 반환하는 표현식입니다. 자신 만의 생성자를 제공 할 수 없습니다. 오히려, 단순히 수퍼 생성자를 호출하는 암시 적으로 제공되므로 제공된 인수는 수퍼 생성자에 맞아야합니다. (부모가 여러 생성자를 포함하는 경우, "가장 단순한"것을 "가장 단순"이라고하며, 자세히 배우고 싶지 않은 다소 복잡한 규칙 집합에 따라 결정됩니다. NetBeans 또는 Eclipse가 말하는 것에주의하십시오.)
또는 구현할 인터페이스를 지정할 수 있습니다.
new *InterfaceName*() {*members*}
이러한 선언은 Object를 확장하고 InterfaceName 를 구현하는 명명되지 않은 클래스의 새 인스턴스를 만듭니다. 다시, 당신은 당신 자신의 생성자를 제공 할 수 없습니다; 이 경우, Java는 암묵적으로 아무 것도하지 않는 생성자를 암시 적으로 제공합니다 (따라서이 경우 생성자 인수는 절대 없습니다).
익명의 내부 클래스에 생성자를 제공 할 수는 없지만 초기화 블록 (메서드 외부에 배치 된 {} 블록)을 사용하여 원하는 설정을 수행 할 수 있습니다.
익명의 내부 클래스는 하나의 인스턴스로 로컬 내부 클래스를 만드는 덜 유연한 방법이라는 점을 명심하십시오. 여러 인터페이스를 구현하거나 Object 이외의 클래스를 확장하면서 인터페이스를 구현하거나 자체 생성자를 지정하는 로컬 내부 클래스를 원한다면 로컬이라는 일반 이름을 작성해야합니다. 내부 클래스.
위의 답변에서 실제의 차이점이 명확 해지지 않았다고 생각합니다.
먼저 권리를 얻는 방법 :
마틴의 대답은 지금까지 옳다. 그러나 실제 질문은 : 중첩 된 클래스를 정적으로 선언하는 목적은 무엇입니까?
함께 중첩되어 있거나 중첩 클래스가 둘러싼 클래스에서 독점적으로 사용되는 경우 클래스를 함께 유지하려는 경우 static 중첩 클래스 를 사용합니다. 정적 중첩 클래스와 다른 모든 클래스 간에는 의미 적 차이가 없습니다.
비 정적 중첩 클래스 는 다른 짐승입니다. 익명 내부 클래스와 마찬가지로 중첩 클래스는 실제로 클로저입니다. 즉, 주변 범위와 둘러싸인 인스턴스를 캡처하여 액세스 할 수있게합니다. 아마도 그 예가 그것을 분명히 할 것입니다. 컨테이너의 스텁보기 :
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)
완전을 기하기 위해 :
익명 클래스 is 비 정적 중첩 클래스의 완벽한 예제로, 이름이 연관되어 있지 않으며 나중에 참조 할 수 없습니다.
위의 답변 중 어느 것도 중첩 된 클래스와 정적 인 중첩 클래스 사이의 실제 차이점을 애플리케이션 디자인의 관점에서 설명하지 못한다고 생각합니다.
중첩 된 클래스 비 정적이거나 정적 일 수 있으며 각각의 경우에 다른 클래스 내에 정의 된 클래스. 중첩 된 클래스는 서브 클래스로만 존재해야 함 중첩 된 클래스가 다른 클래스에서 유용 할 경우 (최상위 클래스로 선언해야 함).
Nonstatic Nested 클래스 :는 포함하는 클래스의 둘러싼 인스턴스에 암시 적으로 연결됩니다. 즉, 포함 된 인스턴스의 메서드 및 액세스 변수를 호출 할 수 있음을 의미합니다. 비 정적 중첩 클래스의 한 가지 일반적인 용도는 Adapter 클래스를 정의하는 것입니다.
정적 중첩 클래스 : 둘러싸는 클래스 인스턴스에 액세스 할 수 없으므로 중첩 클래스가 해당 클래스의 인스턴스에 액세스 할 필요가없는 경우 사용해야합니다. 정적 중첩 클래스의 일반적인 사용은 외부 객체의 구성 요소를 구현하는 것입니다.
따라서 두 가지 디자인의 주된 차이는 디자인 관점에서 볼 때 nonstatic 중첩 클래스는 컨테이너 클래스의 인스턴스에 액세스 할 수 있지만 static은 할 수 없습니다.
Java가 클로저를 제공하지 않기 때문에 주로 중첩 된 클래스가 필요합니다.
중첩 된 클래스는 다른 클래스를 둘러싸는 본문 내에 정의 된 클래스입니다. 그것들은 정적 및 비 정적의 두 가지 유형이 있습니다.
그것들은 둘러싸는 클래스의 멤버로서 취급되므로, 4 개의 액세스 지정자 - private, package, protected, public
-를 지정할 수 있습니다. 우리는 public
또는 package-private 만 선언 할 수있는 최상위 클래스에는이 고급 기능을 제공하지 않습니다.
Inner 클래스 일명 Non-stack 클래스는 private 클래스로 선언 된 경우에도 최상위 클래스의 다른 멤버에 액세스 할 수 있지만 정적 중첩 클래스는 최상위 클래스의 다른 멤버에 액세스 할 수 없습니다.
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();
정적 중첩 클래스의 장점은 포함하는 클래스/최상위 클래스의 객체가 작동하지 않아도된다는 것입니다. 이렇게하면 런타임에 응용 프로그램이 만드는 객체 수를 줄일 수 있습니다.
제 생각에, 일반적으로 뒤따라 지키고있는 국제 대회는 이것입니다 :
그러나 나머지 기억해야 할 점은 다음과 같습니다.
최상위 클래스와 정적 중첩 클래스는 정적으로 중첩 된 클래스의 경우 Outer [parent] 클래스의 전용 정적 필드/메서드에 대한 정적 참조를 만들 수 있다는 점을 제외하고는 완전히 동일합니다.
내부 클래스는 바깥 쪽 [부모] 클래스의 둘러싸는 인스턴스의 인스턴스 변수에 액세스 할 수 있습니다. 그러나 모든 내부 클래스가 인 클로징 인스턴스를 가지고있는 것은 아닙니다 (예 : 정적 이니셜 라이저 블록에서 사용되는 익명 클래스와 같이 정적 컨텍스트의 내부 클래스).
익명 클래스는 기본적으로 상위 클래스를 확장하거나 상위 인터페이스를 구현하므로 다른 클래스를 확장하거나 더 이상 인터페이스를 구현할 절이 없습니다. 그래서,
new YourClass(){};
은 class [Anonymous] extends YourClass {}
를 의미합니다.new YourInterface(){};
은 class [Anonymous] implements YourInterface {}
를 의미합니다.어느 쪽이 언제 열려야하는 더 큰 질문이 언제 느껴지나요? 글쎄 대부분 당신이 처리하는 시나리오에 따라 다르지만 @jrudolph가 제공 한 회신을 읽으면 어떤 결정을 내리는 데 도움이 될 수 있습니다.
다음은 Java 내부 클래스와 정적 중첩 클래스의 주요 차이점과 유사점입니다.
그것이 도움이되기를 바랍니다!
인 클로징 클래스의 인스턴스와 연관 됨 따라서 인스턴스화하려면 먼저 외부 클래스의 인스턴스가 필요합니다 (참고 new 키워드 위치) :
Outerclass.InnerClass innerObject = outerObject.new Innerclass();
정지 정의 정적 멤버 자체
액세스 할 수 없음 외부 클래스 인스턴스 메서드 또는 필드
인 클로징 클래스의 인스턴스와 연결되지 않음 인스턴스화하려면 :
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
Oracle 문서에 따르면 몇 가지 이유가 있습니다 ( full documentation ).
한 곳에서만 사용되는 클래스를 논리적으로 그룹화하는 방법입니다. 한 클래스가 다른 클래스에만 유용한 경우 해당 클래스에 클래스를 포함시키고 두 클래스를 함께 유지하는 것이 논리적입니다. 이러한 "헬퍼 클래스"를 중첩하면 패키지가 더욱 간소화됩니다.
캡슐화를 증가시킵니다. 두 개의 최상위 클래스 A와 B를 고려하십시오. 여기서 B는 그렇지 않으면 비공개로 선언 된 A의 멤버에 액세스해야합니다. 클래스 A 내에 클래스 B를 숨기면 A의 구성원을 비공개로 선언하고 B가 액세스 할 수 있습니다. 또한 B 자체는 외부 세계에서 숨길 수 있습니다.
더 읽기 쉽고 유지 관리 가능한 코드로 이어질 수 있습니다. 최상위 클래스 내에 작은 클래스를 중첩하면 코드가 사용되는 위치에 더 가깝게 배치됩니다.
중첩 된 클래스 : 클래스 내부의 클래스
유형 :
차:
비 정적 중첩 클래스 [내부 클래스]
Static 클래스가 아닌 내부 클래스의 객체는 외부 클래스의 객체 내에 존재합니다. 그래서 외부 클래스의 데이터 멤버는 내부 클래스에 액세스 할 수 있습니다. 따라서 내부 클래스의 객체를 생성하기 위해서는 먼저 외부 클래스의 객체를 생성해야합니다.
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);
특정 상황에서 유용 할 수있는 중첩 된 정적 클래스의 사용에 대한 미묘한 차이가 있습니다.
클래스가 생성자를 통해 인스턴스화되기 전에 정적 속성이 인스턴스화되는 반면 중첩 된 정적 클래스 내부의 정적 속성은 클래스의 생성자가 호출 될 때까지 인스턴스화되지 않는 것처럼 보입니다. 속성이 처음 참조 될 때까지 '최종'으로 표시되어 있더라도.
다음 예제를 고려하십시오.
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");
}
}
'중첩 된'과 'innerItem'은 둘 다 '정적 최종'으로 선언됩니다. nested.innerItem의 설정은 클래스가 인스턴스화 될 때까지 (또는 중첩 된 정적 항목이 처음 참조 될 때까지 적어도 까지) 일어나지 않습니다. .____.] 위에서 언급 한 행의 주석을 달고 주석을 제거함으로써. 같은 것은 'outerItem'에 대해 true를 유지하지 못합니다.
적어도 이것이 Java 6.0에서 보았던 것입니다.
내부 클래스의 인스턴스는 외부 클래스의 인스턴스가 만들어 질 때 만들어집니다. 따라서 내부 클래스의 멤버와 메서드는 외부 클래스의 인스턴스 (개체)의 멤버와 메서드에 액세스 할 수 있습니다. 외부 클래스의 인스턴스가 범위를 벗어나면 내부 클래스 인스턴스도 존재하지 않게됩니다.
정적 중첩 클래스에는 구체적인 인스턴스가 없습니다. 정적 메서드와 마찬가지로 처음 사용할 때로드됩니다. 그것은 완전히 독립된 엔티티이며, 메소드와 변수는 외부 클래스의 인스턴스에 액세스하지 않습니다.
정적 중첩 클래스는 외부 객체와 결합되지 않으며, 더 빠르며 힙/스택 메모리를 사용하지 않습니다. 이러한 클래스의 인스턴스를 만들 필요가 없기 때문입니다. 따라서 엄지 법칙은 가능한 한 제한된 범위 (private> = class> = protected> public)로 정적 중첩 클래스를 정의한 다음 ( "정적"식별자를 제거하여) 내부 클래스로 변환하고 풀 범위, 정말 필요한 경우.
여기에 추가 할 항목이별로 없다고 생각합니다. 대부분의 대답은 정적 중첩 클래스와 내부 클래스 간의 차이점을 완벽하게 설명합니다. 그러나 내부 클래스와 중첩 클래스를 사용할 때는 다음 문제를 고려하십시오. 몇 가지 대답에서 언급했듯이, 내부 클래스는 그 둘러싸는 클래스의 인스턴스없이 인스턴스화 될 수 없습니다. 즉, HOLD a 포인터 둘러싸는 클래스의 인스턴스 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;
에 대한 주석을 제거하면 프로그램은 "나는 파괴되었습니다!"을 출력하지만 주석으로 유지하면됩니다.
이유는 내부 인스턴스가 여전히 참조 된 GC가 수집 할 수 없기 때문이며 외부 인스턴스를 참조 (포인터가 있음)하기 때문에 수집되지도 않습니다. 프로젝트에 이러한 개체가 충분하고 메모리가 부족할 수 있습니다.
인스턴스와 관련이 없지만 클래스와 관련되어 있으므로 내부 클래스 인스턴스에 대한 점을 보유하지 않는 정적 내부 클래스와 비교합니다. 위의 프로그램은 Inner 클래스를 정적으로 만들고 Outer.Inner i = new Outer.Inner();
으로 인스턴스화하면 "나는 파괴되었습니다!"를 인쇄 할 수 있습니다.
인스턴스를 생성하는 경우 정적이 아닌 내부 클래스의 인스턴스는 정의 된 외부 클래스의 객체에 대한 참조로 생성됩니다. 이 은 그것이 인스턴스를 포함하고 있음을 의미합니다. 그러나 정적 내부 클래스 의 인스턴스는 의 객체에 대한 참조가 아니라 외부 클래스의 참조로 생성됩니다. 외부 클래스. 이것은 그것을 의미합니다. 인스턴스를 포함하지 않습니다.
예 :
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….
}
}
이 용어는 서로 바꿔서 사용됩니다. 만약 당신이 그것에 대해 정말 놀람을 원한다면, 당신은 could "중첩 된 클래스 (nested class)"를 정의하여 정적 내부 클래스 (enclosing instance)가없는 정적 내부 클래스를 참조합니다. 코드에서 다음과 같은 것을 가질 수 있습니다.
public class Outer {
public class Inner {}
public static class Nested {}
}
그것은 실제로 널리 받아 들여지는 정의는 아닙니다.
중첩 된 클래스는 매우 일반적인 용어입니다. 최상위 레벨이 아닌 모든 클래스는 중첩 클래스입니다. 내부 클래스는 정적이 아닌 중첩 클래스입니다. Joseph Darcy는 중첩 된 클래스, 내부 클래스, 멤버 클래스 및 최상위 클래스 .
Java 및/또는 중첩 클래스의 초보자 인 학습자 대상 지정
중첩 된 클래스는 다음 중 하나 일 수 있습니다.
1. 정적 중첩 클래스.
2. 비 정적 중첩 클래스. (일컬어 Inner classes) => 이것을 기억하십시오
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"
}
}
스태틱 클래스의 전문 :
결론 :
Question : Java에서 내부 클래스와 정적 중첩 클래스 사이의 주요 차이점은 무엇입니까?
답 :은 위에서 언급 한 각 클래스의 세부 사항을 살펴 봅니다.
음 ... 내부 클래스 IS 중첩 클래스 ... 익명 클래스와 내부 클래스를 의미합니까?
편집 : 만약 당신이 실제로 내부 대 익명을 의미 ... 내부 클래스는 같은 클래스 내에서 정의 된 클래스입니다 :
public class A {
public class B {
}
}
익명 클래스가 익명으로 정의 된 클래스의 확장 인 반면 실제 클래스는 다음과 같이 정의되지 않습니다.
public class A {
}
A anon = new A() { /* you could change behavior of A here */ };
추가 편집 :
Wikipedia 차이점이 있다고 주장합니다 Java에서는 8 년 동안 Java로 작업 해 왔지만 처음으로 그러한 구분을 들었습니다 ... 주장을 뒷받침 할 참조가 없습니다 ... 밑줄, 내부 클래스는 클래스 내에서 정의 된 클래스 (static 또는 not)이며 중첩 된 것은 동일한 것을 의미하는 또 다른 용어입니다.
정적 및 비 정적 중첩 클래스 사이에는 미묘한 차이가 있습니다 ... 기본적으로 비 정적 인 내부 클래스는 인스턴스 클래스와 클래스의 메서드에 대한 암시 적 액세스를 갖습니다 (따라서 정적 컨텍스트에서 구성 할 수 없으며 컴파일러가됩니다. 오류). 반면에 정적 중첩 클래스는 인스턴스 필드와 메소드에 대한 암시 적 액세스를 가지지 않으며 정적 컨텍스트로 구성 될 수 있습니다.
내부 클래스와 중첩 된 정적 클래스는 Java의 최상위 클래스로 알려진 다른 클래스에서 선언 된 클래스입니다. Java 용어에서는 중첩 클래스를 정적으로 선언하면 Java에서 중첩 된 정적 클래스로, 정적이 아닌 중첩 클래스는 단순히 내부 클래스로 참조됩니다.
자바의 내부 클래스 란 무엇입니까?
최상위 클래스가 아니거나 다른 클래스 내부에서 선언 된 클래스는 중첩 클래스로 알려져 있으며 중첩 클래스 중 정적이 아닌 것으로 선언 된 클래스는 Java의 내부 클래스로 알려져 있습니다. Java에는 3 종류의 Inner 클래스가 있습니다.
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에서 중첩 된 정적 클래스는 무엇입니까?
중첩 된 정적 클래스는 클래스 내에서 멤버로 선언되고 정적으로 만들어지는 또 다른 클래스입니다. 중첩 된 정적 클래스는 또한 외부 클래스의 멤버로 선언되며 다른 멤버와 마찬가지로 private, public 또는 protected로 만들 수 있습니다. 내부 클래스보다 중첩 된 정적 클래스의 주된 이점 중 하나는 중첩 된 정적 클래스의 인스턴스가 Outer 클래스의 모든 둘러싸는 인스턴스에 첨부되지 않는다는 것입니다. Java에서 중첩 된 정적 클래스의 인스턴스를 생성하기 위해 Outer 클래스의 인스턴스가 필요하지 않습니다.
1) 개인 클래스를 포함한 외부 클래스의 정적 데이터 멤버에 액세스 할 수 있습니다.
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");
}
}
}
클래스 내에서 정적 멤버 클래스를 선언 할 때는 최상위 수준의 중첩 클래스 또는 정적 중첩 클래스로 알려져 있습니다. 그것은 다음과 같이 시연 될 수 있습니다 :
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);
}
}
}
여기 사람들이 포스터에 주목해야한다고 생각합니다. 정적 둥지 클래스는 첫 번째 내부 클래스 만 있습니다. 예를 들면 다음과 같습니다.
public static class A {} //ERROR
public class A {
public class B {
public static class C {} //ERROR
}
}
public class A {
public static class B {} //COMPILE !!!
}
따라서 요약하면 static 클래스는 클래스에 포함되지 않습니다. 그래서 정상적인 수업을들을 수는 없습니다. (정상 클래스는 인스턴스가 필요하기 때문에).
다음은 static nested class
및 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());
}
}
다이어그램
static nested
와 non-static nested
클래스의 차이점
더 읽기 여기
위의 답변 중 어느 것도 중첩 된 클래스와 정적 인 중첩 클래스 사이의 차이점을 애플리케이션 설계의 관점에서 보여주는 것은 아니라고 생각합니다. 정적 중첩 클래스와 내부 클래스의 가장 큰 차이점은 외부 클래스 인스턴스 필드에 액세스 할 수 있다는 것입니다.
다음의 두 예제를 살펴 보겠습니다.
정적 중첩 클래스 : 정적 중첩 클래스를 사용하는 좋은 예는 빌더 패턴 ( https://dzone.com/articles/design-patterns-the-builder-pattern )입니다.
BankAccount의 경우 정적 중첩 클래스를 주로 사용합니다.
정적 네스트 클래스 인스턴스는 외부 클래스보다 먼저 생성 될 수 있습니다.
빌더 패턴에서 빌더는 BankAccount를 작성하는 데 사용되는 도우미 클래스입니다.
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의 경우 주로 다음과 같은 이유로 inner 클래스를 사용합니다.
내부 클래스 MyAdapter는 외부 클래스 멤버에 액세스해야합니다.
이 예에서 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
}
}
}
Java 프로그래밍 언어를 사용하여 다른 클래스 내의 클래스를 정의 할 수 있습니다. 이러한 클래스는 중첩 클래스라고하며 여기에 설명되어 있습니다.
class OuterClass {
...
class NestedClass {
...
}
}
중첩 클래스는 정적 및 비 정적이라는 두 가지 범주로 구분됩니다. 정적으로 선언 된 중첩 클래스는 정적 중첩 클래스라고합니다. 비 정적 중첩 클래스는 내부 클래스라고합니다. 비 정적 중첩 클래스 (내부 클래스)는 private 클래스로 선언 된 경우에도 포함 클래스의 다른 멤버에 액세스 할 수 있습니다. 정적 중첩 클래스는 정적 클래스 인 경우에만 해당 클래스의 다른 멤버에 액세스 할 수 있습니다. 외부 클래스의 정적 멤버가 아닌 멤버는 액세스 할 수 없습니다. 클래스 메서드 및 변수와 마찬가지로 정적 중첩 클래스는 해당 외부 클래스와 연결됩니다. 예를 들어 정적 중첩 클래스에 대한 객체를 만들려면 다음 구문을 사용합니다.
OuterClass.StaticNestedClass nestedObject =
new OuterClass.StaticNestedClass();
내부 클래스를 인스턴스화하려면 먼저 외부 클래스를 인스턴스화해야합니다. 그런 다음이 구문을 사용하여 외부 객체 내에 내부 객체를 만듭니다.
OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();
중첩 된 클래스를 사용하는 이유
출처 : Java ™ 튜토리얼 - 중첩 클래스
우선, 정적 클래스라고하는 클래스는 없습니다. 내부 클래스 (중첩 클래스라고도 함)와 함께 정적 수정자를 사용하면 외부 클래스의 정적 멤버이므로 다른 정적 멤버와 마찬가지로 액세스 할 수 있습니다. Outer 클래스의 인스턴스입니다. (정적 인 것의 이점은 원래있다.)
중첩 클래스와 일반 Inner 클래스의 차이점은 다음과 같습니다.
OuterClass.InnerClass inner = new OuterClass().new InnerClass();
먼저 Outerclass를 인스턴스화 한 다음 Inner에 액세스 할 수 있습니다.
그러나 클래스가 중첩 된 경우 구문은 다음과 같습니다.
OuterClass.InnerClass inner = new OuterClass.InnerClass();
정적 키워드의 일반적인 구현으로 정적 구문을 사용합니다.