우선, 우리는 지역 변수에 대해서만 이야기하고 있습니다. 사실상 최종 은 필드에 적용되지 않습니다. final
필드에 대한 의미 체계 가 매우 다르고 많은 컴파일러 최적화 및 메모리 모델 약속이 적용 되기 때문에 이것은 중요 합니다. 최종 필드의 의미 체계에 대해서는 $ 17.5.1 을 참조하십시오 .
표면 수준 final
과 effectively final
지역 변수의 경우 실제로 동일합니다. 그러나 JLS는 이와 같은 특수한 상황에서 실제로 광범위한 효과를 갖는 둘을 명확하게 구분합니다.
전제
변수 에 대한 JLS§4.12.4 에서 final
:
상수 변수 A는 final
가변 기본 유형 또는 입력 문자열 로 초기화 상수 식 ( §15.29을 ). 변수가 상수 변수인지 여부는 클래스 초기화 ( §12.4.1 ), 이진 호환성 ( §13.1 ), 도달 가능성 ( §14.22 ) 및 명확한 할당 ( §16.1.1 ) 과 관련하여 영향 을 미칠 수 있습니다 .
int
은 원시적 이므로 변수 a
는 이러한 상수 변수 입니다.
또한, 같은 장에서 effectively final
:
final로 선언되지 않은 특정 변수는 대신 효과적으로 final로 간주됩니다. ...
이 말로하는 방식에서 그래서, 다른 예에서 분명하다 a
되어 있지 그대로, 일정한 변수를 고려 최종하지 ,하지만 에만 효과적으로 마지막.
행동
이제 구별이 생겼으니 무슨 일이 일어나고 있고 왜 출력이 다른지 살펴 보겠습니다.
? :
여기서 조건부 연산자를 사용하고 있으므로 정의를 확인해야합니다. 에서 JLS§15.25 :
두 번째 및 세 번째 피연산자 식에 따라 부울 조건식 , 숫자 조건식 및 참조 조건식의 세 가지 종류의 조건식이 있습니다.
이 경우, 우리는 얘기 숫자 조건식 에서, JLS§15.25.2 :
숫자 조건식의 유형은 다음과 같이 결정됩니다.
그리고 그것은 두 사건이 다르게 분류되는 부분입니다.
효과적으로 최종
effectively final
이 규칙과 일치하는 버전 :
그렇지 않으면 일반 숫자 승격 ( §5.6 )이 두 번째 및 세 번째 피연산자에 적용되고 조건식의 유형은 두 번째 및 세 번째 피연산자의 승격 된 유형입니다.
어떤 당신이 할 것인지와 같은 동작입니다 5 + 'd'
즉, int + char
에서 어떤 결과 int
. JLS§5.6 참조
숫자 승격은 숫자 컨텍스트에있는 모든 표현식의 승격 유형을 결정합니다. 승격 된 유형은 각 표현식이 승격 된 유형으로 변환 될 수 있도록 선택되며 산술 연산의 경우 승격 된 유형의 값에 대해 연산이 정의됩니다. 숫자 컨텍스트에서 표현식의 순서는 숫자 승격에 중요하지 않습니다. 규칙은 다음과 같습니다.
[...]
다음으로 확장 기본 변환 ( §5.1.2 ) 및 축소 기본 변환 ( §5.1.3 )이 다음 규칙에 따라 일부 표현식에 적용됩니다.
숫자 선택 컨텍스트에서 다음 규칙이 적용됩니다.
어떤 식 형인 경우 int
이고 일정하지 식 ( §15.29 ) 다음 추진 유형은 int
한 유형이 아닌 다른 표현 int
거칩니다 프리미티브 확대 변환 에이 int
.
따라서 모든 것이 이미 있는 int
그대로 승진됩니다 . 그것은의 출력을 설명합니다 .a
int
97
결정적인
final
변수가 있는 버전 은 다음 규칙과 일치합니다.
피연산자 중 하나가 is , 또는 또는 인 유형 T
이고 다른 피연산자가 값 을 유형 으로 표현할 수있는 유형 의 상수 식 ( §15.29 ) 인 경우 조건식의 유형은입니다 .T
byte
short
char
int
T
T
최종 변수 a
는 유형 int
이고 상수 표현식입니다 (이니까 final
). 으로 표현할 수 char
있으므로 결과는 유형 char
입니다. 이것으로 출력이 끝납니다 a
.
문자열 예
문자열이 같은 예는 동일한 핵심 차이점을 기반으로하며 final
변수는 상수 표현식 / 변수로 처리되며 effectively final
그렇지 않습니다.
Java에서 문자열 인턴 은 상수 표현식을 기반으로하므로
"a" + "b" + "c" == "abc"
이다 true
(실제 코드에서이 구문을 사용 해달라고)뿐만 아니라.
JLS§3.10.5 참조 :
또한 문자열 리터럴은 항상 String 클래스의 동일한 인스턴스를 참조합니다. 이는 문자열 리터럴 또는 보다 일반적으로 상수 표현식 ( §15.29 ) 의 값인 문자열이 메서드 ( §12.5 )를 사용하여 고유 한 인스턴스를 공유하도록 " 인터 닝 " 되기 때문 입니다.String.intern
주로 리터럴에 대해 이야기하기 때문에 간과하기 쉽지만 실제로는 상수 표현에도 적용됩니다.