Tendo aprendido durante meus dias de C ++ sobre os males do operador de elenco de estilo C, fiquei satisfeito em primeiro lugar ao descobrir que em Java 5 java.lang.Class
havia adquirido um cast
método.
Achei que finalmente tínhamos uma maneira OO de lidar com o elenco.
Acontece que Class.cast
não é o mesmo que static_cast
em C ++. É mais parecido reinterpret_cast
. Não irá gerar um erro de compilação onde é esperado e, em vez disso, irá adiar para o tempo de execução. Aqui está um caso de teste simples para demonstrar diferentes comportamentos.
package test;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class TestCast
{
static final class Foo
{
}
static class Bar
{
}
static final class BarSubclass
extends Bar
{
}
@Test
public void test ( )
{
final Foo foo = new Foo( );
final Bar bar = new Bar( );
final BarSubclass bar_subclass = new BarSubclass( );
{
final Bar bar_ref = bar;
}
{
// Compilation error
final Bar bar_ref = foo;
}
{
// Compilation error
final Bar bar_ref = (Bar) foo;
}
try
{
// !!! Compiles fine, runtime exception
Bar.class.cast( foo );
}
catch ( final ClassCastException ex )
{
assertTrue( true );
}
{
final Bar bar_ref = bar_subclass;
}
try
{
// Compiles fine, runtime exception, equivalent of C++ dynamic_cast
final BarSubclass bar_subclass_ref = (BarSubclass) bar;
}
catch ( final ClassCastException ex )
{
assertTrue( true );
}
}
}
Então, essas são minhas perguntas.
- Deve
Class.cast()
ser banido para terras de Genéricos? Lá, ele tem alguns usos legítimos. - Os compiladores devem gerar erros de compilação quando
Class.cast()
são usados e condições ilegais podem ser determinadas em tempo de compilação? - O Java deve fornecer um operador de elenco como uma construção de linguagem semelhante ao C ++?
java
generics
casting
compiler-warnings
Alexander Pogrebnyak
fonte
fonte
Class.cast()
quando condições ilegais podem ser determinadas em tempo de compilação. Nesse caso, todos, exceto você, apenas usam o operador de elenco padrão. (3) Java tem um operador cast como uma construção de linguagem. Não é semelhante ao C ++. Isso ocorre porque muitas das construções da linguagem Java não são semelhantes a C ++. Apesar das semelhanças superficiais, Java e C ++ são bastante diferentes.Respostas:
Eu sempre usei
Class.cast(Object)
para evitar avisos na "terra dos genéricos". Costumo ver métodos fazendo coisas assim:Geralmente, é melhor substituí-lo por:
Esse é o único caso de uso para
Class.cast(Object)
que eu já encontrei.Com relação aos avisos do compilador: Suspeito que isso
Class.cast(Object)
não seja especial para o compilador. Ele poderia ser otimizado quando usado estaticamente (ou seja, emFoo.class.cast(o)
vez decls.cast(o)
), mas nunca vi ninguém usando - o que torna o esforço de construir essa otimização no compilador um tanto inútil.fonte
Primeiro, você está fortemente desencorajado a fazer quase qualquer elenco, então você deve limitá-lo tanto quanto possível! Você perde os benefícios dos recursos fortemente tipados em tempo de compilação do Java.
Em qualquer caso,
Class.cast()
deve ser usado principalmente quando você recupera oClass
token por meio de reflexão. É mais idiomático escreverao invés de
EDIT: Erros em tempo de compilação
Acima de tudo, o Java realiza verificações de elenco apenas em tempo de execução. No entanto, o compilador pode emitir um erro se puder provar que tais casts nunca terão sucesso (por exemplo, lançar uma classe para outra classe que não seja um supertipo e lançar um tipo de classe final para classe / interface que não está em sua hierarquia de tipo). Aqui, uma vez que
Foo
eBar
são classes que não estão em uma outra hierarquia, o elenco nunca pode ter sucesso.fonte
Class.cast
pareça caber na conta, ele cria mais problemas do que resolve.É sempre problemático e muitas vezes enganoso tentar traduzir construções e conceitos entre idiomas. O elenco não é exceção. Particularmente porque Java é uma linguagem dinâmica e C ++ é um pouco diferente.
Todo o cast em Java, não importa como você o faça, é feito em tempo de execução. As informações de tipo são mantidas em tempo de execução. C ++ é um pouco mais que uma mistura. Você pode converter uma estrutura em C ++ para outra e é apenas uma reinterpretação dos bytes que representam essas estruturas. Java não funciona assim.
Além disso, os genéricos em Java e C ++ são muito diferentes. Não se preocupe excessivamente em como você faz as coisas em C ++ em Java. Você precisa aprender a fazer as coisas do jeito Java.
fonte
(Bar) foo
, gera um erro em tempo de compilação, masBar.class.cast(foo)
não. Na minha opinião, se for usado dessa maneira, deveria.Bar.class.cast(foo)
diz explicitamente ao compilador que você deseja fazer a conversão em tempo de execução. Se você quiser verificar em tempo de compilação a validade do elenco, sua única opção é fazer o(Bar) foo
elenco de estilo.Class.cast()
raramente é usado em código Java. Se for usado, geralmente com tipos que só são conhecidos em tempo de execução (ou seja, por meio de seus respectivosClass
objetos e por algum parâmetro de tipo). Só é realmente útil em código que usa genéricos (essa também é a razão pela qual não foi introduzido anteriormente).É não semelhante a
reinterpret_cast
, porque ele vai não permitem que você quebrar o sistema de tipos em tempo de execução mais do que um elenco normal faz (ou seja, você pode quebrar parâmetros de tipo genérico, mas não pode quebrar tipos "reais").Os males do operador de elenco C-style geralmente não se aplicam ao Java. O código Java que se parece com um elenco de estilo C é mais semelhante a um
dynamic_cast<>()
com um tipo de referência em Java (lembre-se: Java tem informações de tipo de tempo de execução).Geralmente, comparar os operadores de conversão de C ++ com a conversão de Java é muito difícil, pois em Java você só pode lançar referência e nenhuma conversão acontece para objetos (apenas valores primitivos podem ser convertidos usando esta sintaxe).
fonte
dynamic_cast<>()
com um tipo de referência.Geralmente, o operador cast é preferível ao método cast Class #, pois é mais conciso e pode ser analisado pelo compilador para revelar problemas gritantes com o código.
Class # cast assume a responsabilidade pela verificação de tipo em tempo de execução, e não durante a compilação.
Certamente, há casos de uso para elenco de classe #, particularmente quando se trata de operações reflexivas.
Desde que lambda veio para java, eu pessoalmente gosto de usar Class # cast com a API Collections / stream se estou trabalhando com tipos abstratos, por exemplo.
fonte
C ++ e Java são linguagens diferentes.
O operador cast do Java C-style é muito mais restrito do que a versão C / C ++. Efetivamente, o cast de Java é como o C ++ dynamic_cast se o objeto que você possui não pode ser convertido para a nova classe, você obterá uma exceção de tempo de execução (ou se houver informações suficientes no código em um tempo de compilação). Assim, a ideia C ++ de não usar casts de tipo C não é uma boa ideia em Java
fonte
Além de remover avisos de elenco feio como mais mencionado, Class.cast é elenco de tempo de execução usado principalmente com elenco genérico, devido às informações genéricas serão apagadas em tempo de execução e de alguma forma cada genérico será considerado Objeto, isso leva a não lance uma ClassCastException antecipada.
por exemplo, serviceLoder use este truque ao criar os objetos, verifique S p = service.cast (c.newInstance ()); isso lançará uma exceção de lançamento de classe quando SP = (S) c.newInstance (); não irá e pode mostrar um aviso 'Segurança de tipo: conversão não verificada de objeto em S' . (igual a Object P = (Object) c.newInstance ();)
-Simplesmente, ele verifica se o objeto cast é uma instância da classe de cast, então ele usará o operador cast para lançar e ocultar o aviso, suprimindo-o.
implementação java para elenco dinâmico:
fonte
Pessoalmente, já usei isso antes para construir um conversor JSON para POJO. No caso de o JSONObject processado com a função conter uma matriz ou JSONObjects aninhados (implicando que os dados aqui não são de um tipo primitivo ou
String
), tento invocar o método setter usandoclass.cast()
desta forma:Não tenho certeza se isso é extremamente útil, mas como disse aqui antes, reflexão é um dos poucos casos de uso legítimos
class.cast()
que posso pensar, pelo menos você tem outro exemplo agora.fonte