Alguém sabe dizer se a Oracle já resolveu a questão do erasure na compilação que elimina a informação dos generics em tempo de compilação no Java?
Quero dizer assim:
public class X<T> {
List<T> list = new ArrayList<T>();
public T addNewObject() {
Class classOfT = T.class; // Ou outra maneira de pegar a classe referente ao tipo generico.
T obj = (T) classOfT.newInstance(); // Criar nova instância de alguma forma.
list.add(obj);
return obj;
}
}
Assim, em outro lugar poderia ser usado isso, por exemplo:
public class Y {
public static void main(String[] args) {
X<Date> x = new X<Date>();
// ===== e depois em outro lugar...
Object n = x.addNewObject();
// Tudo isso é apenas exemplo, acho que já foi explanado inúmeros casos onde seria interessante
// saber a classe que foi definida declarada como generics.
}
}
Alguém sabe se houve solução no Java 7 para codigos semelhantes? Tem alguma previsão para solucionar isso?
Cara, isso não é um erro, isso foi uma decisão de projeto. Entre outros motivos, de ter sido feito assim, está o fato de que o Java 5 tinha que ser compatível com as versões anteriores da plataforma.
E na boa mesmo ? Quando eu vejo tentando fazer esse tipo de uso de generics, na maioria das vezes é um design complexo, que poderia ficar muito melhor com boa aplicação de OO.
Uma coisa que faz falta (devido a não haver “reificação dos generics”) é que ele impõe que T não possa ser um tipo primitivo.
OK, eu sei que se pudesse ser, teria de ser criado dinamicamente código para tipos primitivos, mas isso provavelmente iria tornar estruturas de dados como ArrayList ou TreeSet muito mais eficientes. (Existem essas especializações em algumas bibliotecas, como Apache Commons, mas é sempre um problema ter de usar algo que não está no JDK. )
Em C# o recurso de generics é reificado e é bem mais simples que no Java. Ele não teve o propósito de ser compatível com versões anteriores do C# (tanto é que existem namespaces diferentes para as coleções que aceitam e as que não aceitam generics), mas acho mais simples usar em C# que em Java.
Alguém sabe dizer se a Oracle já resolveu a questão do erasure na compilação que elimina a informação dos generics em tempo de compilação no Java?
Quero dizer assim:
public class X<T> {
List<T> list = new ArrayList<T>();
public T addNewObject() {
Class classOfT = T.class; // Ou outra maneira de pegar a classe referente ao tipo generico.
T obj = (T) classOfT.newInstance(); // Criar nova instância de alguma forma.
list.add(obj);
return obj;
}
}
Assim, em outro lugar poderia ser usado isso, por exemplo:
public class Y {
public static void main(String[] args) {
X<Date> x = new X<Date>();
// ===== e depois em outro lugar...
Object n = x.addNewObject();
// Tudo isso é apenas exemplo, acho que já foi explanado inúmeros casos onde seria interessante
// saber a classe que foi definida declarada como generics.
}
}
Alguém sabe se houve solução no Java 7 para codigos semelhantes? Tem alguma previsão para solucionar isso?
Abraços.[/quote]
Que eu saiba isso é impossível e vc acaba sendo obrigado a passar o tipo (Class<?>) como parâmetro do método ou construtor.
Como o Sergio disse, não tem como. A menos que você crie uma subclasse e faça alguns truques.
Eu dei uma abstraída com um framework e cheguei em um resultado assim:
this.type = reflect().genericType("T").in(this);
Aí uso isso no construtor da classe. Mas por baixo dos panos é uma solução grosseira (bem mais complexa do que a que foi apresentada).
Não vejo porque usar isso seja algo ruim. Não acho que seja menos OO, isso é algo que facilitaria, e muito, o desenvolvimento de soluções com menos código e mais convenções.
Um exemplo disso foi um mock de annotations que eu criei há um tempo, o código para criar o mock sem utilizar esse truque seria assim:
Resource resource = new AnnotationMock<Resource>(Resource.class) {{
map("name").to(annotation.name());
map(false).to(annotation.shareable());
}}.createMock();
Note que fica redundante eu dizer que o mock é da annotation Resource e ainda passar a classe no construtor. Com o truque fica assim:
Resource resource = new AnnotationMock<Resource>() {{
map("name").to(annotation.name());
map(false).to(annotation.shareable());
}}.createMock();
E para não declarar os valores (usar os “default”), fica assim:
Ataxexe, gostei da solução usando reflect(). Vou tentar fazer uns testes aqui.
A solução do renanreismartins também parece boa. Afinal, um dos problemas que eu pretendo resolver com isso é justamente a construção de um GenericDAO em uma camada de persistência isolada.
O que diz o rmendes08, que foi uma opção de projeto, eu já havia lido em vários lugares. Porém acho estranho o pessoal da Oracle e mesmo da Sun não terem implementado uma solução para tanto. Acho que para tudo tem uma solução. Sinceramente, penso que não priorizaram isso, simplesmente.
Acho que uma reescrita no contrato de Object, adicionando alguns poucos métodos e novas chamadas internas na hora de instanciar qualquer objeto já seria suficiente para manter compatibilidade retroativa e implementar uma sytax para reneric types baseado em reification.
Vou além: Acho que a syntax de declaração poderia ficar como está, com generic baseado em erasure. Porém, uma syntax na instância, poderia permanecer reificado. (eu acho)… Tipo assim:
// erasure na declaração:
List<Integer> numbers;
// reification no instanciamento:
numbers = new ArrayList<Integer>();
//Depois seria só pegar em algum método de Object que fosse adicionado, que retornasse uma Class[] por exemplo:
Class integerClass = numbers.getClassGenericClasses()[0]; //só de exemplo...
Daria para fazer implementado em Class.java também… Sei lá… A instância que não estivesse declarada daquela com reification, ele retornaria null no novo método e pronto… Não sei se falei besteira, mas…