Se eu tentar converter a String
para a java.util.Date
, o compilador Java detectará o erro. Então, por que o compilador não sinaliza o seguinte como erro?
List<String> strList = new ArrayList<>();
Date d = (Date) strList;
Obviamente, a JVM lança um ClassCastException
em tempo de execução, mas o compilador não o sinaliza.
O comportamento é o mesmo com o javac 1.8.0_212 e 11.0.2.
java
casting
compiler-errors
javac
Mike Woinoski
fonte
fonte
List
aqui.Date d = (Date) new Object();
strList
fosse uma instância de uma classe que implemente List.Respostas:
O elenco é tecnicamente possível. Não é possível provar facilmente pelo javac que não é assim no seu caso e o JLS realmente define isso como um programa Java válido, portanto, sinalizar um erro seria incorreto.
Isso ocorre porque
List
é uma interface. Então, você poderia ter uma subclasse de umDate
que realmente implementaList
disfarçada comoList
aqui - e, em seguida, convertê-laDate
seria perfeitamente aceitável. Por exemplo:E depois:
Detectar tal cenário nem sempre é possível, pois exigiria informações de tempo de execução se a instância vier de, por exemplo, um método. E mesmo que isso exigiria muito mais esforço para o compilador. O compilador apenas evita lançamentos que são absolutamente impossíveis, porque não há como a árvore de classes corresponder. O que não é o caso aqui, como visto.
Observe que o JLS requer que seu código seja um programa Java válido. No 5.1.6.1. Conversão de referência restrita permitida diz:
Portanto, mesmo que o compilador possa descobrir que seu caso é realmente comprovadamente impossível, não é permitido sinalizar um erro porque o JLS o define como um programa Java válido.
Só seria permitido mostrar um aviso.
fonte
myDate = (Date) myString
falhar. Usando a terminologia JLS, a instrução tenta converter deS
(theString
) paraT
(theDate
). Aqui,S
não é um tipo de interface, portanto, a condição JLS citada acima não se aplica. Como exemplo, tente converter um calendário para uma data e você receberá um erro do compilador, mesmo que nenhuma classe seja final.Date & List
é inabitável , não basta provar que está desabitado atualmente (pode ser no futuro).Vamos considerar uma generalização do seu exemplo:
Essas são as principais razões pelas quais
Date d = (Date) strList;
não há erro de compilação.A razão intuitiva é que o compilador não (em geral) conhece o tipo preciso do objeto retornado por essa chamada de método. É possível que, além de ser uma classe que implemente
List
, ela também seja uma subclasse deDate
.O motivo técnico é que a Java Language Specification "permite" a conversão de referência restritiva que corresponde a esse tipo de conversão . De acordo com o JLS 5.1.6.1 :
Em um local diferente, o JLS também diz que uma exceção pode ser lançada em tempo de execução ...
Observe que a determinação do JLS 5.1.6.1 é baseada apenas nos tipos declarados das variáveis envolvidas, e não nos tipos de tempo de execução reais. No caso geral, o compilador não conhece e não pode conhecer os tipos de tempo de execução reais.
Então, por que o compilador Java não pode descobrir que o elenco não funcionará?
No meu exemplo, a
someMethod
chamada pode retornar objetos com vários tipos. Mesmo que o compilador tenha sido capaz de analisar o corpo do método e determinar o conjunto preciso de tipos que podem ser retornados, não há nada para impedir que alguém o altere para retornar tipos diferentes ... depois de compilar o código que o chama. Essa é a razão básica pela qual o JLS 5.1.6.1 diz o que diz.No seu exemplo, um compilador inteligente pode descobrir que o elenco nunca pode ter sucesso. E é permitido emitir um aviso em tempo de compilação para apontar o problema.
Então, por que um compilador inteligente não pode dizer que isso é um erro?
Porque o JLS diz que este é um programa válido. Período. Qualquer compilador que chamasse isso de erro não seria compatível com Java.
Além disso, qualquer compilador que rejeite programas Java que o JLS e outros compiladores dizem que é válido é um impedimento à portabilidade do código-fonte Java.
fonte
5.5.1 Carcaça do tipo de referência:
List<String>
éS
eDate
éT
no seu caso.fonte