class OuterClass {
class InnerClass {
static int i = 100; // compile error
static void f() { } // compile error
}
}
를 사용하여 정적 필드에 액세스 할 OuterClass.InnerClass.i
수는 없지만 정적이어야하는 항목 (예 : 생성 된 InnerClass 개체 수)을 기록하려면 해당 필드를 정적으로 만드는 것이 도움이됩니다. 그렇다면 Java는 왜 내부 클래스에서 정적 필드 / 메서드를 금지합니까?
편집 : 정적 중첩 클래스 (또는 정적 내부 클래스)로 컴파일러를 행복하게 만드는 방법을 알고 있지만 Java가 언어 디자인과 내부 클래스 내부의 정적 필드 / 메서드를 금지하는 이유를 알고 싶습니다. 누군가가 그것에 대해 더 많이 알고 있다면 구현 측면.
답변
내부 클래스의 개념은 둘러싸는 인스턴스의 컨텍스트에서 작동하는 것입니다. 어떻게 든 정적 변수와 메서드를 허용하는 것이 이러한 동기와 모순됩니까?
8.1.2 내부 클래스 및 엔 클로징 인스턴스
내부 클래스는 명시 적으로 또는 암시 적으로 정적으로 선언되지 않은 중첩 클래스입니다. 내부 클래스는 정적 이니셜 라이저 (§8.7) 또는 멤버 인터페이스를 선언 할 수 없습니다. 내부 클래스는 컴파일 타임 상수 필드 (§15.28)가 아닌 경우 정적 멤버를 선언 할 수 없습니다.
답변
내가 알고 싶은 것은 자바가 내부 클래스 내부의 정적 필드 / 메서드를 금지하는 이유입니다.
내부 클래스는 “인스턴스”내부 클래스이기 때문입니다. 즉, 둘러싸는 개체의 인스턴스 속성과 같습니다.
그들은 “인스턴스”클래스이기 때문에 static
기능 을 허용 하는 static
것은 의미가 없습니다. 왜냐하면는 처음에 인스턴스없이 작동하기 위한 것 입니다.
정적 / 인스턴스 속성을 동시에 생성하려고하는 것과 같습니다.
다음 예를 살펴보십시오.
class Employee {
public String name;
}
두 개의 employee 인스턴스를 생성하는 경우 :
Employee a = new Employee();
a.name = "Oscar";
Employee b = new Employee();
b.name = "jcyang";
왜 각각의 자산에 대해 고유 한 가치가 있는지 분명합니다. name
그렇죠?
내부 클래스도 마찬가지입니다. 각 내부 클래스 인스턴스는 다른 내부 클래스 인스턴스와 독립적입니다.
따라서 counter
클래스 속성 을 만들려고하면 두 개의 다른 인스턴스에서 해당 값을 공유 할 방법이 없습니다.
class Employee {
public String name;
class InnerData {
static count; // ??? count of which ? a or b?
}
}
인스턴스 생성 할 때 a
와 b
위의 예를, 어떤 정적 변수에 대한 올바른 값이 될 것이다 count
? InnerData
클래스 의 존재 는 둘러싸고있는 각 객체에 완전히 의존 하기 때문에이를 결정할 수 없습니다 .
그렇기 때문에 클래스가으로 선언되면 static
더 이상 살아있는 인스턴스가 필요하지 않습니다. 이제 종속성이 없으므로 정적 속성을 자유롭게 선언 할 수 있습니다.
반복적으로 들리지만 인스턴스 속성과 클래스 속성의 차이점을 생각하면 이해가 될 것입니다.
답변
InnerClass
static
인스턴스 (의 OuterClass
)에 속하므로 구성원을 가질 수 없습니다 . 당신이 선언하면 InnerClass
같은 static
인스턴스에서 분리하기 위해 코드를 컴파일합니다.
class OuterClass {
static class InnerClass {
static int i = 100; // no compile error
static void f() { } // no compile error
}
}
BTW : .NET Framework의 인스턴스를 계속 만들 수 있습니다 InnerClass
. static
이 컨텍스트에서 OuterClass
.
답변
실제로 정적 필드가 상수이고 컴파일 타임에 기록 된 경우 선언 할 수 있습니다.
class OuterClass {
void foo() {
class Inner{
static final int a = 5; // fine
static final String s = "hello"; // fine
static final Object o = new Object(); // compile error, because cannot be written during compilation
}
}
}
답변
- 클래스 초기화 순서 는 중요한 이유입니다.
내부 클래스는 엔 클로징 / 외부 클래스의 인스턴스에 종속되므로 Inner 클래스를 초기화하기 전에 Outer 클래스를 초기화해야합니다.
이것은 JLS가 클래스 초기화에 대해 말합니다. 우리가 필요로하는 요점은 다음과 같은 경우 클래스 T가 초기화된다는 것입니다.
- T에 의해 선언 된 정적 필드가 사용되며 필드는 상수 변수가 아닙니다.
따라서 내부 클래스에 액세스하는 정적 필드가 있으면 내부 클래스가 초기화되지만 포함하는 클래스가 초기화되지는 않습니다.
-
그것은 몇 가지 기본 규칙을 위반합니다 . 멍청한 물건을 피하기 위해 마지막 섹션 (까지
two cases
)으로 건너 뛸 수 있습니다.
에 대한 한 가지 , 일부 는 모든면에서 일반 클래스처럼 작동하고 Outer 클래스와 연결된다는 것입니다.static nested
class
nested class
static
그러나 Inner class
/ 의 개념은 외부 / 인 클로징 클래스 와 연관 될 것 입니다. 클래스가 아닌 인스턴스 와 연관되어 있습니다. 이제 인스턴스와 연결한다는 것은 인스턴스 변수의 개념에서 볼 때 인스턴스 내부에 존재하며 인스턴스간에 달라짐을 의미합니다. non-static
nested class
instance
이제 무언가를 정적으로 만들면 클래스가로드 될 때 초기화되고 모든 인스턴스간에 공유되어야합니다. 그러나 비정 적이기 때문에 내부 클래스 자체 ( 지금은 내부 클래스의 인스턴스에 대해 확실히 잊을 수 있음 )가 외부 / 인 클로징 클래스의 모든 인스턴스 ( 적어도 개념적으로 ) 와 공유되지 않습니다 . 그러면 어떻게 일부 변수를 기대할 수 있습니까? 내부 클래스의 모든 인스턴스간에 공유됩니다.
따라서 Java에서 정적 중첩 클래스가 아닌 정적 변수를 사용할 수 있다면. 두 가지 경우 가 있습니다 .
- 내부 클래스의 모든 인스턴스와 공유하면
context of instance
(인스턴스 변수) 개념을 위반하게됩니다 . 그럼 아니오입니다. - 모든 인스턴스와 공유되지 않으면 정적 개념을 위반하게됩니다. 다시 NO.
답변
이 “한계”에 가장 적합한 동기는 다음과 같습니다. 내부 클래스의 정적 필드 동작을 외부 개체의 인스턴스 필드로 구현할 수 있습니다.
따라서 정적 필드 / 메서드 가 필요하지 않습니다 . 내가 의미하는 동작은 일부 개체의 모든 내부 클래스 인스턴스가 필드 (또는 메서드)를 공유한다는 것입니다.
따라서 모든 내부 클래스 인스턴스를 세고 싶다고 가정하면 다음과 같이 할 수 있습니다.
public class Outer{
int nofInner; //this will count the inner class
//instances of this (Outer)object
//(you know, they "belong" to an object)
static int totalNofInner; //this will count all
//inner class instances of all Outer objects
class Inner {
public Inner(){
nofInner++;
totalNofInner++;
}
}
}
답변
간단히 말해서 비 정적 내부 클래스는 외부 클래스에 대한 인스턴스 변수로 외부 클래스가 생성되고 런타임에 외부 클래스 객체가 생성되고 클래스 로딩시 정적 변수가 생성 될 때만 생성됩니다. 따라서 비 정적 내부 클래스는 런타임 문제이므로 비 정적 내부 클래스의 일부가 아닌 정적입니다.
참고 : 내부 클래스는 항상 외부 클래스의 변수처럼 취급해야합니다. 다른 변수처럼 정적이거나 비정적일 수 있습니다.
