O que há de errado com os genéricos do Java? [fechadas]

46

Eu tenho visto várias vezes neste site postagens que condenam a implementação de genéricos do Java. Agora, posso dizer honestamente que não tive problemas em usá-los. No entanto, eu não tentei fazer uma classe genérica sozinho. Então, quais são seus problemas com o suporte genérico do Java?

    
por Michael K 30.11.2010 / 21:41
fonte

7 respostas

50

A implementação genérica do Java usa tipo eliminação . Isso significa que suas coleções genéricas strongmente tipificadas são realmente do tipo Object no tempo de execução. Isso tem algumas considerações de desempenho, pois significa que tipos primitivos devem ser encaixados quando adicionados a uma coleção genérica. É claro que os benefícios da correção do tempo de compilação superam a disparidade geral do apagamento do tipo e o foco obsessivo na compatibilidade retroativa.

    
por 30.11.2010 / 21:54
fonte
26

Observe que as respostas que já foram fornecidas se concentram na combinação de Java-the-language, JVM e Java Class Library.

Não há nada de errado com os genéricos do Java no que diz respeito à linguagem Java. Conforme descrito em genéricos C # vs Java , os genéricos de Java são muito bem no nível de linguagem 1 .

O que é suboptimal é que a JVM não suporta genéricos diretamente, o que tem várias consequências importantes:

  • as partes relacionadas à reflexão da Biblioteca de classes não podem expor as informações do tipo completo que estavam disponíveis no Java-the-language
  • alguma penalidade de desempenho está envolvida

Suponho que a distinção que estou fazendo seja pedante, já que o Java-the-language é ubiquamente compilado com a JVM como destino e a Java Class Library como a biblioteca principal.

1 Com a possível exceção de curingas, o que se acredita tornar a inferência de tipo indecidível no caso geral. Esta é uma grande diferença entre os genéricos C # e Java que não são mencionados com muita frequência. Obrigado, antimônio.

    
por 01.12.2010 / 04:12
fonte
13

A crítica usual é a falta de reificação. Ou seja, os objetos em tempo de execução não contêm informações sobre seus argumentos genéricos (embora as informações ainda estejam presentes em campos, métodos, construtores e classes e interfaces estendidas). Isso significa que você pode converter, digamos, ArrayList<String> para List<File> . O compilador lhe dará avisos, mas também avisará se você pegar um ArrayList<String> atribuindo-o a uma referência Object e, em seguida, convertê-lo em List<String> . O lado positivo é que com os genéricos você provavelmente não deveria estar fazendo o casting, o desempenho é melhor sem os dados desnecessários e, claro, a compatibilidade com versões anteriores.

Algumas pessoas reclamam que você não pode sobrecarregar com base em argumentos genéricos ( void fn(Set<String>) e void fn(Set<File>) ). Você precisa usar nomes de métodos melhores. Observe que essa sobrecarga não exigiria reificação, pois a sobrecarga é um problema estático em tempo de compilação.

Tipos primitivos não funcionam com genéricos.

Caracteres curinga e limites são bastante complicados. Eles são muito úteis. Se o Java preferisse as interfaces de imutabilidade e tell-don't-ask, então os genéricos do lado da declaração e não do lado do uso seriam mais apropriados.

    
por 30.11.2010 / 23:08
fonte
10

Os genéricos Java são uma droga, porque você não pode fazer o seguinte:

public class AsyncAdapter<Parser,Adapter> extends AsyncTask<String,Integer,Adapter> {
    proptected Adapter doInBackground(String... keywords) {
      Parser p = new Parser(keywords[0]); // this is an error
      /* some more stuff I was hoping for but couldn't do because
         the compiler wouldn't let me
      */
    }
}

Você não precisaria abocanhar todas as classes no código acima para que funcionasse como deveria se os genéricos fossem realmente parâmetros de classe genéricos.

    
por 10.02.2011 / 05:13
fonte
5
    Os
  • avisos do compilador para parâmetros genéricos ausentes que não têm propósito tornam a linguagem sem sentido detalhada, por exemplo, public String getName(Class<?> klazz){ return klazz.getName();}

  • Genéricos não são legais com as matrizes

  • As informações de tipo perdidas tornam a reflexão uma confusão de vazamento e fita adesiva.

por 10.02.2011 / 05:59
fonte
5

Eu acho que outras respostas disseram isso em algum grau, mas não muito claramente. Um dos problemas com genéricos é perder os tipos genéricos durante o processo de reflexão. Então, por exemplo:

List<String> arr = new ArrayList<String>();
assertTrue( ArrayList.class, arr.getClass() );
TypeVarible[] types = arr.getClass().getTypedVariables();

Infelizmente, os tipos retornados não podem dizer que os tipos genéricos de arr são String. É uma diferença sutil, mas é importante. Como o arr é criado no tempo de execução, os tipos genéricos são apagados no tempo de execução para que você não consiga descobrir isso. Como alguns afirmaram ArrayList<Integer> parece o mesmo que ArrayList<String> do ponto de vista da reflexão.

Isso pode não importar para o usuário do Generics, mas digamos que queremos criar uma estrutura sofisticada que use a reflexão para descobrir coisas sofisticadas sobre como o usuário declarou os tipos genéricos concretos de uma instância.

Factory<MySpecialObject> factory = new Factory<MySpecialObject>();
MySpecialObject obj = factory.create();

Digamos que queremos que uma fábrica de genéricos crie uma instância de MySpecialObject , porque esse é o tipo genérico concreto que declaramos para essa instância. Bem, a classe Factory não pode se interrogar para descobrir o tipo concreto declarado para esta instância porque o Java os apagou.

Nos genéricos do .Net você pode fazer isso porque, em tempo de execução, o objeto sabe seus tipos genéricos, porque o compilador o aceitou no binário. Com rasuras, o Java não pode fazer isso.

    
por 01.12.2010 / 03:51
fonte
1

Eu poderia dizer algumas coisas boas sobre genéricos, mas essa não era a questão. Eu poderia reclamar que eles não estão disponíveis em tempo de execução e não funcionam com matrizes, mas isso já foi mencionado.

Um grande aborrecimento psicológico: ocasionalmente entro em situações em que os genéricos não podem funcionar. (Matrizes sendo o exemplo mais simples.) E eu não consigo descobrir se os genéricos não podem fazer o trabalho ou se sou apenas idiota. Eu odeio isso. Algo como genéricos deve funcionar sempre. Toda vez que eu não posso fazer o que eu quero usando Java-the-language, eu sei o problema sou eu, e eu sei que se eu continuar empurrando, eu vou chegar lá eventualmente. Com os genéricos, se eu ficar muito persistente, posso perder muito tempo.

Mas o problema real é que os genéricos adicionam muita complexidade para um ganho muito pequeno. Nos casos mais simples, isso pode me impedir de adicionar uma maçã a uma lista contendo carros. Bem. Mas sem genéricos, este erro lançaria um ClassCastException realmente rápido em tempo de execução com pouco tempo perdido. Se eu adicionar um carro com uma cadeira de criança com uma criança, preciso de um aviso em tempo de compilação de que a lista é apenas para carros com cadeirinhas que contenham chimpanzés bebês? Uma lista de instâncias simples de objetos começa a parecer uma boa ideia.

O código genérico pode ter muitas palavras e caracteres, ocupar muito espaço extra e levar muito mais tempo para ler. Eu posso gastar muito tempo fazendo todo o código extra funcionar corretamente. Quando isso acontece, eu me sinto insanamente inteligente. Eu também perdi várias horas ou mais do meu próprio tempo e tenho que me perguntar se alguém mais conseguirá descobrir o código. Eu gostaria de poder entregá-lo para manutenção a pessoas que são menos espertas do que eu ou que têm menos tempo a perder.

Por outro lado (fiquei um pouco nervoso e sinto a necessidade de fornecer algum equilíbrio), é legal usar coleções simples e mapas para adicionar, colocar e ser verificado quando escrito, e geralmente não adiciona muita complexidade ao código ( se alguém else escreve a coleção ou mapa) . E Java é melhor nisso do que C #. Parece que nenhuma das coleções C # que eu quero usar sempre manipula genéricos. (Eu admito que tenho gostos estranhos em coleções.)

    
por 09.02.2012 / 23:04
fonte

Tags