[java] javac가 왜 불가능한 캐스트를 허용합니까?
나는 캐스팅하려고하면 String
A를 java.util.Date
, 자바 컴파일러는 오류를 잡는다. 그렇다면 왜 컴파일러가 다음을 오류로 표시하지 않습니까?
List<String> strList = new ArrayList<>();
Date d = (Date) strList;
물론 JVM ClassCastException
은 런타임 에을 throw 하지만 컴파일러는 플래그를 지정하지 않습니다.
동작은 javac 1.8.0_212 및 11.0.2와 동일합니다.
답변
캐스트 는 기술적으로 가능합니다. javac에서는 귀하의 경우와 다르지 않다는 것을 쉽게 입증 할 수 없으며 JLS는 실제로 이것을 유효한 Java 프로그램으로 정의하므로 오류 플래그를 잘못 지정합니다.
List
인터페이스 이기 때문 입니다. 따라서 Date
실제로 여기에 List
위장한 것을 구현 하는 하위 클래스를 가질 수 있습니다 . 예를 들면 다음과 같습니다.List
Date
public class SneakyListDate extends Date implements List<Foo> {
...
}
그리고:
List<Foo> list = new SneakyListDate();
Date date = (Date) list; // This one is valid, compiles and runs just fine
인스턴스가 예를 들어 메소드에서 온 경우 런타임 정보가 필요하므로 이러한 시나리오를 감지하는 것이 항상 가능한 것은 아닙니다. 그럼에도 불구하고 컴파일러에는 훨씬 더 많은 노력이 필요합니다. 컴파일러는 클래스 트리를 전혀 일치시킬 수 없기 때문에 절대적으로 불가능한 캐스트 만 방지합니다. 보시다시피 여기서는 그렇지 않습니다.
JLS에서는 코드가 유효한 Java 프로그램이어야합니다. 에서 5.1.6.1. 좁혀진 참조 변환 허용 :
, 축소 참조 변환은 참조 형식에서 존재하는
S
참조 형식에T
경우 모두 다음 중이 사실 :
- […]
- 다음 경우 중 하나 가 적용됩니다 .
- […]
S
인터페이스 유형이고T
클래스 유형이며 클래스T
이름을 지정하지 않습니다final
.
따라서 컴파일러 가 사례가 실제로 불가능하다는 것을 알 JLS에서이를 유효한 Java 프로그램으로 정의하므로 오류를 표시 할 수 없습니다.
경고 만 표시 할 수 있습니다.
답변
예제의 일반화를 고려해 보겠습니다.
List<String> strList = someMethod();
Date d = (Date) strList;
이것이 Date d = (Date) strList;
컴파일 오류가 아닌 주된 이유 입니다.
-
직관적 인 이유는 컴파일러가 메소드 호출에 의해 반환 된 객체의 정확한 유형을 알고 있지 (일반적으로) 않는다는 것입니다. 구현 하는 클래스 일뿐
List
만 아니라 의 하위 클래스 일 수도 있습니다Date
. -
기술적 인 이유는 Java 언어 사양 “허용”하는 것입니다 축소 참조 변환 이이 유형 캐스트에 해당합니다. 에 따르면 JLS 5.1.6.1 :
” 다음 모두가 참이면 참조 유형에서 참조 유형
S
으로 축소 참조 변환이 존재T
합니다.”…
5) ”
S
는 인터페이스 유형이며T
클래스 유형이며 클래스T
이름을 지정하지 않습니다final
.”…
다른 곳에서 JLS는 런타임에 예외가 발생할 수 있다고 말합니다 …
JLS 5.1.6.1 결정은 실제 런타임 유형이 아니라 관련 변수의 선언 된 유형 에만 기반 합니다. 일반적인 경우 컴파일러는 실제 런타임 유형을 알 수 없으며 알 수 없습니다.
그렇다면 왜 Java 컴파일러가 캐스트가 작동하지 않는다고 해결할 수 없습니까?
-
이 예에서
someMethod
호출은 다양한 유형의 객체를 반환 할 수 있습니다. 컴파일러가 메소드 본문을 분석하고 리턴 될 수있는 정확한 유형 세트를 판별 할 수 있다고하더라도이를 호출하는 코드를 컴파일 한 후 다른 유형을 리턴하도록 누군가가 변경을 중지하는 것은 없습니다. 이것이 JLS 5.1.6.1이 말하는 내용의 기본 이유입니다. -
당신의 예에서, 스마트 컴파일러는 수 캐스트가 성공하지 못할 수 있음을 알아낼. 그리고 문제를 지적하기 위해 컴파일 타임 경고 를 낼 수 있습니다.
그렇다면 왜 똑똑한 컴파일러가 이것이 오류라고 말할 수는 없습니까?
-
JLS는 이것이 유효한 프로그램이라고 말합니다. 기간. 이것을 에러 라고하는 컴파일러는 Java 호환이되지 않습니다.
-
또한 JLS와 다른 컴파일러가 유효하다고 말한 Java 프로그램을 거부하는 컴파일러 는 Java 소스 코드의 이식성을 방해합니다.
답변
컴파일시 참조 형을 감안할 때
S
(소스) 및 컴파일 시간 기준 유형T
(대상)을 주조 변환에서 존재S
에
T
더 컴파일 시간 오류는 다음과 같은 규칙으로 인해 발생하지 않는 경우.[…]
경우
S
인터페이스 유형은 다음과 같습니다
[…]
경우
T
최종없는 클래스 또는 인터페이스 유형이 다음 슈퍼가 존재하는 경우X
의T
, 그리고 슈퍼 타입Y
의
S
두 않도록,X
그리고Y
라도 유용 별개의 매개 변수 종류를, 그리고의 소거 것을X
하고는Y
동일하며, 컴파일 타임 오류 발생합니다.(경우에도 때문에 그렇지 않으면, 캐스트는 항상 컴파일시에 법적
T
구현하지 않는S
의 서브 클래스,T
힘).
List<String>
이다 S
하고 Date
있다 T
귀하의 경우.