정적 및 최종 한정자가있는 이상한 Java 동작
이 질문에 이미 답변이 있습니다.
- 최종 필드 초기화 순서 2 답변
우리 팀에서 우리는 우리가 모두 사용되는 몇 가지 이상한 행동을 발견 static
하고 final
한정자를. 이것은 우리의 테스트 클래스입니다.
public class Test {
public static final Test me = new Test();
public static final Integer I = 4;
public static final String S = "abc";
public Test() {
System.out.println(I);
System.out.println(S);
}
public static Test getInstance() { return me; }
public static void main(String[] args) {
Test.getInstance();
}
}
main
메서드 를 실행하면 다음과 같은 결과가 나타납니다.
null
abc
null
정적 클래스 멤버의 코드가 위에서 아래로 실행되기 때문에 두 번 모두 값 을 썼다면 이해할 것 입니다.
누구든지이 행동이 왜 일어나는지 설명 할 수 있습니까?
프로그램을 실행할 때 취한 단계는 다음과 같습니다.
- 전에
main
실행할 수 있으며,Test
클래스는 외관의 순서로 정적 초기화를 실행하여 초기화해야합니다. me
필드 를 초기화하려면 실행을 시작하십시오new Test()
.- 의 값을 인쇄합니다
I
. 필드 유형이이므로Integer
컴파일 시간 상수처럼 보이는4
것이 계산 된 값 (Integer.valueOf(4)
)이됩니다. 이 필드의 이니셜 라이저가 아직 실행되지 않았으며 초기 값을 인쇄합니다null
. - 의 값을 인쇄합니다
S
. 컴파일 타임 상수로 초기화되기 때문에이 값은 참조 사이트 인 printingabc
. new Test()
완료되면 이제 이니셜 라이저가I
실행됩니다.
교훈 : 열심히 초기화 된 정적 싱글 톤에 의존하는 경우 싱글 톤 선언을 마지막 정적 필드 선언으로 배치하거나 다른 모든 정적 선언 이후에 발생하는 정적 초기화 블록에 의존합니다. 그러면 클래스가 싱글 톤의 구성 코드로 완전히 초기화 된 것처럼 보입니다.
S
JLS 15.28 규칙을 따르는 컴파일 타임 상수 입니다. 따라서 S
코드에서 발생하는 모든 항목은 컴파일 타임에 알려진 값으로 대체됩니다.
유형을 I
으로 변경하면 int
해당 항목도 동일하게 표시됩니다.
Integer
데이터 유형 으로 인해 이상한 동작이 있습니다 . JLS 12.4.2 와 관련하여 정적 필드는 작성한 순서대로 초기화되지만 컴파일 타임 상수가 먼저 초기화됩니다.
랩퍼 유형 사용하지 않는 경우 Integer
그러나 int
유형을, 당신은 당신이 원하는 동작을 얻을.
다음으로 Test
컴파일됩니다.
public class Test {
public static final Test me;
public static final Integer I;
public static final String S = "abc";
static {
me = new Test();
I = Integer.valueOf(4);
}
public Test() {
System.out.println(I);
System.out.println("abc");
}
public static Test getInstance() { return me; }
public static void main(String[] args) {
Test.getInstance();
}
}
As you can see, the constructor for Test
gets called before I
is initialized. This is why it prints "null"
for I
. If you were to swap the declaration order for me
and I
, you would get the expected result because I
would be initialized before the constructor is invoked. You can also change the type for I
from Integer
to int
.
Because 4
needs to get autoboxed (i.e., wrapped in an Integer
object), it is not a compile-time constant and is part of the static initializer block. However, if the type were int
, the number 4
would be a compile-time constant, so it would not need to be explicitly initialized. Because "abc"
is a compile-time constant, the value of S
is printed as expected.
If you would replace,
public static final String S = "abc";
with,
public static final String S = new String("abc");
Then you would notice the output of S
is "null"
as well. Why does that happen? For the same reason why I
also outputs "null"
. Fields like these that have literal, constant values (that do not need autoboxing, like String
) are attributed with the "ConstantValue"
attribute when compiled, which means that their value can be resolved simply by looking into the class' constant pool, without needing to run any code.
참고URL : https://stackoverflow.com/questions/39448160/strange-java-behaviour-with-static-and-final-qualifiers
'Nice programing' 카테고리의 다른 글
C의 구조 메모리 레이아웃 (0) | 2020.10.15 |
---|---|
Optional Bool의 값 확인 (0) | 2020.10.15 |
LAMP 스택이란 무엇입니까? (0) | 2020.10.15 |
Angularjs에 다른 상수로 상수를 정의하는 방법이 있습니까? (0) | 2020.10.15 |
텍스트보기에 인도 루피 기호 설정 (0) | 2020.10.15 |