왜 정적이 아닌 내부 클래스에 정적 메소드를 가질 수 없습니까?
내부 클래스를 정적으로 만들면 작동합니다. 왜?
static
."
왜 정적이 아닌 내부 클래스에 정적 메소드를 가질 수 없습니까?
내부 클래스를 정적으로 만들면 작동합니다. 왜?
static
."
답변:
내부 클래스의 인스턴스는 외부 클래스의 인스턴스와 암시 적으로 연결되므로 정적 메서드 자체를 정의 할 수 없습니다. 정적 중첩 클래스는 포함 클래스에 정의 된 인스턴스 변수 또는 메소드를 직접 참조 할 수 없으므로 객체 참조를 통해서만 사용할 수 있으므로 정적 중첩 클래스에서 정적 메소드를 선언하는 것이 안전합니다.
A.B.sync(X)
거나 (A 내에서) 전화를 걸 수 B.sync(x)
없습니까?
정적이 아닌 내부 클래스에서 정적 메서드를 허용 할 필요는 없습니다. 어떻게 접근하겠습니까? 외부 클래스 인스턴스를 거치지 않으면 비 정적 내부 클래스 인스턴스에 액세스 할 수 없습니다 (최소한 초기에). 정적이 아닌 내부 클래스를 만드는 순수한 정적 방법은 없습니다.
외부 클래스의 Outer
경우 다음 test()
과 같은 정적 메소드에 액세스 할 수 있습니다 .
Outer.test();
정적 내부 클래스의 Inner
경우 다음 innerTest()
과 같이 정적 메소드에 액세스 할 수 있습니다 .
Outer.Inner.innerTest();
그러나 Inner
정적이 아닌 경우 메소드를 참조하는 완전히 정적 인 방법은 없습니다 innertest
. 비 정적 내부 클래스는 외부 클래스의 특정 인스턴스에 연결됩니다. Outer.Inner.CONSTANT
함수 호출 Outer.Inner.staticFunction();
이 아닌 방식으로에 대한 참조 가 명확하게 보장 된다는 점에서 함수는 상수와 다릅니다 . 에 정의 된 Inner.staticFunction()
호출 이 있다고 가정 해 보겠습니다 . 정적 함수를 호출하려고하면 이제 Inner 클래스에 대한 모호한 참조가 생깁니다. 즉, 내부 클래스의 어느 인스턴스에서 정적 함수를 호출합니까? 그것은 중요. 외부 객체에 대한 암시 적 참조로 인해 정적 메소드를 참조하는 정적 방법은 없습니다.getState()
Outer
Paul Bellora는 언어 디자이너가 이것을 허용했을 수도 있습니다. 그런 다음 정적이 아닌 내부 클래스의 정적 메서드에서 외부 클래스에 대한 암시 적 참조에 대한 액세스를 신중하게 허용하지 않아야합니다. 이때 정적 클래스를 제외하고 외부 클래스를 참조 할 수없는 경우 내부 클래스가되는 값은 무엇입니까? 그리고 정적 액세스가 괜찮다면 왜 내부 클래스 전체를 정적으로 선언하지 않습니까? 내부 클래스 자체를 정적으로 만들면 외부 클래스에 대한 암시 적 참조가 없으며 더 이상이 모호성이 없습니다.
비 정적 내부 클래스에 실제로 정적 메소드 가 필요한 경우 설계를 다시 생각해야합니다.
Outer.Inner i = new Outer().new Inner();
또한 내부 클래스 는 JLS §15.28에 따라 정적 상수 를 선언 할 수 있습니다.
Outer.Inner.staticMethod()
액세스 할 수있는 것처럼 전화를 겁니다 Outer.Inner.CONSTANT
. "외부 클래스 인스턴스를 거치지 않으면 정적이 아닌 내부 클래스 인스턴스에 액세스 할 수 없습니다." 왜 인스턴스가 필요합니까? Outer
호출 할 인스턴스가 필요하지 않습니다 Outer.staticMethod()
. 나는 이것이 nitpicky라는 것을 알고 있지만 내 요점은 당신의 대답을 이런 식으로 구성하는 것이 의미가 없다는 것입니다. IMHO는 언어 디자이너가 원하는 경우 허용 할 수있었습니다.
Outer.Inner.CONSTANT
와 Outer.Inner.staticMethod()
일정한 기준에 내재적 인스턴스 참조의 기회가없는 점이다 Outer
있는을 Inner
인스턴스화한다. 모든 Outer.staticMethod()
정확한 참조 상태 를 공유합니다. 모든 Outer.Inner.CONSTANT
정확한 참조 상태 를 공유합니다. 그러나에 대한 참조 Outer.Inner.staticMethod()
는 모호합니다. "정적"상태는의 각 인스턴스에서 외부 클래스에 대한 암시 적 참조로 인해 실제로 정적이 아닙니다 Inner
. 액세스 할 수있는 확실한 방법은 없습니다.
Outer.this
. 내부 클래스의 모든 것이 포함 클래스의 컨텍스트 내에 있어야하기 때문에 내부 클래스에 정적 메소드 또는 최종이 아닌 정적 필드를 허용 할 이유가 없다는 Java 언어 디자이너에 동의합니다.
나는 틀릴 수도 있고 틀릴 수도있는 이론을 가지고있다.
먼저 내부 클래스가 Java로 구현되는 방법에 대해 알아야합니다. 이 수업이 있다고 가정 해보십시오.
class Outer {
private int foo = 0;
class Inner implements Runnable {
public void run(){ foo++; }
}
public Runnable newFooIncrementer(){ return new Inner(); }
}
컴파일하면 생성 된 바이트 코드는 다음과 같이 쓴 것처럼 보입니다.
class Outer {
private int foo = 0;
static class Inner implements Runnable {
private final Outer this$0;
public Inner(Outer outer){
this$0 = outer;
}
public void run(){ this$0.foo++; }
}
public Runnable newFooIncrementer(){ return new Inner(this); }
}
비 정적 내부 클래스에서 정적 메서드를 허용 한 경우 이와 같은 작업을 수행 할 수 있습니다.
class Outer {
private int foo = 0;
class Inner {
public static void incrFoo(){ foo++; }
}
}
... Inner
클래스 당 하나의 화신이 있는 것처럼 보이므로 상당히 합리적 Outer
입니다. 그러나 위에서 본 것처럼 정적이 아닌 내부 클래스는 실제로 정적 "내부"클래스의 구문 설탕이므로 마지막 예제는 대략 다음과 같습니다.
class Outer {
private int foo = 0;
static class Inner {
private final Outer this$0;
public Inner(Outer outer){
this$0 = outer;
}
public static void incrFoo(){ this$0.foo++; }
}
}
... this$0
정적 이기 때문에 분명히 작동하지 않습니다 . 이런 종류의 정적 메소드가 허용되지 않는 이유는 무엇입니까? 다른 객체의 정적이 아닌 내부 클래스의 인스턴스가 "정적 상태"를 공유하는 경우 반 직관적입니다. 또한 엔 클로징 오브젝트를 참조하지 않는 한 최종 필드 가 허용되는 이유도 설명합니다 .
public static double sinDeg(double theta) { ... }
내부 수학 유틸리티 클래스 를 작성 하려면 어떻게해야 합니까?
유일한 이유는 "필수적이지 않다"는 것인데, 왜 그것을지지해야 하는가?
구문 적으로 내부 클래스에 정적 멤버가있는 것을 금지 할 이유가 없습니다. 의 인스턴스가의 인스턴스와 Inner
연결되어 있지만 정적 멤버를 참조하는 데 Outer
여전히 사용할 수 있습니다.Outer.Inner.myStatic
Inner
java가 그렇게하기로 결정한 경우 .
의 모든 인스턴스간에 무언가를 공유해야하는 경우 Inner
이를 Outer
정적 멤버 로 넣을 수 있습니다 . 에 이것은 당신이 정적 멤버를 사용하는 것보다하지 더 나쁜 Inner
경우, Outer
여전히의 private 멤버에 액세스 할 수 있습니다Inner
(캡슐이 향상되지 않습니다) 어쨌든.
Inner
하나의 outer
객체 로 생성 된 모든 인스턴스간에 무언가를 공유 해야하는 경우 인스턴스에 넣는 것이 더 합리적입니다.Outer
일반 구성원 클래스 입니다.
"정적 중첩 클래스는 거의 최상위 클래스"라는 의견에 동의하지 않습니다. 정적 중첩 클래스 / 내부 클래스는 외부 클래스의 일부로 간주하는 것이 좋습니다. 외부 클래스의 개인 멤버에 액세스 할 수 있기 때문입니다. 그리고 외부 계급의 구성원도 "내부 계급의 구성원"입니다. 따라서 내부 클래스에서 정적 멤버를 지원할 필요가 없습니다. 외부 클래스의 일반 / 정적 구성원이면 충분합니다.
보낸 사람 : https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
인스턴스 메서드 및 변수와 마찬가지로 내부 클래스는 해당 클래스의 인스턴스와 연결되며 해당 개체의 메서드 및 필드에 직접 액세스 할 수 있습니다. 또한 내부 클래스는 인스턴스와 연결되므로 정적 멤버 자체를 정의 할 수 없습니다.
오라클의 설명은 피상적이고 손으로 만듭니다. 내부 클래스 내에서 정적 멤버를 선점해야 할 기술적 또는 구문상의 이유가 없기 때문에 (C #과 같은 다른 언어로 허용됨) Java 디자이너의 동기는 개념적 취향 및 / 또는 기술적 편의성 문제 일 수 있습니다.
내 추측은 다음과 같습니다.
최상위 클래스와 달리 내부 클래스는 인스턴스에 따라 다릅니다. 내부 클래스 인스턴스는 모든 외부 클래스의 인스턴스와 연결되며 해당 멤버에 직접 액세스 할 수 있습니다. 이것이 자바를 사용하게하는 주요 동기입니다. 다른 방법으로 표현 : 내부 클래스가되는 의미 외부 클래스 인스턴스의 맥락에서 인스턴스화. 외부 클래스 인스턴스가 없으면 내부 클래스는 외부 클래스 의 다른 인스턴스 멤버보다 더 이상 사용할 수 없습니다 . 이것을 내부 클래스 의 인스턴스 종속 정신 이라고하겠습니다 .
정적 멤버 (객체 지향이 아님)의 본질은 외부 클래스 인스턴스없이 내부 클래스의 정적 멤버를 참조 / 호출 할 수 있기 때문에 인스턴스 지향적 인 내부 클래스 정신 ( 객체 지향)과 충돌 합니다. 규정 된 내부 클래스 이름 사용
정적 변수는 특히 또 다른 방식으로 기분을 상하게 할 수 있습니다. 외부 클래스의 다른 인스턴스와 연관된 내부 클래스의 두 인스턴스는 정적 변수를 공유합니다. 변수는 상태의 구성 요소이므로 사실상 두 개의 내부 클래스 인스턴스는 연결된 외부 클래스 인스턴스와 독립적으로 상태를 공유합니다. 정적 변수가 이런 식으로 작동하는 것은 용납 할 수없는 것은 아니지만 (Java에서 OOP 순도에 대한 합리적인 타협으로 허용 함) 인스턴스가 이미 외부 클래스 인스턴스와 결합 된 내부 클래스에서 허용함으로써 더 큰 위반이있을 수 있습니다. 디자인에 의해. 인스턴스 종속 정신 에 찬성하여 내부 클래스 내에서 정적 멤버를 금지 하면이 더 깊은 OOP 공격을 선점하는 추가 보너스가 제공됩니다.
다른 한편으로, 그러한 위반은 정적 상수에 의해 수반되지 않으며, 이는 의미 상 상태를 구성하지 않으므로 허용 될 수 있습니다. 인스턴스 종속 정신과 의 최대 일관성을 위해 정적 상수를 금지하지 않는 이유 입니까? 아마도 상수 는 필요한 것보다 더 많은 메모리를 차지할 필요가 없기 때문에 (정적이지 않으면 강제로 낭비되는 모든 내부 클래스 인스턴스에 복사됩니다) 그렇지 않으면 예외의 이유를 상상할 수 없습니다.
확실한 추론은 아니지만 IMO는 그 문제에 대한 오라클의 커서 발언을 가장 잘 이해합니다.
짧은 대답 : 대부분의 프로그래머가 범위가 작동하는 방식에 대한 정신 모델은 javac에서 사용하는 모델이 아닙니다. 보다 직관적 인 모델을 찾으려면 javac 작동 방식에 큰 변화가 필요했을 것입니다.
내부 클래스의 정적 멤버가 바람직한 주된 이유는 코드 청결도 때문입니다. 내부 클래스에서만 사용되는 정적 멤버는 외부 클래스에 배치하지 않고 내부 클래스에 있어야합니다. 치다:
class Outer {
int outID;
class Inner {
static int nextID;
int id = nextID++;
String getID() {
return outID + ":" + id;
}
}
}
규정되지 않은 식별자 "outID"를 사용할 때 getID ()에서 무슨 일이 일어나고 있는지 고려하십시오. 이 식별자가 나타나는 범위는 다음과 같습니다.
Outer -> Inner -> getID()
여기서도 javac가 작동하는 방식이므로 범위의 "Outer"레벨에는 Outer의 정적 및 인스턴스 멤버가 모두 포함됩니다. 우리는 일반적으로 클래스의 정적 부분을 다른 수준의 범위로 생각해야하므로 혼동됩니다.
Outer static -> Outer instance -> instanceMethod()
\----> staticMethod()
물론 이런 생각으로 staticMethod ()는 외부의 정적 멤버 만 볼 수 있습니다. 그러나 이것이 javac가 작동하는 방식이라면 정적 메소드에서 인스턴스 변수를 참조하면 "이름을 확인할 수 없습니다"오류가 발생합니다. 실제로 발생하는 것은 이름이 범위에 있지만 추가 수준의 확인이 시작되어 이름이 인스턴스 컨텍스트에서 선언되었고 정적 컨텍스트에서 참조되고 있음을 알아내는 것입니다.
자, 이것이 내부 클래스와 어떤 관련이 있습니까? 우리는 내부 클래스가 정적 범위를 가질 수없는 이유가 없다고 생각합니다.
Outer static -> Outer instance -> Inner instance -> getID()
\------ Inner static ------^
즉, 내부 클래스의 정적 선언과 외부 클래스의 인스턴스 선언은 모두 내부 클래스의 인스턴스 컨텍스트 내에 있지만 실제로는 다른 클래스에 중첩되지 않습니다. 둘 다 외부의 정적 범위에 중첩됩니다.
그것은 javac가 작동하는 방식이 아닙니다. 정적 및 인스턴스 멤버 모두에 대한 단일 레벨 범위가 있으며 범위는 항상 엄격하게 중첩됩니다. 상속은 심지어 수퍼 클래스 범위를 분기하고 검색하는 대신 선언을 서브 클래스에 복사하여 구현됩니다.
중 분할 정적을 가지고 예를 스코프 것 javac의 내부 클래스의 정적 멤버 지원 및 지원 분기 및 범위 계층 구조를 재결합, 또는이 모든 수준에서 컨텍스트의 유형을 추적하기 위해 변화에 간단한 부울 "정적 컨텍스트"개념을 확장 할 것을 현재 범위의 중첩 클래스
왜 정적이 아닌 내부 클래스에 정적 메소드를 가질 수 없습니까?
참고 : 정적이 아닌 중첩 클래스는 내부 클래스로 알려져 있으므로 그렇게하지 마십시오 non-static inner class
.
내부 클래스 인스턴스는 해당 외부 클래스 인스턴스가 없으면 존재하지 않습니다. 내부 클래스는 컴파일 시간 상수 이외의 정적 멤버를 선언 할 수 없습니다. 그것이 허용된다면의 의미에 대한 모호성이 있었을 것이다 static
. 이 경우 특정 혼란이 있었을 것입니다.
그렇기 때문에 설계자들은 아마도이 문제를 전혀 처리하지 않기로 결정한 것입니다.
내부 클래스를 정적으로 만들면 작동합니다. 왜 ?
다시 내부 클래스를 정적으로 만들 수 없으며 정적 클래스를 중첩으로 선언 할 수 있습니다. 이 경우이 중첩 클래스는 실제로 외부 클래스의 일부이며 문제없이 정적 멤버를 가질 수 있습니다.
이 주제는 많은 사람들로부터 주목을 받았지만 여전히 가장 간단한 용어로 설명하려고 노력할 것입니다.
먼저, http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1 과 관련하여 클래스 또는 인터페이스는 첫 번째 발생 / 호출 직전에 초기화됩니다. static 키워드가 앞에 오는 멤버
따라서 내부 클래스 내에서 정적 멤버를 사용하면 외부 클래스를 포함하지 않아도 내부 클래스가 초기화됩니다. 따라서 클래스 초기화 시퀀스를 방해합니다.
또한 정적이 아닌 내부 클래스가 엔 클로징 / 외부 클래스의 인스턴스와 연결되어 있다는 사실을 고려하십시오. 따라서 인스턴스와 연결하면 내부 클래스가 외부 클래스 인스턴스 내에 존재하며 인스턴스마다 다릅니다.
요점을 단순화하려면 정적 멤버에 액세스하려면 외부 클래스의 인스턴스가 필요합니다.이 클래스에서 비 정적 내부 클래스의 인스턴스를 다시 만들어야합니다. 정적 멤버는 인스턴스에 바인딩되지 않아야하므로 컴파일 오류가 발생합니다.
외부 클래스의 인스턴스가 두 개이고 모두 내부 클래스를 인스턴스화했다고 가정합니다. 이제 내부 클래스에 하나의 정적 멤버가 있으면 힙 영역에 해당 멤버의 사본 하나만 유지합니다.이 경우 외부 클래스의 두 객체가 모두 단일 복사 및 함께 변경 가능 "이것은"더러운 읽기 "상황을 유발하여이 Java가이 제한을 적용하지 못하게 할 수 있습니다.이 인수를 지원하는 또 다른 장점은 java가 여기에서 값을 가질 수없는 최종 정적 멤버를 허용한다는 것입니다 외부 클래스 객체 중 하나에서 변경되었습니다. 내가 틀렸다면 알려주십시오.
우선 누군가 정적이 아닌 내부 클래스에서 정적 멤버를 정의하려는 이유는 무엇입니까? 대답은 외부 클래스 멤버가 내부 클래스 이름으로 만 정적 멤버를 사용할 수 있도록하는 것입니다.
그러나이 경우 외부 클래스에서 멤버를 직접 정의 할 수 있습니다. 외부 클래스 인스턴스 내에서 내부 클래스의 모든 객체와 연결됩니다.
아래 코드와 같이
public class Outer {
class Inner {
public static void method() {
}
}
}
이렇게 쓸 수 있습니다
public class Outer {
void method() {
}
class Inner {
}
}
따라서 제 생각에는 코드를 복잡하게하지 않기 위해 Java 디자이너는이 기능을 허용하지 않거나 향후 릴리스에서 더 많은 기능을 갖춘이 기능을 볼 수 있습니다.
수업을 일반 필드로 취급하면 이해하게 될 것입니다.
//something must be static. Suppose something is an inner class, then it has static keyword which means it's a static class
Outer.something
내부 클래스 멤버를 정적 멤버로 사용하는 것은 처음에는 액세스 할 수 없으므로 쓸모가 없습니다.
이것에 대해 생각해보십시오. className.memberName을 사용하는 정적 멤버에 액세스하려면 우리의 경우 outerclassName.innerclassName.memberName과 같아야합니다. 이제 innerclass가 정적이어야하는 이유를 알 수 있습니다 ....