Java가 배열에서 복사 된 경우 최종 변수에 대한 명시 적 캐스트가 필요한 이유는 무엇입니까?
다음 코드로 시작합니다 ...
byte foo = 1;
byte fooFoo = foo + foo;
이 코드를 컴파일하려고하면 다음과 같은 오류가 발생합니다.
오류 : (5, 27) Java : 호환되지 않는 유형 : 정수에서 바이트로 손실 가능한 변환 가능
...하지만 foo
최종적인 경우 ...
final byte foo = 1;
final byte fooFoo = foo + foo;
파일이 성공적으로 컴파일됩니다.
다음 코드로 이동 ...
final byte[] fooArray = new byte[1];
fooArray[0] = 1;
final byte foo = fooArray[0];
fooArray[0] = 127;
System.out.println("foo is: " + foo);
... 인쇄합니다
foo is: 1
... 괜찮습니다. 값은 최종 변수에 복사되며 더 이상 변경할 수 없습니다. 배열의 값을 가지고 놀아도 foo
(예상대로 ...) 의 값이 변경되지 않습니다 .
다음 항목에 캐스트가 필요한 이유는 무엇입니까?
final byte[] fooArray = new byte[1];
fooArray[0] = 1;
final byte foo = fooArray[0];
final byte fooFoo = foo + foo;
이 질문의 두 번째 예와 어떻게 다른가요? 컴파일러에서 다음 오류가 발생하는 이유는 무엇입니까?
오류 : (5, 27) Java : 호환되지 않는 유형 : 정수에서 바이트로 손실 가능한 변환 가능
어떻게 이런 일이 일어날 수 있습니까?
JLS ( §5.2 )에는 상수 표현식을 사용한 할당 변환에 대한 특수 규칙이 있습니다 .
또한, 식 일정한 표현 (경우 §15.28 형)
byte
,short
,char
, 또는int
:
- 좁아 기본 변환 변수의 타입 인 경우 사용될 수있는
byte
,short
또는char
, 상기 식의 상수 값이 변수의 타입에서 표현할 수있다.
위의 링크를 따라 가면 상수 표현식 의 정의에서 다음과 같이 볼 수 있습니다 .
위의 두 번째 링크를 따라 가면
기본 형식 또는 형식의 변수
String
, 즉final
컴파일 타임 상수 식 ( §15.28 )으로 초기화 된 변수를 상수 변수 라고 합니다 .
그 다음 foo + foo
단지에 할당 할 수있는 fooFoo
경우에 foo
A는 상수 변수 . 이를 귀하의 사례에 적용하려면 :
byte foo = 1;
상수 변수가 아니기 때문에 정의 하지 않습니다final
.final byte foo = 1;
않는 정의 상수 변수 가 있기 때문에,final
및로 초기화 상수 식 (원시 리터럴).final byte foo = fooArray[0];
상수 표현식으로 초기화되지 않았기 때문에 상수 변수를 정의 하지 않습니다 .
여부를주의 fooFoo
그 자체는 final
중요하지 않습니다.
값 1은 바이트에 잘 맞습니다. 1 + 1도 마찬가지입니다. 변수가 최종일 때 컴파일러는 상수 접기를 수행 할 수 있습니다 . (즉, 컴파일러는 foo
+ 연산을 수행 할 때 사용하지 않지만 "원시"1 값)
그러나 변수가 최종적이지 않으면 전환 및 프로모션에 대한 모든 흥미로운 규칙이 시작됩니다 ( 여기를 참조 하십시오 . 기본 전환 확대에 대한 섹션 5.12를 읽고 싶습니다).
두 번째 부분의 경우 : 배열을 최종화하면 해당 필드 를 변경할 수 있습니다. 그래서 다시; 지속적인 폴딩이 불가능합니다. "확대"작업이 다시 시작됩니다.
final
바이트 코드에서 볼 수 있듯이 실제로 컴파일러와 함께 사용할 때 상수 접기에서 수행하는 작업입니다 .
byte f = 1;
// because compiler still use variable 'f', so `f + f` will
// be promoted to int, so we need cast
byte ff = (byte) (f + f);
final byte s = 3;
// here compiler will directly compute the result and it know
// 3 + 3 = 6 is a byte, so no need cast
byte ss = s + s;
//----------------------
L0
LINENUMBER 12 L0
ICONST_1 // set variable to 1
ISTORE 1 // store variable 'f'
L1
LINENUMBER 13 L1
ILOAD 1 // use variable 'f'
ILOAD 1
IADD
I2B
ISTORE 2 // store 'ff'
L2
LINENUMBER 14 L2
ICONST_3 // set variable to 3
ISTORE 3 // store 's'
L3
LINENUMBER 15 L3
BIPUSH 6 // compiler just compute the result '6' and set directly
ISTORE 4 // store 'ss'
마지막 바이트를 127로 변경하면 다음과 같이 불평합니다.
final byte s = 127;
byte ss = s + s;
이 경우 컴파일러는 결과를 계산하고 한계를 벗어난 것을 알고 있으므로 여전히 호환되지 않는다고 불평합니다.
더:
그리고 여기 문자열을 사용한 상수 접기에 대한 또 다른 질문이 있습니다.
'Nice programing' 카테고리의 다른 글
분기 이름에 '공백'문자가 포함될 수없는 이유는 무엇입니까? (0) | 2020.12.25 |
---|---|
Swift 3에서 함수의 클로저 매개 변수를 어떻게 문서화합니까? (0) | 2020.12.25 |
디버그 모드가 아닐 때 Visual Studio의 출력 창에 메시지를 표시합니까? (0) | 2020.12.25 |
동일한 R 패키지의 여러 버전을 어떻게 사용합니까? (0) | 2020.12.25 |
R : 상대 경로를 사용하여 파일 소싱 (0) | 2020.12.25 |