O tipo de referência que é formado assumindo o nome de uma declaração de tipo genérica sem uma lista de argumentos de tipo associada.
Um tipo de matriz cujo tipo de elemento é um tipo bruto.
Um statictipo não membro de um tipo bruto Rque não é herdado de uma superclasse ou superinterface de R.
Aqui está um exemplo para ilustrar:
publicclassMyType<E>{classInner{}staticclassNested{}publicstaticvoid main(String[] args){MyType mt;// warning: MyType is a raw typeMyType.Inner inn;// warning: MyType.Inner is a raw typeMyType.Nested nest;// no warning: not parameterized typeMyType<Object> mt1;// no warning: type parameter givenMyType<?> mt2;// no warning: type parameter given (wildcard OK!)}}
Aqui, MyType<E>é um tipo parametrizado ( JLS 4.5 ). É comum referir-se coloquialmente a esse tipo simplesmente como MyTypeabreviação, mas tecnicamente o nome é MyType<E>.
mttem um tipo bruto (e gera um aviso de compilação) pelo primeiro marcador na definição acima; inntambém tem um tipo bruto pelo terceiro marcador.
MyType.Nestednão é um tipo parametrizado, mesmo que seja um tipo de membro de um tipo parametrizado MyType<E>, porque é static.
mt1e mt2são declarados com parâmetros de tipo reais, portanto, não são tipos brutos.
O que há de tão especial nos tipos brutos?
Essencialmente, os tipos brutos se comportam exatamente como eram antes da introdução dos genéricos. Ou seja, o seguinte é totalmente legal em tempo de compilação.
List names =newArrayList();// warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE);// not a compilation error!
O código acima funciona muito bem, mas suponha que você também tenha o seguinte:
for(Object o : names){String name =(String) o;System.out.println(name);}// throws ClassCastException!// java.lang.Boolean cannot be cast to java.lang.String
Agora, enfrentamos problemas no tempo de execução, porque namescontém algo que não é instanceof String.
Presumivelmente, se você quiser namesconter apenas String, talvez ainda possa usar um tipo bruto e verificar manualmente todos os itens adde depois converter manualmente para Stringtodos os itens de names. Melhor ainda, NÃO é usar um tipo bruto e deixar o compilador fazer todo o trabalho para você , aproveitando o poder dos genéricos Java.
Como um tipo bruto é diferente de usar <Object>como parâmetros de tipo?
A seguir, uma citação do Effective Java 2nd Edition, Item 23: Não use tipos brutos no novo código :
Qual é a diferença entre o tipo bruto Liste o tipo parametrizado List<Object>? Em termos gerais, o primeiro optou pela verificação de tipo genérico, enquanto o último disse explicitamente ao compilador que é capaz de armazenar objetos de qualquer tipo. Enquanto você pode passar um List<String>a um parâmetro do tipo List, você não pode passá-lo para um parâmetro do tipo List<Object>. Existem regras de subtipagem para genéricos e List<String>é um subtipo do tipo bruto List, mas não do tipo parametrizado List<Object>. Como conseqüência, você perde a segurança de tipo se usar um tipo bruto List, mas não se usar um tipo parametrizadoList<Object> .
Para ilustrar o ponto, considere o método a seguir, que pega a List<Object>e acrescenta a new Object().
Se você tivesse declarado usar appendNewObjectum tipo bruto Listcomo parâmetro, isso seria compilado e, portanto, você perderia a segurança de tipo obtida dos genéricos.
Qual a diferença entre um tipo bruto e o uso <?>como parâmetro de tipo?
List<Object>, List<String>etc são todos List<?>, portanto, pode ser tentador dizer que eles são apenas o Listcontrário. No entanto, há uma grande diferença: como a List<E>define apenas add(E), você não pode adicionar qualquer objeto arbitrário a List<?>. Por outro lado, como o tipo bruto Listnão possui segurança de tipo, você pode addpraticamente qualquer coisa para a List.
Considere a seguinte variação do snippet anterior:
staticvoid appendNewObject(List<?> list){
list.add(newObject());// compilation error!}//...List<String> names =newArrayList<String>();
appendNewObject(names);// this part is fine!
O compilador fez um trabalho maravilhoso ao proteger você de violar potencialmente a invariância de tipo do List<?>! Se você tivesse declarado o parâmetro como o tipo bruto List list, o código seria compilado e você violaria o tipo invariante List<String> names.
Um tipo bruto é o apagamento desse tipo
Voltar para JLS 4.8:
É possível usar como um tipo o apagamento de um tipo parametrizado ou o apagamento de um tipo de matriz cujo tipo de elemento é um tipo parametrizado. Esse tipo é chamado de tipo bruto .
[...]
As superclasses (respectivamente, superinterfaces) de um tipo bruto são apagamentos das superclasses (superinterfaces) de qualquer uma das parametrizações do tipo genérico.
O tipo de construtor, método de instância ou não staticcampo de um tipo bruto Cque não é herdado de suas superclasses ou superinterfaces é o tipo bruto que corresponde ao apagamento de seu tipo na declaração genérica correspondente a C.
Em termos mais simples, quando um tipo bruto é usado, os construtores, métodos de instância e não staticcampos também são apagados .
O apagamento de tipo também mapeia a assinatura de um construtor ou método para uma assinatura que não possui tipos ou variáveis de tipo parametrizados. O apagamento de uma assinatura de construtor ou método sé uma assinatura que consiste no mesmo nome se no apagamento de todos os tipos de parâmetros formais fornecidos em s.
O tipo de retorno de um método e os parâmetros de tipo de um método ou construtor genérico também sofrem apagamento se a assinatura do método ou construtor for apagada.
O apagamento da assinatura de um método genérico não possui parâmetros de tipo.
O relatório de bug a seguir contém algumas reflexões de Maurizio Cimadamore, um desenvolvedor de compiladores, e Alex Buckley, um dos autores do JLS, sobre por que esse tipo de comportamento deve ocorrer: https://bugs.openjdk.java.net/browse / JDK-6400189 . (Em resumo, isso simplifica a especificação.)
Se não é seguro, por que é permitido usar um tipo bruto?
Aqui está outra citação do JLS 4.8:
O uso de tipos brutos é permitido apenas como uma concessão à compatibilidade do código legado. O uso de tipos brutos no código escrito após a introdução da genéricos na linguagem de programação Java é fortemente desencorajado. É possível que versões futuras da linguagem de programação Java não permitam o uso de tipos brutos.
O Java 2nd Edition eficaz também tem isso a acrescentar:
Como você não deve usar tipos brutos, por que os designers de idiomas os permitiram? Para fornecer compatibilidade.
A plataforma Java estava prestes a entrar em sua segunda década, quando os genéricos foram introduzidos, e havia uma enorme quantidade de código Java existente que não usava genéricos. Foi considerado crítico que todo esse código permaneça legal e interoperável com o novo código que usa genéricos. Tinha que ser legal passar instâncias de tipos parametrizados para métodos projetados para uso com tipos comuns e vice-versa. Esse requisito, conhecido como compatibilidade de migração , levou a decisão de oferecer suporte a tipos brutos.
Em resumo, os tipos brutos NUNCA devem ser usados no novo código. Você sempre deve usar tipos parametrizados .
Não há exceções?
Infelizmente, como os genéricos Java não são reificados, há duas exceções em que os tipos brutos devem ser usados no novo código:
Literais de classe, por exemplo List.class, nãoList<String>.class
instanceofoperando, por exemplo o instanceof Set, nãoo instanceof Set<String>
O que você quer dizer com "genéricos Java não são reificados"?
Carl G
7
Para a segunda exceção, a sintaxe o instanceof Set<?>também é permitida para evitar o tipo bruto (embora seja apenas superficial neste caso).
Paul Bellora
1
Os tipos brutos são muito úteis e reduzem o código padrão no caso de pesquisas JNDI para um bean que estende uma interface. Isso resolve a necessidade de gravar nbeans remotos para cada classe de implementação com código idêntico.
djmj
8
"Não reificado" é outra maneira de dizer que eles são apagados. O compilador sabe quais são os parâmetros genéricos, mas essas informações não são passadas para o bytecode gerado. O JLS requer que os literais de classe não tenham parâmetros de tipo.
Erick G. Hagstrom
2
@OldCurmudgeon Isso é interessante. Quero dizer oficialmente que não é nenhum , porque uma classe literal definida como justa TypeName.class, onde TypeNameé um identificador simples ( jls ). Falando hipoteticamente, acho que também poderia ser. Talvez como uma pista, List<String>.classseja a variante que o JLS chama especificamente de erro do compilador; portanto, se algum dia o adicionarem ao idioma, seria de esperar que esse seja o tipo que eles usam.
Radiodef 19/04
62
O que são tipos brutos em Java e por que geralmente ouço que eles não devem ser usados no novo código?
Tipos brutos são história antiga da linguagem Java. No começo, havia Collectionse eles Objectsnão tinham nada mais e nada menos. Todas as operações Collectionsnecessárias são convertidas Objectpara o tipo desejado.
List aList =newArrayList();String s ="Hello World!";
aList.add(s);String c =(String)aList.get(0);
Enquanto isso funcionava na maioria das vezes, erros aconteciam
List aNumberList =newArrayList();String one ="1";//Number one
aNumberList.add(one);Integer iOne =(Integer)aNumberList.get(0);//Insert ClassCastException here
As coleções antigas sem tipo não podiam impor a segurança de tipo; portanto, o programador precisava se lembrar do que armazenava em uma coleção.
Onde os genéricos foram inventados para contornar essa limitação, o desenvolvedor declararia o tipo armazenado uma vez e o compilador o faria.
List<String> aNumberList =newArrayList<String>();
aNumberList.add("one");Integer iOne = aNumberList.get(0);//Compile time errorString sOne = aNumberList.get(0);//works fine
Para comparação:
// Old style collections now known as raw typesList aList =newArrayList();//Could contain anything// New style collections with GenericsList<String> aList =newArrayList<String>();//Contains only Strings
Mais complexa a interface Comparável:
//raw, not type save can compare with Other classesclassMyCompareAbleimplementsCompareAble{int id;publicint compareTo(Object other){returnthis.id -((MyCompareAble)other).id;}}//GenericclassMyCompareAbleimplementsCompareAble<MyCompareAble>{int id;publicint compareTo(MyCompareAble other){returnthis.id - other.id;}}
Observe que é impossível implementar o CompareAble interface com compareTo(MyCompareAble)tipos brutos. Por que você não deve usá-los:
Qualquer Object arquivo armazenado em um Collectiondeve ser convertido para poder ser usado
O uso de genéricos permite verificações do tempo de compilação
Usar tipos brutos é o mesmo que armazenar cada valor como Object
O que o compilador faz: os genéricos são compatíveis com versões anteriores, eles usam as mesmas classes java que os tipos brutos. A mágica acontece principalmente em tempo de compilação.
List<String> someStrings =newArrayList<String>();
someStrings.add("one");String one = someStrings.get(0);
Será compilado como:
List someStrings =newArrayList();
someStrings.add("one");String one =(String)someStrings.get(0);
Este é o mesmo código que você escreveria se usasse os tipos brutos diretamente. Embora não tenha certeza do que acontece com a CompareAbleinterface, acho que ela cria duas compareTofunções, uma tendo umMyCompareAble e outra pegando uma Objecte passando para a primeira após a transmissão.
Quais são as alternativas para os tipos brutos: usar genéricos
Para criar um tipo parametrizado de Box<T>, você fornece um argumento de tipo real para o parâmetro de tipo formal T:
Box<Integer> intBox =newBox<>();
Se o argumento de tipo real for omitido, você cria um tipo bruto de Box<T>:
Box rawBox =newBox();
Portanto, Boxé o tipo bruto do tipo genéricoBox<T> . No entanto, uma classe ou tipo de interface não genérico não é um tipo bruto.
Os tipos brutos aparecem no código legado porque muitas classes de API (como as classes Collections) não eram genéricas antes do JDK 5.0. Ao usar tipos brutos, você basicamente obtém um comportamento pré-genérico - a Boxfornece Objects. Para compatibilidade com versões anteriores, é permitido atribuir um tipo parametrizado ao seu tipo bruto.
Box<String> stringBox =newBox<>();Box rawBox = stringBox;// OK
Mas se você atribuir um tipo bruto a um tipo parametrizado, receberá um aviso:
Box rawBox =newBox();// rawBox is a raw type of Box<T>Box<Integer> intBox = rawBox;// warning: unchecked conversion
Você também receberá um aviso se usar um tipo bruto para chamar métodos genéricos definidos no tipo genérico correspondente:
O aviso mostra que os tipos brutos ignoram as verificações de tipo genérico, adiando a captura de código não seguro para o tempo de execução. Portanto, você deve evitar o uso de tipos brutos.
A seção Eliminação de tipo tem mais informações sobre como o compilador Java usa tipos brutos.
Mensagens de erro não verificadas
Como mencionado anteriormente, ao misturar código legado com código genérico, você pode encontrar mensagens de aviso semelhantes à seguinte:
Nota: Example.java usa operações não verificadas ou inseguras.
Nota: Recompile com -Xlint: desmarcado para obter detalhes.
Isso pode acontecer ao usar uma API mais antiga que opera em tipos brutos, conforme mostrado no exemplo a seguir:
publicclassWarningDemo{publicstaticvoid main(String[] args){Box<Integer> bi;
bi = createBox();}staticBox createBox(){returnnewBox();}}
O termo "desmarcado" significa que o compilador não possui informações de tipo suficientes para executar todas as verificações de tipo necessárias para garantir a segurança do tipo. O aviso "desmarcado" está desabilitado, por padrão, embora o compilador dê uma dica. Para ver todos os avisos "desmarcados", recompile com -Xlint: desmarcado.
Recompilar o exemplo anterior com -Xlint: desmarcado revela as seguintes informações adicionais:
WarningDemo.java:4: warning:[unchecked] unchecked conversion
found :Box
required:Box<java.lang.Integer>
bi = createBox();^1 warning
Para desativar completamente os avisos não verificados, use o sinalizador -Xlint: -unchecked. A @SuppressWarnings("unchecked")anotação suprime avisos não verificados. Se você não estiver familiarizado com o@SuppressWarnings sintaxe, consulte Anotações.
Um tipo "bruto" em Java é uma classe que não é genérica e lida com objetos "brutos", em vez de parâmetros de tipo genérico com segurança de tipo.
Por exemplo, antes que os genéricos Java estivessem disponíveis, você usaria uma classe de coleção como esta:
LinkedList list =newLinkedList();
list.add(newMyObject());MyObject myObject =(MyObject)list.get(0);
Quando você adiciona seu objeto à lista, ele não se importa com o tipo de objeto e, quando o obtém da lista, é necessário convertê-lo explicitamente no tipo que você espera.
Usando genéricos, você remove o fator "desconhecido", porque você deve especificar explicitamente quais tipos de objetos podem entrar na lista:
LinkedList<MyObject> list =newLinkedList<MyObject>();
list.add(newMyObject());MyObject myObject = list.get(0);
Observe que, com os genéricos, você não precisa converter o objeto proveniente da chamada get, a coleção é predefinida para funcionar apenas com MyObject. Esse fato é o principal fator determinante dos genéricos. Ele altera uma fonte de erros de tempo de execução para algo que pode ser verificado em tempo de compilação.
Mais especificamente, um tipo bruto é o que você obtém quando simplesmente omite os parâmetros de tipo para um tipo genérico. Os tipos brutos foram realmente apenas um recurso de compatibilidade com versões anteriores e estão potencialmente sujeitos a remoção. Você pode obter um comportamento semelhante usando? parâmetros curinga.
John Flatness
@zerocrates: semelhante, mas diferente! O uso ?ainda oferece segurança de tipo. Eu cobri isso na minha resposta.
polygenelubricants
19
privatestaticList<String> list =newArrayList<String>();
Você deve especificar o parâmetro de tipo.
O aviso informa que os tipos definidos para oferecer suporte aos genéricos devem ser parametrizados, em vez de usar sua forma bruta.
Listé definido para genéricos de apoio: public class List<E>. Isso permite muitas operações com segurança de tipo, que são verificadas em tempo de compilação.
Agora substituído por inferência de diamante em Java 7 - #private static List<String> list = new ArrayList<>();
Ian Campbell
14
O que é um tipo bruto e por que geralmente ouço que eles não devem ser usados no novo código?
Um "tipo bruto" é o uso de uma classe genérica sem especificar um ou mais argumentos de tipo para seu (s) tipo (s) parametrizado (s), por exemplo, usando em Listvez deList<String> . Quando os genéricos foram introduzidos no Java, várias classes foram atualizadas para usar os genéricos. O uso dessas classes como um "tipo bruto" (sem especificar um argumento de tipo) permitiu que o código legado ainda fosse compilado.
"Tipos brutos" são usados para compatibilidade com versões anteriores. Seu uso no novo código não é recomendado porque o uso da classe genérica com um argumento de tipo permite uma digitação mais forte, o que por sua vez pode melhorar a compreensibilidade do código e levar à detecção de possíveis problemas anteriormente.
Qual é a alternativa se não podemos usar tipos brutos e como é melhor?
A alternativa preferida é usar classes genéricas como pretendido - com um argumento de tipo adequado (por exemplo List<String>). Isso permite que o programador especifique tipos mais especificamente, transmite mais significado aos futuros mantenedores sobre o uso pretendido de uma variável ou estrutura de dados e permite que o compilador imponha melhor segurança de tipo. Essas vantagens juntas podem melhorar a qualidade do código e ajudar a impedir a introdução de alguns erros de codificação.
Por exemplo, para um método em que o programador deseja garantir que uma variável da lista chamada 'names' contenha apenas Strings:
List<String> names =newArrayList<String>();
names.add("John");// OK
names.add(newInteger(1));// compile error
Ah, estou tão tentado a copiar polygenelubricantsas referências "tipo bruto" de stackoverflow.com/questions/2770111/… em minha própria resposta, mas suponho que as deixarei para uso em sua própria resposta.
Bert F
1
sim, eu tenho essencialmente copiado e colado esse segmento em todos os lugares em que as pessoas usam tipos brutos no stackoverflow e, finalmente, decidi ter apenas uma pergunta para referir a partir de agora. Espero que seja uma boa contribuição para a comunidade.
polygenelubricants
1
@polygenelubricants notei - nós batemos algumas das mesmas perguntas :-)
Bert F
1
@ ha9u63ar: De fato. Em geral, respostas concisas e simples são pelo menos tão boas quanto as longas e aceitas.
displayName
O que é "syping mais forte"?
precisa saber é o seguinte
12
O compilador deseja que você escreva isso:
privatestaticList<String> list =newArrayList<String>();
porque, caso contrário, você pode adicionar qualquer tipo que desejar list, tornando a instanciação new ArrayList<String>()inútil. Os genéricos Java são apenas um recurso em tempo de compilação; portanto, um objeto criado com new ArrayList<String>()prazer aceitará elementos Integerou JFramese for atribuído a uma referência do "tipo bruto" List- o objeto em si não sabe nada sobre os tipos que deve conter, apenas o compilador.
ArrayList<String> arré uma ArrayListvariável de referência com o tipo Stringque se refere a um ArralyListObjeto do Tipo String. Isso significa que ele pode conter apenas o tipo String.
É estrito, e Stringnão um tipo bruto, portanto, nunca emitirá um aviso.
arr.add("hello");// alone statement will compile successfully and no warning.
arr.add(23);//prone to compile time error.//error: no suitable method found for add(int)
Caso 2
Nesse caso, ArrayList<String> arré um tipo estrito, mas seu Objeto new ArrayList();é um tipo bruto.
arr.add("hello");//alone this compile but raise the warning.
arr.add(23);//again prone to compile time error.//error: no suitable method found for add(int)
aqui arré um tipo estrito. Portanto, isso gerará um erro de tempo de compilação ao adicionar um integer.
Aviso : - Um Rawobjeto de tipo é referenciado a um Stricttipo de variável referenciada ArrayList.
Caso 3
Nesse caso, ArrayList arré um tipo bruto, mas seu Objeto new ArrayList<String>();é um tipo Estrito.
arr.add("hello");
arr.add(23);//compiles fine but raise the warning.
Ele adicionará qualquer tipo de objeto a ele, porque arré um tipo bruto.
Aviso : - Um StrictObjeto de Tipo é referenciado a uma rawVariável referenciada por tipo.
Um tipo bruto é a falta de um parâmetro de tipo ao usar um tipo genérico.
O tipo bruto não deve ser usado porque pode causar erros de tempo de execução, como inserir um doubleno que deveria ser um Setdos ints.
Set set =newHashSet();
set.add(3.45);//ok
Ao recuperar as coisas do Set, você não sabe o que está saindo. Vamos supor que você espera que seja tudo ints, para o qual está lançando Integer; exceção em tempo de execução quando odouble 3.45 aparecer.
Com um parâmetro de tipo adicionado ao seu Set, você receberá um erro de compilação de uma só vez. Esse erro de preferência permite que você corrija o problema antes que algo exploda durante o tempo de execução (economizando tempo e esforço).
Set<Integer> set =newHashSet<Integer>();
set.add(3.45);//NOT ok.
Como foi mencionado na resposta aceita, você perde todo o suporte a genéricos no código do tipo bruto. Todo parâmetro de tipo é convertido em sua eliminação (que no exemplo acima é apenas Object).
O que está dizendo é que você listé um Listobjeto não especificado. Ou seja, o Java não sabe que tipo de objetos estão na lista. Então, quando você quiser iterar a lista, precisará converter todos os elementos, para poder acessar as propriedades desse elemento (neste caso, String).
Em geral, é uma idéia melhor parametrizar as coleções, para que você não tenha problemas de conversão, você poderá adicionar apenas elementos do tipo parametrizado e seu editor oferecerá os métodos apropriados a serem selecionados.
privatestaticList<String> list =newArrayList<String>();
Tipos brutos referem-se ao uso de um tipo genérico sem especificar um parâmetro de tipo.
Por exemplo ,
Uma lista é um tipo bruto, enquanto List<String>é um tipo parametrizado.
Quando os genéricos foram introduzidos no JDK 1.5, os tipos brutos foram retidos apenas para manter a compatibilidade com versões anteriores do Java. Embora o uso de tipos brutos ainda seja possível,
Eles devem ser evitados :
Eles geralmente exigem elencos
Eles não são do tipo seguro e alguns tipos importantes de erros aparecerão apenas em tempo de execução
Eles são menos expressiva, e não fazer auto-documento da mesma forma que tipos parametrizados
Exemplo
import java.util.*;publicfinalclassAvoidRawTypes{void withRawType(){//Raw List doesn't self-document, //doesn't state explicitly what it can containList stars =Arrays.asList("Arcturus","Vega","Altair");Iterator iter = stars.iterator();while(iter.hasNext()){String star =(String) iter.next();//cast needed
log(star);}}void withParameterizedType(){List<String> stars =Arrays.asList("Spica","Regulus","Antares");for(String star: stars){
log(star);}}privatevoid log(Object message){System.out.println(Objects.toString(message));}}
Encontrei esta página depois de fazer alguns exemplos de exercícios e ter exatamente a mesma perplexidade.
============== Eu fui deste código conforme fornecido pela amostra ===============
publicstaticvoid main(String[] args)throwsIOException{Map wordMap =newHashMap();if(args.length >0){for(int i =0; i < args.length; i++){
countWord(wordMap, args[i]);}}else{
getWordFrequency(System.in, wordMap);}for(Iterator i = wordMap.entrySet().iterator(); i.hasNext();){Map.Entry entry =(Map.Entry) i.next();System.out.println(entry.getKey()+" :\t"+ entry.getValue());}
====================== Para este código ========================
publicstaticvoid main(String[] args)throwsIOException{// replace with TreeMap to get them sorted by nameMap<String,Integer> wordMap =newHashMap<String,Integer>();if(args.length >0){for(int i =0; i < args.length; i++){
countWord(wordMap, args[i]);}}else{
getWordFrequency(System.in, wordMap);}for(Iterator<Entry<String,Integer>> i = wordMap.entrySet().iterator(); i.hasNext();){Entry<String,Integer> entry = i.next();System.out.println(entry.getKey()+" :\t"+ entry.getValue());}}
Os tipos brutos são bons quando expressam o que você deseja expressar.
Por exemplo, uma função de desserialização pode retornar a List, mas não sabe o tipo de elemento da lista. Assim Listé o tipo de retorno apropriado aqui.
Respostas:
O que é um tipo bruto?
A Java Language Specification define um tipo bruto da seguinte maneira:
Tipos brutos do JLS 4.8
Aqui está um exemplo para ilustrar:
Aqui,
MyType<E>
é um tipo parametrizado ( JLS 4.5 ). É comum referir-se coloquialmente a esse tipo simplesmente comoMyType
abreviação, mas tecnicamente o nome éMyType<E>
.mt
tem um tipo bruto (e gera um aviso de compilação) pelo primeiro marcador na definição acima;inn
também tem um tipo bruto pelo terceiro marcador.MyType.Nested
não é um tipo parametrizado, mesmo que seja um tipo de membro de um tipo parametrizadoMyType<E>
, porque éstatic
.mt1
emt2
são declarados com parâmetros de tipo reais, portanto, não são tipos brutos.O que há de tão especial nos tipos brutos?
Essencialmente, os tipos brutos se comportam exatamente como eram antes da introdução dos genéricos. Ou seja, o seguinte é totalmente legal em tempo de compilação.
O código acima funciona muito bem, mas suponha que você também tenha o seguinte:
Agora, enfrentamos problemas no tempo de execução, porque
names
contém algo que não éinstanceof String
.Presumivelmente, se você quiser
names
conter apenasString
, talvez ainda possa usar um tipo bruto e verificar manualmente todos os itensadd
e depois converter manualmente paraString
todos os itens denames
. Melhor ainda, NÃO é usar um tipo bruto e deixar o compilador fazer todo o trabalho para você , aproveitando o poder dos genéricos Java.Claro, se você NÃO quer
names
para permitir que umBoolean
, então você pode declará-lo comoList<Object> names
, e o código acima seria compilar.Veja também
Como um tipo bruto é diferente de usar
<Object>
como parâmetros de tipo?A seguir, uma citação do Effective Java 2nd Edition, Item 23: Não use tipos brutos no novo código :
Para ilustrar o ponto, considere o método a seguir, que pega a
List<Object>
e acrescenta anew Object()
.Os genéricos em Java são invariantes. A
List<String>
não é aList<Object>
, portanto, o seguinte geraria um aviso do compilador:Se você tivesse declarado usar
appendNewObject
um tipo brutoList
como parâmetro, isso seria compilado e, portanto, você perderia a segurança de tipo obtida dos genéricos.Veja também
<E extends Number>
e<Number>
?Qual a diferença entre um tipo bruto e o uso
<?>
como parâmetro de tipo?List<Object>
,List<String>
etc são todosList<?>
, portanto, pode ser tentador dizer que eles são apenas oList
contrário. No entanto, há uma grande diferença: como aList<E>
define apenasadd(E)
, você não pode adicionar qualquer objeto arbitrário aList<?>
. Por outro lado, como o tipo brutoList
não possui segurança de tipo, você podeadd
praticamente qualquer coisa para aList
.Considere a seguinte variação do snippet anterior:
O compilador fez um trabalho maravilhoso ao proteger você de violar potencialmente a invariância de tipo do
List<?>
! Se você tivesse declarado o parâmetro como o tipo brutoList list
, o código seria compilado e você violaria o tipo invarianteList<String> names
.Um tipo bruto é o apagamento desse tipo
Voltar para JLS 4.8:
Em termos mais simples, quando um tipo bruto é usado, os construtores, métodos de instância e não
static
campos também são apagados .Veja o seguinte exemplo:
Quando usamos o cru
MyType
, ele tambémgetNames
é apagado, para que ele retorne um cruList
!O JLS 4.6 continua explicando o seguinte:
O relatório de bug a seguir contém algumas reflexões de Maurizio Cimadamore, um desenvolvedor de compiladores, e Alex Buckley, um dos autores do JLS, sobre por que esse tipo de comportamento deve ocorrer: https://bugs.openjdk.java.net/browse / JDK-6400189 . (Em resumo, isso simplifica a especificação.)
Se não é seguro, por que é permitido usar um tipo bruto?
Aqui está outra citação do JLS 4.8:
O Java 2nd Edition eficaz também tem isso a acrescentar:
Em resumo, os tipos brutos NUNCA devem ser usados no novo código. Você sempre deve usar tipos parametrizados .
Não há exceções?
Infelizmente, como os genéricos Java não são reificados, há duas exceções em que os tipos brutos devem ser usados no novo código:
List.class
, nãoList<String>.class
instanceof
operando, por exemploo instanceof Set
, nãoo instanceof Set<String>
Veja também
Collection<String>.class
ilegal?fonte
o instanceof Set<?>
também é permitida para evitar o tipo bruto (embora seja apenas superficial neste caso).n
beans remotos para cada classe de implementação com código idêntico.TypeName.class
, ondeTypeName
é um identificador simples ( jls ). Falando hipoteticamente, acho que também poderia ser. Talvez como uma pista,List<String>.class
seja a variante que o JLS chama especificamente de erro do compilador; portanto, se algum dia o adicionarem ao idioma, seria de esperar que esse seja o tipo que eles usam.Tipos brutos são história antiga da linguagem Java. No começo, havia
Collections
e elesObjects
não tinham nada mais e nada menos. Todas as operaçõesCollections
necessárias são convertidasObject
para o tipo desejado.Enquanto isso funcionava na maioria das vezes, erros aconteciam
As coleções antigas sem tipo não podiam impor a segurança de tipo; portanto, o programador precisava se lembrar do que armazenava em uma coleção.
Onde os genéricos foram inventados para contornar essa limitação, o desenvolvedor declararia o tipo armazenado uma vez e o compilador o faria.
Para comparação:
Mais complexa a interface Comparável:
Observe que é impossível implementar o
CompareAble
interface comcompareTo(MyCompareAble)
tipos brutos. Por que você não deve usá-los:Object
arquivo armazenado em umCollection
deve ser convertido para poder ser usadoObject
O que o compilador faz: os genéricos são compatíveis com versões anteriores, eles usam as mesmas classes java que os tipos brutos. A mágica acontece principalmente em tempo de compilação.
Será compilado como:
Este é o mesmo código que você escreveria se usasse os tipos brutos diretamente. Embora não tenha certeza do que acontece com a
CompareAble
interface, acho que ela cria duascompareTo
funções, uma tendo umMyCompareAble
e outra pegando umaObject
e passando para a primeira após a transmissão.Quais são as alternativas para os tipos brutos: usar genéricos
fonte
Um tipo bruto é o nome de uma classe ou interface genérica sem nenhum argumento de tipo. Por exemplo, dada a classe Box genérica:
Para criar um tipo parametrizado de
Box<T>
, você fornece um argumento de tipo real para o parâmetro de tipo formalT
:Se o argumento de tipo real for omitido, você cria um tipo bruto de
Box<T>
:Portanto,
Box
é o tipo bruto do tipo genéricoBox<T>
. No entanto, uma classe ou tipo de interface não genérico não é um tipo bruto.Os tipos brutos aparecem no código legado porque muitas classes de API (como as classes Collections) não eram genéricas antes do JDK 5.0. Ao usar tipos brutos, você basicamente obtém um comportamento pré-genérico - a
Box
forneceObject
s. Para compatibilidade com versões anteriores, é permitido atribuir um tipo parametrizado ao seu tipo bruto.Mas se você atribuir um tipo bruto a um tipo parametrizado, receberá um aviso:
Você também receberá um aviso se usar um tipo bruto para chamar métodos genéricos definidos no tipo genérico correspondente:
O aviso mostra que os tipos brutos ignoram as verificações de tipo genérico, adiando a captura de código não seguro para o tempo de execução. Portanto, você deve evitar o uso de tipos brutos.
A seção Eliminação de tipo tem mais informações sobre como o compilador Java usa tipos brutos.
Mensagens de erro não verificadas
Como mencionado anteriormente, ao misturar código legado com código genérico, você pode encontrar mensagens de aviso semelhantes à seguinte:
Isso pode acontecer ao usar uma API mais antiga que opera em tipos brutos, conforme mostrado no exemplo a seguir:
O termo "desmarcado" significa que o compilador não possui informações de tipo suficientes para executar todas as verificações de tipo necessárias para garantir a segurança do tipo. O aviso "desmarcado" está desabilitado, por padrão, embora o compilador dê uma dica. Para ver todos os avisos "desmarcados", recompile com -Xlint: desmarcado.
Recompilar o exemplo anterior com -Xlint: desmarcado revela as seguintes informações adicionais:
Para desativar completamente os avisos não verificados, use o sinalizador -Xlint: -unchecked. A
@SuppressWarnings("unchecked")
anotação suprime avisos não verificados. Se você não estiver familiarizado com o@SuppressWarnings
sintaxe, consulte Anotações.Fonte original: Java Tutorials
fonte
Um tipo "bruto" em Java é uma classe que não é genérica e lida com objetos "brutos", em vez de parâmetros de tipo genérico com segurança de tipo.
Por exemplo, antes que os genéricos Java estivessem disponíveis, você usaria uma classe de coleção como esta:
Quando você adiciona seu objeto à lista, ele não se importa com o tipo de objeto e, quando o obtém da lista, é necessário convertê-lo explicitamente no tipo que você espera.
Usando genéricos, você remove o fator "desconhecido", porque você deve especificar explicitamente quais tipos de objetos podem entrar na lista:
Observe que, com os genéricos, você não precisa converter o objeto proveniente da chamada get, a coleção é predefinida para funcionar apenas com MyObject. Esse fato é o principal fator determinante dos genéricos. Ele altera uma fonte de erros de tempo de execução para algo que pode ser verificado em tempo de compilação.
fonte
?
ainda oferece segurança de tipo. Eu cobri isso na minha resposta.Você deve especificar o parâmetro de tipo.
O aviso informa que os tipos definidos para oferecer suporte aos genéricos devem ser parametrizados, em vez de usar sua forma bruta.
List
é definido para genéricos de apoio:public class List<E>
. Isso permite muitas operações com segurança de tipo, que são verificadas em tempo de compilação.fonte
private static List<String> list = new ArrayList<>();
O que é um tipo bruto e por que geralmente ouço que eles não devem ser usados no novo código?
Um "tipo bruto" é o uso de uma classe genérica sem especificar um ou mais argumentos de tipo para seu (s) tipo (s) parametrizado (s), por exemplo, usando em
List
vez deList<String>
. Quando os genéricos foram introduzidos no Java, várias classes foram atualizadas para usar os genéricos. O uso dessas classes como um "tipo bruto" (sem especificar um argumento de tipo) permitiu que o código legado ainda fosse compilado."Tipos brutos" são usados para compatibilidade com versões anteriores. Seu uso no novo código não é recomendado porque o uso da classe genérica com um argumento de tipo permite uma digitação mais forte, o que por sua vez pode melhorar a compreensibilidade do código e levar à detecção de possíveis problemas anteriormente.
Qual é a alternativa se não podemos usar tipos brutos e como é melhor?
A alternativa preferida é usar classes genéricas como pretendido - com um argumento de tipo adequado (por exemplo
List<String>
). Isso permite que o programador especifique tipos mais especificamente, transmite mais significado aos futuros mantenedores sobre o uso pretendido de uma variável ou estrutura de dados e permite que o compilador imponha melhor segurança de tipo. Essas vantagens juntas podem melhorar a qualidade do código e ajudar a impedir a introdução de alguns erros de codificação.Por exemplo, para um método em que o programador deseja garantir que uma variável da lista chamada 'names' contenha apenas Strings:
fonte
polygenelubricants
as referências "tipo bruto" de stackoverflow.com/questions/2770111/… em minha própria resposta, mas suponho que as deixarei para uso em sua própria resposta.O compilador deseja que você escreva isso:
porque, caso contrário, você pode adicionar qualquer tipo que desejar
list
, tornando a instanciaçãonew ArrayList<String>()
inútil. Os genéricos Java são apenas um recurso em tempo de compilação; portanto, um objeto criado comnew ArrayList<String>()
prazer aceitará elementosInteger
ouJFrame
se for atribuído a uma referência do "tipo bruto"List
- o objeto em si não sabe nada sobre os tipos que deve conter, apenas o compilador.fonte
Aqui estou considerando vários casos através dos quais você pode esclarecer o conceito
Caso 1
ArrayList<String> arr
é umaArrayList
variável de referência com o tipoString
que se refere a umArralyList
Objeto do TipoString
. Isso significa que ele pode conter apenas o tipo String.É estrito, e
String
não um tipo bruto, portanto, nunca emitirá um aviso.Caso 2
Nesse caso,
ArrayList<String> arr
é um tipo estrito, mas seu Objetonew ArrayList();
é um tipo bruto.aqui
arr
é um tipo estrito. Portanto, isso gerará um erro de tempo de compilação ao adicionar uminteger
.Caso 3
Nesse caso,
ArrayList arr
é um tipo bruto, mas seu Objetonew ArrayList<String>();
é um tipo Estrito.Ele adicionará qualquer tipo de objeto a ele, porque
arr
é um tipo bruto.fonte
Um tipo bruto é a falta de um parâmetro de tipo ao usar um tipo genérico.
O tipo bruto não deve ser usado porque pode causar erros de tempo de execução, como inserir um
double
no que deveria ser umSet
dosint
s.Ao recuperar as coisas do
Set
, você não sabe o que está saindo. Vamos supor que você espera que seja tudoint
s, para o qual está lançandoInteger
; exceção em tempo de execução quando odouble
3.45 aparecer.Com um parâmetro de tipo adicionado ao seu
Set
, você receberá um erro de compilação de uma só vez. Esse erro de preferência permite que você corrija o problema antes que algo exploda durante o tempo de execução (economizando tempo e esforço).fonte
Aqui está outro caso em que tipos brutos o morderão:
Como foi mencionado na resposta aceita, você perde todo o suporte a genéricos no código do tipo bruto. Todo parâmetro de tipo é convertido em sua eliminação (que no exemplo acima é apenas
Object
).fonte
O que está dizendo é que você
list
é umList
objeto não especificado. Ou seja, o Java não sabe que tipo de objetos estão na lista. Então, quando você quiser iterar a lista, precisará converter todos os elementos, para poder acessar as propriedades desse elemento (neste caso, String).Em geral, é uma idéia melhor parametrizar as coleções, para que você não tenha problemas de conversão, você poderá adicionar apenas elementos do tipo parametrizado e seu editor oferecerá os métodos apropriados a serem selecionados.
fonte
página do tutorial .
Um tipo bruto é o nome de uma classe ou interface genérica sem nenhum argumento de tipo. Por exemplo, dada a classe Box genérica:
Para criar um tipo parametrizado de Box, você fornece um argumento de tipo real para o parâmetro de tipo formal T:
Se o argumento de tipo real for omitido, você cria um tipo bruto de Box:
fonte
Evite tipos brutos
Por exemplo ,
Uma lista é um tipo bruto, enquanto
List<String>
é um tipo parametrizado.Quando os genéricos foram introduzidos no JDK 1.5, os tipos brutos foram retidos apenas para manter a compatibilidade com versões anteriores do Java. Embora o uso de tipos brutos ainda seja possível,
Eles devem ser evitados :
Eles são menos expressiva, e não fazer auto-documento da mesma forma que tipos parametrizados Exemplo
Para referência : https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html
fonte
Encontrei esta página depois de fazer alguns exemplos de exercícios e ter exatamente a mesma perplexidade.
============== Eu fui deste código conforme fornecido pela amostra ===============
====================== Para este código ========================
==================================================== =============================
Pode ser mais seguro, mas levou 4 horas para desmembrar a filosofia ...
fonte
Os tipos brutos são bons quando expressam o que você deseja expressar.
Por exemplo, uma função de desserialização pode retornar a
List
, mas não sabe o tipo de elemento da lista. AssimList
é o tipo de retorno apropriado aqui.fonte