les didacticiels java utilisent toujours la JComboBox qui provoque cet avertissement. Quelle version de la zone de liste déroulante ne provoquera pas cet avertissement? docs.oracle.com/javase/tutorial/uiswing/components/…
SuperStar
1
Notez que la raison pour laquelle les types bruts existent est la rétrocompatibilité avec Java 1.4 et les versions antérieures, qui n'avaient pas du tout de génériques.
Jesper
Réponses:
745
Qu'est-ce qu'un type brut?
La spécification du langage Java définit un type brut comme suit:
Type de référence formé en prenant le nom d'une déclaration de type générique sans liste d'arguments de type associée.
Un type de tableau dont le type d'élément est un type brut.
Un statictype non membre d'un type brut Rqui n'est pas hérité d'une superclasse ou d'une superinterface de R.
Voici un exemple pour illustrer:
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!)}}
Voici MyType<E>un type paramétré ( JLS 4.5 ). Il est courant de se référer familièrement à ce type simplement MyTypepour faire court, mais techniquement le nom est MyType<E>.
mta un type brut (et génère un avertissement de compilation) par le premier point de la définition ci-dessus; inna également un type brut par le troisième point.
MyType.Nestedn'est pas un type paramétré, même s'il s'agit d'un type membre d'un type paramétré MyType<E>, car il l'est static.
mt1et mt2sont tous deux déclarés avec des paramètres de type réels, donc ce ne sont pas des types bruts.
Quelle est la particularité des types bruts?
Essentiellement, les types bruts se comportent comme ils l'étaient avant l'introduction des génériques. Autrement dit, ce qui suit est entièrement légal au moment de la compilation.
List names =newArrayList();// warning: raw type!
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE);// not a compilation error!
Le code ci-dessus fonctionne très bien, mais supposez que vous disposiez également des éléments suivants:
for(Object o : names){String name =(String) o;System.out.println(name);}// throws ClassCastException!// java.lang.Boolean cannot be cast to java.lang.String
Maintenant, nous rencontrons des problèmes au moment de l'exécution, car namescontient quelque chose qui n'est pas un instanceof String.
On peut supposer que si vous voulez namescontenir seulement String, vous pourriez peut - être utiliser encore un type cru et vérifier manuellement chaqueadd vous, puis jeter manuellement à Stringchaque élément de names. Encore mieux , il ne faut PAS utiliser un type brut et laisser le compilateur faire tout le travail pour vous , en exploitant la puissance des génériques Java.
En quoi un type brut est-il différent de l'utilisation <Object>comme paramètres de type?
Ce qui suit est une citation de Effective Java 2nd Edition, article 23: N'utilisez pas de types bruts dans le nouveau code :
Quelle est la différence entre le type brut Listet le type paramétré List<Object>? En gros, le premier a désactivé la vérification de type générique, tandis que le second a explicitement déclaré au compilateur qu'il était capable de contenir des objets de tout type. Bien que vous puissiez passer un List<String>à un paramètre de type List, vous ne pouvez pas le passer à un paramètre de type List<Object>. Il existe des règles de sous-typage pour les génériques, et il List<String>s'agit d'un sous-type du type brut List, mais pas du type paramétré List<Object>. Par conséquent, vous perdez la sécurité du type si vous utilisez un type brut comme List, mais pas si vous utilisez un type paramétré commeList<Object> .
Pour illustrer ce point, considérons la méthode suivante qui prend a List<Object>et ajoute a new Object().
Si vous aviez déclaré appendNewObjectprendre un type brut Listcomme paramètre, cela se compilerait et vous perdriez donc la sécurité de type que vous obtenez des génériques.
En quoi un type brut est-il différent de l'utilisation <?>comme paramètre de type?
List<Object>, List<String>, Etc sont tous List<?>, donc il peut être tentant de simplement dire qu'ils sont juste à la Listplace. Cependant, il y a une différence majeure: puisque a List<E>définit uniquement add(E), vous ne pouvez pas ajouter n'importe quel objet arbitraire à a List<?>. D'un autre côté, puisque le type brut Listn'a pas de sécurité de type, vous pouvez à addpeu près n'importe quoi pour a List.
Considérez la variante suivante de l'extrait précédent:
staticvoid appendNewObject(List<?> list){
list.add(newObject());// compilation error!}//...List<String> names =newArrayList<String>();
appendNewObject(names);// this part is fine!
Le compilateur a fait un excellent travail pour vous protéger contre la violation potentielle de l'invariance de type du List<?>! Si vous aviez déclaré le paramètre comme type brut List list, le code se compilerait et vous violeriez l'invariant de type List<String> names.
Un type brut est l'effacement de ce type
Retour à JLS 4.8:
Il est possible d'utiliser comme type l'effacement d'un type paramétré ou l'effacement d'un type tableau dont le type d'élément est un type paramétré. Un tel type est appelé type brut .
[...]
Les superclasses (respectivement, superinterfaces) d'un type brut sont les effacements des superclasses (superinterfaces) de n'importe laquelle des paramétrisations du type générique.
Le type d'un constructeur, d'une méthode d'instance ou d'un non- staticchamp d'un type brut Cqui n'est pas hérité de ses superclasses ou superinterfaces est le type brut qui correspond à l'effacement de son type dans la déclaration générique correspondant à C.
En termes plus simples, lorsqu'un type brut est utilisé, les constructeurs, les méthodes d'instance et les non- staticchamps sont également effacés .
Lorsque nous utilisons le brut MyType, il getNamesest également effacé, de sorte qu'il renvoie un brut List!
JLS 4.6 continue d'expliquer les éléments suivants:
L'effacement de type mappe également la signature d'un constructeur ou d'une méthode à une signature qui n'a pas de types ou de variables de type paramétrés. L'effacement d'une signature de constructeur ou de méthode sest une signature composée du même nom set des effacements de tous les types de paramètres formels indiqués dans s.
Le type de retour d'une méthode et les paramètres de type d'une méthode générique ou d'un constructeur subissent également un effacement si la signature de la méthode ou du constructeur est effacée.
L'effacement de la signature d'une méthode générique n'a pas de paramètres de type.
Le rapport de bogue suivant contient quelques réflexions de Maurizio Cimadamore, développeur de compilateur, et d'Alex Buckley, l'un des auteurs du JLS, sur les raisons pour lesquelles ce type de comportement devrait se produire: https://bugs.openjdk.java.net/browse / JDK-6400189 . (En bref, cela rend la spécification plus simple.)
Si ce n'est pas sûr, pourquoi est-il autorisé à utiliser un type brut?
Voici une autre citation de JLS 4.8:
L'utilisation de types bruts n'est autorisée qu'à titre de concession à la compatibilité du code hérité. L'utilisation de types bruts dans du code écrit après l'introduction de la généricité dans le langage de programmation Java est fortement déconseillée. Il est possible que les futures versions du langage de programmation Java interdisent l'utilisation de types bruts.
Efficace Java 2nd Edition a également ceci à ajouter:
Étant donné que vous ne devez pas utiliser de types bruts, pourquoi les concepteurs de langage les ont-ils autorisés? Pour assurer la compatibilité.
La plate-forme Java était sur le point d'entrer dans sa deuxième décennie avec l'introduction des génériques, et il existait une énorme quantité de code Java qui n'utilisait pas de génériques. Il a été jugé essentiel que tout ce code reste légal et interopérable avec un nouveau code qui utilise des génériques. Il devait être légal de transmettre des instances de types paramétrés à des méthodes conçues pour être utilisées avec des types ordinaires, et vice versa. Cette exigence, connue sous le nom de compatibilité de migration , a conduit à prendre la décision de prendre en charge les types bruts.
En résumé, les types bruts ne doivent JAMAIS être utilisés dans un nouveau code. Vous devez toujours utiliser des types paramétrés .
N'y a-t-il pas d'exceptions?
Malheureusement, comme les génériques Java ne sont pas réifiés, il existe deux exceptions où les types bruts doivent être utilisés dans le nouveau code:
Littéraux de classe, par exemple List.class, nonList<String>.class
instanceofopérande, par exemple o instanceof Set, paso instanceof Set<String>
Que voulez-vous dire par "les génériques Java ne sont pas réifiés"?
Carl G
7
Pour la deuxième exception, la syntaxe o instanceof Set<?>est également autorisée pour éviter le type brut (bien que ce ne soit que superficiel dans ce cas).
Paul Bellora
1
Les types bruts sont très utiles et réduisent le code passe-partout en cas de recherches JNDI pour un bean qui étend une interface. Cela résout le besoin d'écrire ndes beans distants pour chaque classe d'implémentation avec un code identique.
djmj
8
«Non réifié» est une autre façon de dire qu'ils sont effacés. Le compilateur connaît les paramètres génériques, mais ces informations ne sont pas transmises au bytecode généré. Le JLS requiert que les littéraux de classe n'aient pas de paramètres de type.
Erick G.Hagstrom
2
@OldCurmudgeon C'est intéressant. Je veux dire officiellement que ce n'est ni l'un ni l' autre , car un littéral de classe défini comme juste TypeName.class, où TypeNameest un identificateur simple ( jls ). Parlant hypothétiquement, je suppose que ça pourrait vraiment être l'un ou l'autre. Peut-être comme indice, List<String>.classest la variante que le JLS appelle spécifiquement une erreur de compilation, donc s'ils l'ajoutent jamais au langage, je m'attends à ce que ce soit celui qu'ils utilisent.
Radiodef
62
Quels sont les types bruts en Java et pourquoi j'entends souvent dire qu'ils ne devraient pas être utilisés dans le nouveau code?
Les types bruts sont une histoire ancienne du langage Java. Au début, il y en avait Collectionset ils Objectsne tenaient ni plus ni moins. Chaque opération sur Collectionsles moulages requis du Objectau type souhaité.
List aList =newArrayList();String s ="Hello World!";
aList.add(s);String c =(String)aList.get(0);
Bien que cela ait fonctionné la plupart du temps, des erreurs se sont produites
List aNumberList =newArrayList();String one ="1";//Number one
aNumberList.add(one);Integer iOne =(Integer)aNumberList.get(0);//Insert ClassCastException here
Les anciennes collections sans type ne pouvaient pas appliquer la sécurité de type, donc le programmeur devait se rappeler ce qu'il stockait dans une collection.
Les génériques ont été inventés pour contourner cette limitation, le développeur déclarerait le type stocké une fois et le compilateur le ferait à la place.
List<String> aNumberList =newArrayList<String>();
aNumberList.add("one");Integer iOne = aNumberList.get(0);//Compile time errorString sOne = aNumberList.get(0);//works fine
En comparaison:
// 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
L'interface Comparable est plus complexe:
//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;}}
Notez qu'il est impossible d'implémenter l' CompareAbleinterface compareTo(MyCompareAble)avec des types bruts. Pourquoi vous ne devriez pas les utiliser:
Tout Objectcontenu stocké dans un Collectiondoit être lancé avant de pouvoir être utilisé
L'utilisation de génériques permet de vérifier les temps de compilation
L'utilisation de types bruts revient à stocker chaque valeur comme Object
Ce que fait le compilateur: les génériques sont rétrocompatibles, ils utilisent les mêmes classes java que les types bruts. La magie se produit principalement au moment de la compilation.
List<String> someStrings =newArrayList<String>();
someStrings.add("one");String one = someStrings.get(0);
Sera compilé comme:
List someStrings =newArrayList();
someStrings.add("one");String one =(String)someStrings.get(0);
Il s'agit du même code que vous écririez si vous utilisiez directement les types bruts. Je ne savais pas trop ce qui se passait avec l' CompareAbleinterface, je suppose qu'elle crée deux compareTofonctions, l'une prenant un MyCompareAbleet l'autre prenant un Objectet le passant à la première après l'avoir lancé.
Quelles sont les alternatives aux types bruts: Utilisez des génériques
Pour créer un type paramétré de Box<T>, vous fournissez un argument de type réel pour le paramètre de type formel T:
Box<Integer> intBox =newBox<>();
Si l'argument de type réel est omis, vous créez un type brut de Box<T>:
Box rawBox =newBox();
Par conséquent, Boxest le type brut du type générique Box<T>. Cependant, un type de classe ou d'interface non générique n'est pas un type brut.
Les types bruts apparaissent dans le code hérité, car de nombreuses classes d'API (telles que les classes Collections) n'étaient pas génériques avant JDK 5.0. Lorsque vous utilisez des types bruts, vous obtenez essentiellement un comportement pré-générique - un Boxvous donne Objects. Pour des raisons de compatibilité descendante, l'attribution d'un type paramétré à son type brut est autorisée:
Box<String> stringBox =newBox<>();Box rawBox = stringBox;// OK
Mais si vous affectez un type brut à un type paramétré, vous obtenez un avertissement:
Box rawBox =newBox();// rawBox is a raw type of Box<T>Box<Integer> intBox = rawBox;// warning: unchecked conversion
Vous obtenez également un avertissement si vous utilisez un type brut pour appeler des méthodes génériques définies dans le type générique correspondant:
L'avertissement montre que les types bruts contournent les vérifications de type génériques, reportant la capture de code non sécurisé à l'exécution. Par conséquent, vous devez éviter d'utiliser des types bruts.
La section Effacement de type contient plus d'informations sur la façon dont le compilateur Java utilise les types bruts.
Messages d'erreur non vérifiés
Comme mentionné précédemment, lorsque vous mélangez du code hérité avec du code générique, vous pouvez rencontrer des messages d'avertissement similaires au suivant:
Remarque: Example.java utilise des opérations non contrôlées ou non sécurisées.
Remarque: recompilez avec -Xlint: décoché pour plus de détails.
Cela peut se produire lorsque vous utilisez une ancienne API qui fonctionne sur des types bruts, comme indiqué dans l'exemple suivant:
publicclassWarningDemo{publicstaticvoid main(String[] args){Box<Integer> bi;
bi = createBox();}staticBox createBox(){returnnewBox();}}
Le terme "non vérifié" signifie que le compilateur ne dispose pas d'assez d'informations sur le type pour effectuer toutes les vérifications de type nécessaires pour garantir la sécurité du type. L'avertissement "non vérifié" est désactivé par défaut, bien que le compilateur donne un indice. Pour voir tous les avertissements "non cochés", recompilez avec -Xlint: non coché.
La recompilation de l'exemple précédent avec -Xlint: unchecked révèle les informations supplémentaires suivantes:
WarningDemo.java:4: warning:[unchecked] unchecked conversion
found :Box
required:Box<java.lang.Integer>
bi = createBox();^1 warning
Pour désactiver complètement les avertissements non vérifiés, utilisez l'indicateur -Xlint: -unchecked. L' @SuppressWarnings("unchecked")annotation supprime les avertissements non contrôlés. Si vous n'êtes pas familier avec la @SuppressWarningssyntaxe, voir Annotations.
Un type "brut" en Java est une classe qui n'est pas générique et traite des objets "bruts", plutôt que des paramètres de type génériques sûrs.
Par exemple, avant que les génériques Java ne soient disponibles, vous utiliseriez une classe de collection comme celle-ci:
LinkedList list =newLinkedList();
list.add(newMyObject());MyObject myObject =(MyObject)list.get(0);
Lorsque vous ajoutez votre objet à la liste, peu importe de quel type d'objet il s'agit, et lorsque vous l'obtenez de la liste, vous devez le convertir explicitement dans le type que vous attendez.
En utilisant des génériques, vous supprimez le facteur "inconnu", car vous devez spécifier explicitement quel type d'objets peut aller dans la liste:
LinkedList<MyObject> list =newLinkedList<MyObject>();
list.add(newMyObject());MyObject myObject = list.get(0);
Notez qu'avec les génériques, vous n'avez pas besoin de transtyper l'objet provenant de l'appel get, la collection est prédéfinie pour fonctionner uniquement avec MyObject. Ce fait est le principal facteur déterminant pour les génériques. Il transforme une source d'erreurs d'exécution en quelque chose qui peut être vérifié au moment de la compilation.
Plus précisément, un type brut est ce que vous obtenez lorsque vous omettez simplement les paramètres de type pour un type générique. Les types bruts n'étaient vraiment qu'une fonctionnalité de compatibilité descendante et sont potentiellement sujets à suppression. Vous pouvez obtenir un comportement similaire en utilisant? paramètres génériques.
John Flatness
@zerocrates: similaire mais différent! L'utilisation ?offre toujours une sécurité de type. Je l'ai couvert dans ma réponse.
lubrifiants polygéniques
19
privatestaticList<String> list =newArrayList<String>();
Vous devez spécifier le type-paramètre.
L'avertissement indique que les types définis pour prendre en charge les génériques doivent être paramétrés, plutôt que d'utiliser leur forme brute.
Listest défini aux génériques de soutien: public class List<E>. Cela permet de nombreuses opérations de type sécurisé, qui sont vérifiées au moment de la compilation.
Maintenant remplacé par l' inférence de diamant dans Java 7 -private static List<String> list = new ArrayList<>();
Ian Campbell
14
Qu'est-ce qu'un type brut et pourquoi est-ce que j'entends souvent qu'ils ne devraient pas être utilisés dans un nouveau code?
Un "type brut" est l'utilisation d'une classe générique sans spécifier un ou des arguments de type pour son ou ses types paramétrés, par exemple en utilisant à la Listplace de List<String>. Lorsque les génériques ont été introduits dans Java, plusieurs classes ont été mises à jour pour utiliser les génériques. L'utilisation de ces classes comme un "type brut" (sans spécifier d'argument de type) a permis au code hérité de continuer à être compilé.
Les "types bruts" sont utilisés pour la compatibilité descendante. Leur utilisation dans le nouveau code n'est pas recommandée car l'utilisation de la classe générique avec un argument de type permet un typage plus fort, ce qui peut à son tour améliorer la compréhensibilité du code et entraîner des problèmes potentiels plus tôt.
Quelle est l'alternative si nous ne pouvons pas utiliser de types bruts, et comment est-ce mieux?
L'alternative préférée consiste à utiliser les classes génériques comme prévu - avec un argument de type approprié (par exemple List<String>). Cela permet au programmeur de spécifier des types plus spécifiquement, donne plus de sens aux futurs responsables de l'utilisation prévue d'une variable ou d'une structure de données, et permet au compilateur d'appliquer une meilleure sécurité de type. Ensemble, ces avantages peuvent améliorer la qualité du code et empêcher l'introduction de certaines erreurs de codage.
Par exemple, pour une méthode où le programmeur veut s'assurer qu'une variable List appelée 'names' ne contient que des chaînes:
List<String> names =newArrayList<String>();
names.add("John");// OK
names.add(newInteger(1));// compile error
Ah, donc tenté de copier polygenelubricantsles références de "type brut" de stackoverflow.com/questions/2770111/… dans ma propre réponse, mais je suppose que je vais les laisser pour une utilisation dans sa propre réponse.
Bert F
1
Oui, j'ai essentiellement copié-collé ce segment partout où les gens utilisent des types bruts sur stackoverflow, et j'ai finalement décidé de n'avoir qu'une seule question à laquelle se référer à partir de maintenant. J'espère que c'est une bonne contribution pour la communauté.
Lubrifiants polygéniques
1
@polygenelubricants J'ai remarqué - nous avons rencontré certaines des mêmes questions :-)
Bert F
1
@ ha9u63ar: En effet. En général, les réponses concises et simples sont au moins aussi bonnes que les réponses longues et acceptées.
displayName
Qu'est-ce que le "typage plus fort"?
carloswm85
12
Le compilateur veut que vous écriviez ceci:
privatestaticList<String> list =newArrayList<String>();
car sinon, vous pourriez ajouter n'importe quel type que vous aimez list, rendant l'instanciation new ArrayList<String>()inutile. Les génériques Java ne sont qu'une fonctionnalité au moment de la compilation, donc un objet créé avec new ArrayList<String>()acceptera volontiers Integerou les JFrameéléments s'il est affecté à une référence du "type brut" List- l'objet lui-même ne sait rien des types qu'il est censé contenir, seul le compilateur le fait.
ArrayList<String> arrc'est une ArrayListvariable de référence dont le type fait Stringréférence à un ArralyListobjet de type String. Cela signifie qu'il ne peut contenir que des objets de type chaîne.
C'est un type strict à Stringpas brut donc il ne déclenchera jamais d'avertissement.
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)
Cas 2
Dans ce cas, ArrayList<String> arrc'est un type strict mais votre objet new ArrayList();est un type brut.
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)
voici arrun type Strict. Ainsi, cela soulèvera une erreur de temps de compilation lors de l'ajout d'un fichier integer.
Avertissement : - Un Rawobjet type est référencé à une Strictvariable référencée de type ArrayList.
Cas 3
Dans ce cas, il ArrayList arrs'agit d'un type brut, mais votre objet new ArrayList<String>();est de type strict.
arr.add("hello");
arr.add(23);//compiles fine but raise the warning.
Il y ajoutera tout type d'objet car il arrs'agit d'un type brut.
Avertissement : - Un Strictobjet type est référencé à une rawvariable référencée type.
Un type brut est l'absence de paramètre de type lors de l'utilisation d'un type générique.
Le type brut ne doit pas être utilisé car il pourrait provoquer des erreurs d'exécution, comme l'insertion d'un doubledans ce qui était censé être un Setde ints.
Set set =newHashSet();
set.add(3.45);//ok
Lorsque vous récupérez le contenu de la Set, vous ne savez pas ce qui sort. Supposons que vous vous attendiez à ce que ce soit tout ints, vous le lancez Integer; exception lors de l'exécution lorsque le double3.45 arrive.
Avec un paramètre de type ajouté à votre Set, vous obtiendrez immédiatement une erreur de compilation. Cette erreur préventive vous permet de résoudre le problème avant que quelque chose explose pendant l'exécution (économisant ainsi du temps et des efforts).
Set<Integer> set =newHashSet<Integer>();
set.add(3.45);//NOT ok.
Comme cela a été mentionné dans la réponse acceptée, vous perdez tout support pour les génériques dans le code du type brut. Chaque paramètre de type est converti en son effacement (qui dans l'exemple ci-dessus est juste Object).
Qu'est - ce que dire est que votre listest un Listdes objets unespecified. C'est-à-dire que Java ne sait pas quels types d'objets se trouvent dans la liste. Ensuite, lorsque vous souhaitez parcourir la liste, vous devez transtyper chaque élément, pour pouvoir accéder aux propriétés de cet élément (dans ce cas, String).
En général, il est préférable de paramétrer les collections, donc vous n'avez pas de problèmes de conversion, vous ne pourrez ajouter que des éléments du type paramétré et votre éditeur vous proposera les méthodes appropriées à sélectionner.
privatestaticList<String> list =newArrayList<String>();
Les types bruts font référence à l'utilisation d'un type générique sans spécifier de paramètre de type.
Par exemple ,
Une liste est un type brut, tandis List<String>qu'un type est paramétré.
Lorsque les génériques ont été introduits dans JDK 1.5, les types bruts ont été conservés uniquement pour maintenir la compatibilité descendante avec les anciennes versions de Java. Bien que l'utilisation de types bruts soit toujours possible,
Ils doivent être évités :
Ils nécessitent généralement des moulages
Ils ne sont pas sécurisés et certains types d'erreurs importants n'apparaîtront qu'au moment de l'exécution
Ils sont moins expressifs et ne s'auto-documentent pas de la même manière que les types paramétrés.
Exemple
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));}}
J'ai trouvé cette page après avoir fait quelques exemples d'exercices et avoir exactement la même perplexité.
============== Je suis passé de ce code tel que fourni par l'exemple ===============
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());}
====================== Vers ce code =========================
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());}}
Les types bruts conviennent bien lorsqu'ils expriment ce que vous voulez exprimer.
Par exemple, une fonction de désérialisation peut retourner un List, mais elle ne connaît pas le type d'élément de la liste. Il en Listva de même du type de retour approprié ici.
Réponses:
Qu'est-ce qu'un type brut?
La spécification du langage Java définit un type brut comme suit:
JLS 4.8 Types bruts
Voici un exemple pour illustrer:
Voici
MyType<E>
un type paramétré ( JLS 4.5 ). Il est courant de se référer familièrement à ce type simplementMyType
pour faire court, mais techniquement le nom estMyType<E>
.mt
a un type brut (et génère un avertissement de compilation) par le premier point de la définition ci-dessus;inn
a également un type brut par le troisième point.MyType.Nested
n'est pas un type paramétré, même s'il s'agit d'un type membre d'un type paramétréMyType<E>
, car il l'eststatic
.mt1
etmt2
sont tous deux déclarés avec des paramètres de type réels, donc ce ne sont pas des types bruts.Quelle est la particularité des types bruts?
Essentiellement, les types bruts se comportent comme ils l'étaient avant l'introduction des génériques. Autrement dit, ce qui suit est entièrement légal au moment de la compilation.
Le code ci-dessus fonctionne très bien, mais supposez que vous disposiez également des éléments suivants:
Maintenant, nous rencontrons des problèmes au moment de l'exécution, car
names
contient quelque chose qui n'est pas uninstanceof String
.On peut supposer que si vous voulez
names
contenir seulementString
, vous pourriez peut - être utiliser encore un type cru et vérifier manuellement chaqueadd
vous, puis jeter manuellement àString
chaque élément denames
. Encore mieux , il ne faut PAS utiliser un type brut et laisser le compilateur faire tout le travail pour vous , en exploitant la puissance des génériques Java.Bien sûr, si vous NE voulez
names
permettre unBoolean
, vous pouvez le déclarer commeList<Object> names
, et le code ci - dessus compilerez.Voir également
En quoi un type brut est-il différent de l'utilisation
<Object>
comme paramètres de type?Ce qui suit est une citation de Effective Java 2nd Edition, article 23: N'utilisez pas de types bruts dans le nouveau code :
Pour illustrer ce point, considérons la méthode suivante qui prend a
List<Object>
et ajoute anew Object()
.Les génériques en Java sont invariants. A
List<String>
n'est pas unList<Object>
, donc ce qui suit générerait un avertissement du compilateur:Si vous aviez déclaré
appendNewObject
prendre un type brutList
comme paramètre, cela se compilerait et vous perdriez donc la sécurité de type que vous obtenez des génériques.Voir également
<E extends Number>
et<Number>
?En quoi un type brut est-il différent de l'utilisation
<?>
comme paramètre de type?List<Object>
,List<String>
, Etc sont tousList<?>
, donc il peut être tentant de simplement dire qu'ils sont juste à laList
place. Cependant, il y a une différence majeure: puisque aList<E>
définit uniquementadd(E)
, vous ne pouvez pas ajouter n'importe quel objet arbitraire à aList<?>
. D'un autre côté, puisque le type brutList
n'a pas de sécurité de type, vous pouvez àadd
peu près n'importe quoi pour aList
.Considérez la variante suivante de l'extrait précédent:
Le compilateur a fait un excellent travail pour vous protéger contre la violation potentielle de l'invariance de type du
List<?>
! Si vous aviez déclaré le paramètre comme type brutList list
, le code se compilerait et vous violeriez l'invariant de typeList<String> names
.Un type brut est l'effacement de ce type
Retour à JLS 4.8:
En termes plus simples, lorsqu'un type brut est utilisé, les constructeurs, les méthodes d'instance et les non-
static
champs sont également effacés .Prenons l'exemple suivant:
Lorsque nous utilisons le brut
MyType
, ilgetNames
est également effacé, de sorte qu'il renvoie un brutList
!JLS 4.6 continue d'expliquer les éléments suivants:
Le rapport de bogue suivant contient quelques réflexions de Maurizio Cimadamore, développeur de compilateur, et d'Alex Buckley, l'un des auteurs du JLS, sur les raisons pour lesquelles ce type de comportement devrait se produire: https://bugs.openjdk.java.net/browse / JDK-6400189 . (En bref, cela rend la spécification plus simple.)
Si ce n'est pas sûr, pourquoi est-il autorisé à utiliser un type brut?
Voici une autre citation de JLS 4.8:
Efficace Java 2nd Edition a également ceci à ajouter:
En résumé, les types bruts ne doivent JAMAIS être utilisés dans un nouveau code. Vous devez toujours utiliser des types paramétrés .
N'y a-t-il pas d'exceptions?
Malheureusement, comme les génériques Java ne sont pas réifiés, il existe deux exceptions où les types bruts doivent être utilisés dans le nouveau code:
List.class
, nonList<String>.class
instanceof
opérande, par exempleo instanceof Set
, paso instanceof Set<String>
Voir également
Collection<String>.class
illégal?la source
o instanceof Set<?>
est également autorisée pour éviter le type brut (bien que ce ne soit que superficiel dans ce cas).n
des beans distants pour chaque classe d'implémentation avec un code identique.TypeName.class
, oùTypeName
est un identificateur simple ( jls ). Parlant hypothétiquement, je suppose que ça pourrait vraiment être l'un ou l'autre. Peut-être comme indice,List<String>.class
est la variante que le JLS appelle spécifiquement une erreur de compilation, donc s'ils l'ajoutent jamais au langage, je m'attends à ce que ce soit celui qu'ils utilisent.Les types bruts sont une histoire ancienne du langage Java. Au début, il y en avait
Collections
et ilsObjects
ne tenaient ni plus ni moins. Chaque opération surCollections
les moulages requis duObject
au type souhaité.Bien que cela ait fonctionné la plupart du temps, des erreurs se sont produites
Les anciennes collections sans type ne pouvaient pas appliquer la sécurité de type, donc le programmeur devait se rappeler ce qu'il stockait dans une collection.
Les génériques ont été inventés pour contourner cette limitation, le développeur déclarerait le type stocké une fois et le compilateur le ferait à la place.
En comparaison:
L'interface Comparable est plus complexe:
Notez qu'il est impossible d'implémenter l'
CompareAble
interfacecompareTo(MyCompareAble)
avec des types bruts. Pourquoi vous ne devriez pas les utiliser:Object
contenu stocké dans unCollection
doit être lancé avant de pouvoir être utiliséObject
Ce que fait le compilateur: les génériques sont rétrocompatibles, ils utilisent les mêmes classes java que les types bruts. La magie se produit principalement au moment de la compilation.
Sera compilé comme:
Il s'agit du même code que vous écririez si vous utilisiez directement les types bruts. Je ne savais pas trop ce qui se passait avec l'
CompareAble
interface, je suppose qu'elle crée deuxcompareTo
fonctions, l'une prenant unMyCompareAble
et l'autre prenant unObject
et le passant à la première après l'avoir lancé.Quelles sont les alternatives aux types bruts: Utilisez des génériques
la source
Un type brut est le nom d'une classe ou d'une interface générique sans aucun argument de type. Par exemple, étant donné la classe Box générique:
Pour créer un type paramétré de
Box<T>
, vous fournissez un argument de type réel pour le paramètre de type formelT
:Si l'argument de type réel est omis, vous créez un type brut de
Box<T>
:Par conséquent,
Box
est le type brut du type génériqueBox<T>
. Cependant, un type de classe ou d'interface non générique n'est pas un type brut.Les types bruts apparaissent dans le code hérité, car de nombreuses classes d'API (telles que les classes Collections) n'étaient pas génériques avant JDK 5.0. Lorsque vous utilisez des types bruts, vous obtenez essentiellement un comportement pré-générique - un
Box
vous donneObject
s. Pour des raisons de compatibilité descendante, l'attribution d'un type paramétré à son type brut est autorisée:Mais si vous affectez un type brut à un type paramétré, vous obtenez un avertissement:
Vous obtenez également un avertissement si vous utilisez un type brut pour appeler des méthodes génériques définies dans le type générique correspondant:
L'avertissement montre que les types bruts contournent les vérifications de type génériques, reportant la capture de code non sécurisé à l'exécution. Par conséquent, vous devez éviter d'utiliser des types bruts.
La section Effacement de type contient plus d'informations sur la façon dont le compilateur Java utilise les types bruts.
Messages d'erreur non vérifiés
Comme mentionné précédemment, lorsque vous mélangez du code hérité avec du code générique, vous pouvez rencontrer des messages d'avertissement similaires au suivant:
Cela peut se produire lorsque vous utilisez une ancienne API qui fonctionne sur des types bruts, comme indiqué dans l'exemple suivant:
Le terme "non vérifié" signifie que le compilateur ne dispose pas d'assez d'informations sur le type pour effectuer toutes les vérifications de type nécessaires pour garantir la sécurité du type. L'avertissement "non vérifié" est désactivé par défaut, bien que le compilateur donne un indice. Pour voir tous les avertissements "non cochés", recompilez avec -Xlint: non coché.
La recompilation de l'exemple précédent avec -Xlint: unchecked révèle les informations supplémentaires suivantes:
Pour désactiver complètement les avertissements non vérifiés, utilisez l'indicateur -Xlint: -unchecked. L'
@SuppressWarnings("unchecked")
annotation supprime les avertissements non contrôlés. Si vous n'êtes pas familier avec la@SuppressWarnings
syntaxe, voir Annotations.Source d'origine: Tutoriels Java
la source
Un type "brut" en Java est une classe qui n'est pas générique et traite des objets "bruts", plutôt que des paramètres de type génériques sûrs.
Par exemple, avant que les génériques Java ne soient disponibles, vous utiliseriez une classe de collection comme celle-ci:
Lorsque vous ajoutez votre objet à la liste, peu importe de quel type d'objet il s'agit, et lorsque vous l'obtenez de la liste, vous devez le convertir explicitement dans le type que vous attendez.
En utilisant des génériques, vous supprimez le facteur "inconnu", car vous devez spécifier explicitement quel type d'objets peut aller dans la liste:
Notez qu'avec les génériques, vous n'avez pas besoin de transtyper l'objet provenant de l'appel get, la collection est prédéfinie pour fonctionner uniquement avec MyObject. Ce fait est le principal facteur déterminant pour les génériques. Il transforme une source d'erreurs d'exécution en quelque chose qui peut être vérifié au moment de la compilation.
la source
?
offre toujours une sécurité de type. Je l'ai couvert dans ma réponse.Vous devez spécifier le type-paramètre.
L'avertissement indique que les types définis pour prendre en charge les génériques doivent être paramétrés, plutôt que d'utiliser leur forme brute.
List
est défini aux génériques de soutien:public class List<E>
. Cela permet de nombreuses opérations de type sécurisé, qui sont vérifiées au moment de la compilation.la source
private static List<String> list = new ArrayList<>();
Qu'est-ce qu'un type brut et pourquoi est-ce que j'entends souvent qu'ils ne devraient pas être utilisés dans un nouveau code?
Un "type brut" est l'utilisation d'une classe générique sans spécifier un ou des arguments de type pour son ou ses types paramétrés, par exemple en utilisant à la
List
place deList<String>
. Lorsque les génériques ont été introduits dans Java, plusieurs classes ont été mises à jour pour utiliser les génériques. L'utilisation de ces classes comme un "type brut" (sans spécifier d'argument de type) a permis au code hérité de continuer à être compilé.Les "types bruts" sont utilisés pour la compatibilité descendante. Leur utilisation dans le nouveau code n'est pas recommandée car l'utilisation de la classe générique avec un argument de type permet un typage plus fort, ce qui peut à son tour améliorer la compréhensibilité du code et entraîner des problèmes potentiels plus tôt.
Quelle est l'alternative si nous ne pouvons pas utiliser de types bruts, et comment est-ce mieux?
L'alternative préférée consiste à utiliser les classes génériques comme prévu - avec un argument de type approprié (par exemple
List<String>
). Cela permet au programmeur de spécifier des types plus spécifiquement, donne plus de sens aux futurs responsables de l'utilisation prévue d'une variable ou d'une structure de données, et permet au compilateur d'appliquer une meilleure sécurité de type. Ensemble, ces avantages peuvent améliorer la qualité du code et empêcher l'introduction de certaines erreurs de codage.Par exemple, pour une méthode où le programmeur veut s'assurer qu'une variable List appelée 'names' ne contient que des chaînes:
la source
polygenelubricants
les références de "type brut" de stackoverflow.com/questions/2770111/… dans ma propre réponse, mais je suppose que je vais les laisser pour une utilisation dans sa propre réponse.Le compilateur veut que vous écriviez ceci:
car sinon, vous pourriez ajouter n'importe quel type que vous aimez
list
, rendant l'instanciationnew ArrayList<String>()
inutile. Les génériques Java ne sont qu'une fonctionnalité au moment de la compilation, donc un objet créé avecnew ArrayList<String>()
acceptera volontiersInteger
ou lesJFrame
éléments s'il est affecté à une référence du "type brut"List
- l'objet lui-même ne sait rien des types qu'il est censé contenir, seul le compilateur le fait.la source
Ici, je considère plusieurs cas à travers lesquels vous pouvez clarifier le concept
Cas 1
ArrayList<String> arr
c'est uneArrayList
variable de référence dont le type faitString
référence à unArralyList
objet de typeString
. Cela signifie qu'il ne peut contenir que des objets de type chaîne.C'est un type strict à
String
pas brut donc il ne déclenchera jamais d'avertissement.Cas 2
Dans ce cas,
ArrayList<String> arr
c'est un type strict mais votre objetnew ArrayList();
est un type brut.voici
arr
un type Strict. Ainsi, cela soulèvera une erreur de temps de compilation lors de l'ajout d'un fichierinteger
.Cas 3
Dans ce cas, il
ArrayList arr
s'agit d'un type brut, mais votre objetnew ArrayList<String>();
est de type strict.Il y ajoutera tout type d'objet car il
arr
s'agit d'un type brut.la source
Un type brut est l'absence de paramètre de type lors de l'utilisation d'un type générique.
Le type brut ne doit pas être utilisé car il pourrait provoquer des erreurs d'exécution, comme l'insertion d'un
double
dans ce qui était censé être unSet
deint
s.Lorsque vous récupérez le contenu de la
Set
, vous ne savez pas ce qui sort. Supposons que vous vous attendiez à ce que ce soit toutint
s, vous le lancezInteger
; exception lors de l'exécution lorsque ledouble
3.45 arrive.Avec un paramètre de type ajouté à votre
Set
, vous obtiendrez immédiatement une erreur de compilation. Cette erreur préventive vous permet de résoudre le problème avant que quelque chose explose pendant l'exécution (économisant ainsi du temps et des efforts).la source
Voici un autre cas où les types bruts vous mordront:
Comme cela a été mentionné dans la réponse acceptée, vous perdez tout support pour les génériques dans le code du type brut. Chaque paramètre de type est converti en son effacement (qui dans l'exemple ci-dessus est juste
Object
).la source
Qu'est - ce que dire est que votre
list
est unList
des objets unespecified. C'est-à-dire que Java ne sait pas quels types d'objets se trouvent dans la liste. Ensuite, lorsque vous souhaitez parcourir la liste, vous devez transtyper chaque élément, pour pouvoir accéder aux propriétés de cet élément (dans ce cas, String).En général, il est préférable de paramétrer les collections, donc vous n'avez pas de problèmes de conversion, vous ne pourrez ajouter que des éléments du type paramétré et votre éditeur vous proposera les méthodes appropriées à sélectionner.
la source
page de tutoriel .
Un type brut est le nom d'une classe ou d'une interface générique sans aucun argument de type. Par exemple, étant donné la classe Box générique:
Pour créer un type de boîte paramétré, vous fournissez un argument de type réel pour le paramètre de type formel T:
Si l'argument de type réel est omis, vous créez un type brut de boîte:
la source
Évitez les types bruts
Par exemple ,
Une liste est un type brut, tandis
List<String>
qu'un type est paramétré.Lorsque les génériques ont été introduits dans JDK 1.5, les types bruts ont été conservés uniquement pour maintenir la compatibilité descendante avec les anciennes versions de Java. Bien que l'utilisation de types bruts soit toujours possible,
Ils doivent être évités :
Ils sont moins expressifs et ne s'auto-documentent pas de la même manière que les types paramétrés. Exemple
Pour référence : https://docs.oracle.com/javase/tutorial/java/generics/rawTypes.html
la source
J'ai trouvé cette page après avoir fait quelques exemples d'exercices et avoir exactement la même perplexité.
============== Je suis passé de ce code tel que fourni par l'exemple ===============
====================== Vers ce code =========================
================================================== =============================
Cela peut être plus sûr, mais il a fallu 4 heures pour brouiller la philosophie ...
la source
Les types bruts conviennent bien lorsqu'ils expriment ce que vous voulez exprimer.
Par exemple, une fonction de désérialisation peut retourner un
List
, mais elle ne connaît pas le type d'élément de la liste. Il enList
va de même du type de retour approprié ici.la source