Tenho a classe Historico, e as classes HistoricoAluno e HistoricoProfessor que estendem Historico…
No runtime posso passar uma ou outra assim:
Set<? extends Historico> colecaoDeHistoricos = new HashSet<HistoricoAluno>([Passa uma collection aqui]);
Só que gostaria de manipular “colecaoDeHistoricos” de acordo com o tipo, se fosse HistoricoAluno fazia uma coisa, se fosse HistoricoProfessor fazia outra…
Tenho a classe Historico, e as classes HistoricoAluno e HistoricoProfessor que estendem Historico…
No runtime posso passar uma ou outra assim:
Set<? extends Historico> colecaoDeHistoricos = new HashSet<HistoricoAluno>([Passa uma collection aqui]);
Só que gostaria de manipular “colecaoDeHistoricos” de acordo com o tipo, se fosse HistoricoAluno fazia uma coisa, se fosse HistoricoProfessor fazia outra…
Alguém ajuda? Obrigado. [/quote]
Parece um pouco tosco, mas talvez seja uma solução que pensei rapidamente. A lista será somente de um objeto, certo ?
Podes pegar o objeto da primeira posição e verificar via instance of a qual classe pertence, depois, é iterar sobre a lista de acordo com o tipo que desejas.
[quote=Vin?ius Abreu de Fran?]Só teria essa maneira? Isso me cheira mal… Tipo, não posso pegar diretamente o tipo da coleção já que sei que todos os itens são do mesmo tipo…
Tentei:
//Quero saber se o Set colecaoDeHistoricos é do tipo Set<HistoricoAluno>
colecaoDeHistoricos.getClass().isAssignableFrom(HistoricoAluno.class)
Mas nada… :roll: [/quote]
A princípio, isso não é possível, pois a informação de tipo genérico é removida após a compilação. Agora, se você precisa de um comportamento que varia com o tipo do objeto, esse comportamento tem que ser implementado dentro da classe, e não fora dela. Pesquise sobre o padrão Strategy.
Ambas soluções retornam um class, o que não mostra qual classe é. De qualquer forma, tem que verificar a classe.
Ainda acho que verificar via instance of o primeiro objeto e a partir dele identificar tua necessidade é uma boa solução.
Agora, se quer melhorar isso, é adotar a ideia do rmendes08, é uma alternativa e possivelmente mais elegante.
Podes usar a solução de reflection, é claro. Podes criar um método que te retorna um Enum ou algo do tipo indicando qual classe é, é uma solução também.
Olá pessoal, obrigado pelas respostas, já tentei as outras soluções e nada, acho que a do drsmachado (usar reflection) se aproxima mais do que eu quero fazer. Sobre o padrão Strategy, acho que não se encaixaria aqui no contexto e mesmo que o fizesse, em algum momento teria que fazer a comparação de tipos… Vou tentar usar reflection e posto e resultado…
*Só esclarecendo a outra solução postada por mauriciot.silva, não quero iterar na lista, quero saber de que tipo é para adicionar mais um elemento e setar no bean do tipo correto. (Uma Cidade possui uma lista de históricos de Alunos e Professores, tenho que saber em qual lista adicionar)
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
public class Test {
List<String> stringList = new ArrayList<String>();
List<Integer> integerList = new ArrayList<Integer>();
public static void main(String... args) throws Exception {
Field stringListField = Test.class.getDeclaredField("stringList");
ParameterizedType stringListType = (ParameterizedType) stringListField.getGenericType();
Class<?> stringListClass = (Class<?>) stringListType.getActualTypeArguments()[0];
System.out.println(stringListClass); // class java.lang.String.
Field integerListField = Test.class.getDeclaredField("integerList");
ParameterizedType integerListType = (ParameterizedType) integerListField.getGenericType();
Class<?> integerListClass = (Class<?>) integerListType.getActualTypeArguments()[0];
System.out.println(integerListClass); // class java.lang.Integer.
}
}
And tell us what`s the result…[/quote]
Eu fiz um teste aqui e essa abordagem não resolve o problema:
1 - você só consegue fazer essa inferência a partir de variáveis de instância
2 - nem sempre o tipo retornado por getActualTypeArguments é uma classe. No caso, de declarar o seu Set como Set<? extends Historico> vai retornar um WildcardType.
Ou seja, mesmo essa solução só te permite obter tipos conhecidos em tempo de compilação, mas você não consegue obter o tipo passado como argumento na criação do HashSet.
Enfim, eu consideraria seriamente repensar esse design enquanto houver tempo, caso contrário, esse tipo de workaround vai se espalhar rapidamente pelo seu sistema.
Minha sugestão: o bom e velho composição a favor de herança. Por que ao invés de estender Historico, você não mantém uma única classe Historico com um campo de tipo e um campo objeto para receber tanto Aluno quanto Professor ? Ou então, você definitivamente separa HistoricoAluno e HistoricoProfessor, sem relação de herança entre elas …
Olá amigos do GUJ, desculpem a demora pra responder já que já tinha conseguido resolver com uma solução que adotei na mesma tarde (final de semana, mais tempo pra responde heheh)…
Bem pessoal, depois de testar as várias soluções apontadas resolvi escolher a mais simples e NÃO a considero como POG já que só posso escolher entre um tipo e outro e resolveu perfeitamente o problema. O jeito foi verificar o tipo do item que vem contido na lista pra saber o tipo da lista, solução de mauriciot.silva embora que modificada pois não vou percorrer os itens.
Aqui vai um exemplo de como fiz envolvendo as entidades Contador e Prefeito:
private void ordenaEAdicionaNaColecaoDeHistoricoGenerico(Set<? extends Historico> colecaoDeHistoricos, boolean isOrdemCrescente) {
assert !colecaoDeHistoricos.isEmpty();
if (colecaoDeHistoricos.toArray()[0] instanceof HistoricoContador) {
TreeSet<HistoricoContador> ts;
if (isOrdemCrescente) {
ts = new TreeSet<HistoricoContador>(comparatorHistoricoOrdemCrescente);
} else {
ts = new TreeSet<HistoricoContador>(comparatorHistoricoOrdemDecrescente);
}
ts.addAll((Set<HistoricoContador>) colecaoDeHistoricos);
cidade.setHistoricoContatores(ts);
} else if (colecaoDeHistoricos.toArray()[0] instanceof HistoricoPrefeito) {
TreeSet<HistoricoPrefeito> ts;
if (isOrdemCrescente) {
ts = new TreeSet<HistoricoPrefeito>(comparatorHistoricoOrdemCrescente);
} else {
ts = new TreeSet<HistoricoPrefeito>(comparatorHistoricoOrdemDecrescente);
}
ts.addAll((Set<HistoricoPrefeito>) colecaoDeHistoricos);
cidade.setHistoricoPrefeitos(ts);
}
}