초기화되지 않은 지역 변수를 사용하여 해당 변수 유형의 정적 콘텐츠에 액세스 할 수없는 이유는 무엇입니까?
초기화되지 않은 지역 변수 x
를 통해 정적 필드에 액세스하는 동안 컴파일 오류가 발생 합니다.Foo foo;
foo.x
Variable 'foo' might not have been initialized
class Foo{
public static int x = 1;
public static void main(String[] args) {
Foo foo;
System.out.println(foo.x); // Error: Variable 'foo' might not have been initialized
}
}
이 오류는 의미가 있는 것처럼 보일 수 있지만static
멤버 에 액세스하기 위해 컴파일러는 실제로 변수 값 을 사용하지 않고 해당 유형 만 사용 한다는 사실을 깨닫기 전까지 만 가능 합니다 .
예를 들어 foo
값으로 초기화 하면 문제없이 null
액세스 x
할 수 있습니다.
Foo foo = null;
System.out.println(foo.x); //compiles and while running prints 1!!!
이러한 시나리오는 컴파일러가 그것이 x
정적 임을 인식하고 foo.x
작성된 것처럼 처리 하기 때문에 작동 합니다 Foo.x
(적어도 지금까지 생각했던 것입니다).
그렇다면 컴파일러는 왜 갑자기 그 장소에서 사용하지 않을foo
값 을 가지고 있다고 주장 합니까?
(면책 조항 : 이것은 실제 응용 프로그램에서 사용되는 코드가 아니라 Stack Overflow에서 답을 찾을 수없는 흥미로운 현상 일 뿐이므로 질문하기로 결정했습니다.)
필드가 정적 인 경우 :
Primary식이 평가되고 결과가 삭제됩니다 . Primary 식의 평가가 갑자기 완료되면 같은 이유로 필드 액세스식이 갑자기 완료됩니다.
이전에는 필드 액세스가 Primary.Identifier
.
이것은를 사용하지 않는 것처럼 보이지만 Primary
여전히 평가되고 결과가 삭제되므로 초기화해야 함을 보여줍니다. 이는 견적서에 명시된대로 평가가 액세스를 중지 할 때 차이를 만들 수 있습니다.
편집하다:
다음은 Primary
결과가 삭제 되더라도가 평가 되는 것을 시각적으로 보여주는 간단한 예 입니다.
class Foo {
public static int x = 1;
public static Foo dummyFoo() throws InterruptedException {
Thread.sleep(5000);
return null;
}
public static void main(String[] args) throws InterruptedException {
System.out.println(dummyFoo().x);
System.out.println(Foo.x);
}
}
여기서는 항상 버려지 는 값을 반환하더라도 5 초 지연 dummyFoo()
되기 때문에 여전히 평가 되는 것을 볼 수 있습니다 .print
Thread.sleep()
null
표현식이 평가되지 않은 경우는 print
클래스가 때 볼 수있는, 즉시 나타납니다 Foo
액세스에 직접 사용 x
으로 Foo.x
.
참고 : 메서드 호출은 §15.8 Primary Expressions에Primary
표시된 것으로 간주됩니다 .
16 장. 명확한 할당
각 지역 변수 (§14.4) 및 모든 빈 최종 필드 (§4.12.4, §8.3.1.2) 에는 해당 값에 대한 액세스가 발생할 때 확실히 할당 된 값이 있어야합니다.
지역 변수를 통해 무엇 에 액세스하려고 하는지 는 중요하지 않습니다 . 규칙은 그 전에 확실히 할당되어야한다는 것입니다.
필드 액세스 식 을 평가하려면 foo.x
해당 primary
부분 ( foo
)을 먼저 평가해야합니다. 에 대한 액세스 foo
가 발생하여 컴파일 타임 오류가 발생 함을 의미합니다 .
지역 변수 또는 빈 마지막 필드 x에 대한 모든 액세스에 대해 액세스 전에 x를 확실히 할당해야합니다. 그렇지 않으면 컴파일 타임 오류가 발생합니다.
규칙을 가능한 한 단순하게 유지하는 것이 가치가 있으며 "초기화되지 않았을 수도있는 변수를 사용하지 마십시오"는 매우 간단합니다.
요컨대, 정적 메소드를 호출하는 확립 된 방법이 있습니다. 항상 변수가 아닌 클래스 이름을 사용하십시오.
System.out.println(Foo.x);
변수 "foo"는 제거해야하는 원치 않는 오버 헤드이며, 컴파일러 오류 및 경고가이를 유도하는 데 도움이 될 수 있습니다.
다른 답변은 일어나는 일의 메커니즘을 완벽하게 설명합니다. 아마도 당신은 Java의 사양에 대한 근거를 원했을 수도 있습니다. Java 전문가가 아니므로 원래 이유를 설명 할 수는 없지만이 점을 지적하겠습니다.
- Every piece of code either has a meaning or it triggers a compilation error.
- (For statics, because an instance is unnecessary,
Foo.x
is natural.) - Now, what shall we do with
foo.x
(access through instance variable)?- It could be a compilation error, as in C#, or
- It has a meaning. Because
Foo.x
already means "simply accessx
", it is reasonable that the expressionfoo.x
has a different meaning; that is, every part of the expression is valid and accessx
.
Let's hope someone knowledgeable can tell the real reason. :-)
'programing' 카테고리의 다른 글
이미지 대 zImage 대 uImage (0) | 2020.11.05 |
---|---|
"포인터 이벤트 : 없음"을 사용할 때 CSS 커서 속성 추가 (0) | 2020.11.05 |
자바 스크립트-객체 키-> 값 (0) | 2020.11.05 |
키 이름의 MongoDB 점 (.) (0) | 2020.11.04 |
블록 범위가 원래 JavaScript에서 구현되지 않은 이유는 무엇입니까? (0) | 2020.11.04 |