Quais são as diferenças entre List
, List<?>
, List<T>
, List<E>
, e List<Object>
?
1. Lista
List
: é um tipo bruto, portanto não typesafe
. Isso gerará apenas um erro de tempo de execução quando a transmissão estiver ruim. Queremos um erro de tempo de compilação quando o elenco é ruim. Não recomendado para uso.
2. Lista <?>
List<?>
é um curinga ilimitado. Mas não sei ao certo para que serve? Posso imprimir um List<?>
sem problemas:
public static void test(List<?> list){
System.out.println(list); // Works
}
Por que não consigo adicionar itens a um List<?>
?
public static void test(List<?> list){
list.add(new Long(2)); // Error
list.add("2"); // Error
System.out.println(list);
}
3. Lista <T>
public static void test(List<T> list){ // T cannot be resolved
System.out.println(list);
}
Eu não entendo essa sintaxe. Eu vi algo assim, e funciona:
public <T> T[] toArray(T[] a){
return a;
}
Às vezes, eu vejo <T>
, ou <E>
, ou <U>
, <T,E>
. Eles são todos iguais ou representam algo diferente?
4. Liste <Objeto>
Isso fornece o erro "O método test(List<Object>)
não é aplicável ao argumento List<String>
":
public static void test(List<Object> list){
System.out.println(list);
}
Se eu tentar isso, obtive "Não é possível transmitir de List<String>
para List<Object>
":
test((List<Object>) names);
Estou confuso. String
é uma subclasse de Object
, então por que não é List<String>
uma subclasse de List<Object>
?
2
. Eu escrevo alguns códigos para demonstrar isso2
. tyvmList<Object>
?Para a última parte: Embora String seja um subconjunto de Objeto, mas Lista <> não é herdada da Lista <Objeto>.
fonte
List<Object>
?A notação
List<?>
significa "uma lista de algo (mas não estou dizendo o que)". Como o códigotest
funciona para qualquer tipo de objeto na lista, isso funciona como um parâmetro formal do método.O uso de um parâmetro de tipo (como no seu ponto 3) exige que o parâmetro de tipo seja declarado. A sintaxe Java para isso é colocar
<T>
na frente da função. Isso é exatamente análogo a declarar nomes de parâmetros formais para um método antes de usar os nomes no corpo do método.Quanto a
List<Object>
não aceitar aList<String>
, isso faz sentido porque aString
não éObject
; é uma subclasse deObject
. A correção é declararpublic static void test(List<? extends Object> set) ...
. Mas então oextends Object
é redundante, porque toda classe se estende direta ou indiretamenteObject
.fonte
List<Object>
?List<?>
pois a lista é de algum tipo específico, mas desconhecido.List<Object>
seria realmente "uma lista de qualquer coisa", pois pode realmente conter qualquer coisa.A razão que você não pode lançar
List<String>
aList<Object>
é que ele iria permitir que você violar as restrições doList<String>
.Pense no seguinte cenário: Se eu tiver um
List<String>
, ele deve conter apenas objetos do tipoString
. (Que é umafinal
classe)Se eu puder converter isso para a
List<Object>
, isso me permitirá adicionarObject
a essa lista, violando o contrato original deList<String>
.Portanto, em geral, se a classe
C
herda de classeP
, você não pode dizer queGenericType<C>
também herda deGenericType<P>
.NB: Eu já comentei isso em uma resposta anterior, mas queria expandi-lo.
fonte
List<Object>
?List<Object>
pois isso meio que derrota o propósito dos genéricos. No entanto, há casos em que o código antigo pode terList
tipos diferentes aceitos; portanto, você pode modificar o código para usar a parametrização de tipo apenas para evitar avisos do compilador para tipos brutos. (Mas a funcionalidade é inalterada) #Eu aconselharia a leitura de quebra-cabeças Java. Explica muito bem herança, genéricos, abstrações e curingas em declarações. http://www.javapuzzlers.com/
fonte
Vamos falar sobre eles no contexto da história do Java;
List
:Lista significa que pode incluir qualquer objeto. A lista estava no release anterior ao Java 5.0; O Java 5.0 introduziu a Lista, para compatibilidade com versões anteriores.
List<?>
:?
significa Objeto desconhecido, nenhum Objeto; a?
introdução do curinga é para resolver o problema criado pelo tipo genérico; veja curingas ; mas isso também causa outro problema:List< T> List< E>
Significa Declaração genérica na premissa de nenhum tipo T ou E em seu projeto Lib.
List< Object>
significa parametrização genérica.fonte
No terceiro ponto, "T" não pode ser resolvido porque não é declarado; geralmente, quando você declara uma classe genérica, pode usar "T" como o nome do parâmetro do tipo acoplado , muitos exemplos online, incluindo
os tutoriais da Oracle,usam "T" como o nome do parâmetro type, digamos, por exemplo, que você declara uma classe como:você está dizendo que o
FooHandler's
operateOnFoo
método espera uma variável do tipo "T" declarada na própria declaração de classe. Com isso em mente, você poderá adicionar outro método posteriormente, comoem todos os casos, T, E ou U, todos os identificadores do parâmetro type, você pode até ter mais de um parâmetro type que usa a sintaxe
em seu quarto ponto de vista, embora Sting seja efetivamente um subtipo de objeto, nas classes genéricas não existe tal relação,
List<String>
não é um subtipo,List<Object>
pois são dois tipos diferentes do ponto de vista do compilador, isso é melhor explicado nesta entrada do blogfonte
Teoria
String[]
pode ser lançado paraObject[]
mas
List<String>
não pode ser convertido paraList<Object>
.Prática
Para listas, é mais sutil que isso, porque em tempo de compilação o tipo de um parâmetro List passado para um método não é verificado. A definição do método também pode dizer
List<?>
- do ponto de vista do compilador, é equivalente. É por isso que o exemplo 2 do OP fornece erros de tempo de execução, não erros de compilação.Se você manipular um
List<Object>
parâmetro passado para um método com cuidado para não forçar uma verificação de tipo em nenhum elemento da lista, poderá definir seu método usando,List<Object>
mas de fato aceitar umList<String>
parâmetro do código de chamada.A. Portanto, esse código não fornecerá erros de compilação ou tempo de execução e funcionará (e talvez surpreendentemente?):
B. Este código dará um erro de tempo de execução:
C. Este código dará um erro de tempo de execução (
java.lang.ArrayStoreException: java.util.Collections$UnmodifiableRandomAccessList Object[]
):Em B, o parâmetro
set
não é digitadoList
em tempo de compilação: o compilador vê comoList<?>
. Há um erro de tempo de execução porque, em tempo de execução,set
torna-se o objeto real transmitidomain()
e esse é umList<String>
. AList<String>
não pode ser lançado paraList<Object>
.Em C, o parâmetro
set
requer umObject[]
. Não há erro de compilação nem erro de tempo de execução quando é chamado com umString[]
objeto como parâmetro. Isso porqueString[]
lança paraObject[]
. Mas o objeto real recebido portest()
permanece aString[]
, não mudou. Portanto, oparams
objeto também se torna aString[]
. E o elemento 0 de aString[]
não pode ser atribuído a aLong
!(Espero ter tudo aqui, se meu raciocínio estiver errado, tenho certeza de que a comunidade vai me dizer. ATUALIZADO: Atualizei o código no exemplo A para que ele realmente compile, enquanto ainda mostra o argumento.)
fonte
List<Object> cannot be applied to List<String>
. Você não pode passarArrayList<String>
para um método que esperaArrayList<Object>
.O problema 2 está OK, porque "System.out.println (set);" significa "System.out.println (set.toString ());" set é uma instância de List, portanto, o complier chamará List.toString ();
Problema 3: esses símbolos são os mesmos, mas você pode fornecer especificações diferentes. Por exemplo:
Problema 4: a coleção não permite covariância de parâmetro de tipo. Mas a matriz permite covariância.
fonte
Você está certo: String é um subconjunto de Objeto. Como String é mais "precisa" que Object, você deve convertê-la para usá-la como argumento para System.out.println ().
fonte