La spécification de langage Java définit un type brut comme suit:
Un type brut est défini comme étant l’un des suivants:
Le 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 type de membre non
static
d’un type brutR
qui n’est pas hérité d’une superclasse ou d’une superinterface deR
Voici un exemple pour illustrer:
public class MyType { class Inner { } static class Nested { } public static void main(Ssortingng[] args) { MyType mt; // warning: MyType is a raw type MyType.Inner inn; // warning: MyType.Inner is a raw type MyType.Nested nest; // no warning: not parameterized type MyType
Ici, MyType
est un type paramétré ( JLS 4.5 ). Il est courant de parler couramment de ce type simplement comme MyType
, mais techniquement, son nom est MyType
.
mt
a un type brut (et génère un avertissement de compilation) par le premier sharepoint la définition ci-dessus; inn
également un type brut à la troisième puce.
MyType.Nested
n’est pas un type paramétré, même s’il s’agit d’un type de membre d’un type paramétré MyType
, car il est static
.
mt1
et mt2
sont tous deux déclarés avec les parameters de type réels, ils ne sont donc pas des types bruts.
Essentiellement, les types bruts se comportent comme avant l’introduction des génériques. C’est-à-dire que ce qui suit est tout à fait légal au moment de la compilation.
List names = new ArrayList(); // warning: raw type! names.add("John"); names.add("Mary"); names.add(Boolean.FALSE); // not a compilation error!
Le code ci-dessus fonctionne correctement, mais supposons que vous disposiez également des éléments suivants:
for (Object o : names) { Ssortingng name = (Ssortingng) o; System.out.println(name); } // throws ClassCastException! // java.lang.Boolean cannot be cast to java.lang.Ssortingng
Nous avons maintenant des problèmes au moment de l’exécution, car les names
contiennent quelque chose qui n’est pas une instanceof Ssortingng
.
Vraisemblablement, si vous voulez que les names
ne contiennent que Ssortingng
, vous pouvez toujours utiliser un type brut et vérifier manuellement chaque add
, puis transtyper manuellement en Ssortingng
chaque élément à partir de names
. Mieux encore , il ne faut PAS utiliser un type brut et laisser le compilateur faire tout le travail à votre place , en exploitant la puissance des génériques Java.
List names = new ArrayList (); names.add("John"); names.add("Mary"); names.add(Boolean.FALSE); // compilation error!
Bien sûr, si vous voulez que les names
autorisent un Boolean
, vous pouvez le déclarer sous la forme de List
et le code ci-dessus sera compilé.
tant que parameters de type? Ce qui suit est une citation tirée de Effective Java 2nd Edition, élément 23: n’utilisez pas de types bruts dans le nouveau code :
Quelle est la différence entre le type brut
List
et le type paramétréList
? En gros, le premier a désactivé la vérification de type générique, tandis que le second a explicitement indiqué au compilateur qu’il était capable de contenir des objects de tout type. Bien que vous puissiez passer unList
à un paramètre de typeList
, vous ne pouvez pas le transmettre à un paramètre de typeList
. Il existe des règles de sous-typage pour les génériques etList
est un sous-type du type brutList
, mais pas du type paramétréList
. En conséquence, vous perdez la sécurité de type si vous utilisez un type brut commeList
, mais pas si vous utilisez un type paramétré tel queList
.
Pour illustrer ce propos, considérons la méthode suivante qui utilise un List
et ajoute un new Object()
.
void appendNewObject(List
Les génériques en Java sont invariants. Une List
n’est pas une List
. Par conséquent, les éléments suivants génèrent un avertissement du compilateur:
List names = new ArrayList (); appendNewObject(names); // compilation error!
Si vous aviez déclaré que appendNewObject
une List
type brut en tant que paramètre, la compilation serait alors effectuée et le type de sécurité que vous obtenez des génériques était alors perdu.
et
? >
Comme paramètre de type? List
, List
, etc sont tous des List>
. Il peut donc être tentant de simplement dire qu’ils sont simplement List
. Cependant, il existe une différence majeure: dans la mesure où une List
ne définit que add(E)
, vous ne pouvez append aucun object quelconque à une List>
. D’autre part, étant donné que le type brut List
n’a pas de type sécurité, vous pouvez add
peu près n’importe quoi à une List
.
Considérez la variante suivante de l’extrait précédent:
static void appendNewObject(List> list) { list.add(new Object()); // compilation error! } //... List names = new ArrayList (); appendNewObject(names); // this part is fine!
Le compilateur a fait un travail remarquable en vous protégeant d’une éventuelle violation de l’invariance de type de la List>
! Si vous aviez déclaré le paramètre en tant que List list
type brut, le code se comstackrait et vous violeriez le type invariant des List
de List
.
Retour à JLS 4.8:
Il est possible d’utiliser comme type l’effacement d’un type paramétré ou l’effacement d’un type de tableau dont le type d’élément est un type paramétré. Un tel type s’appelle un type brut .
[…]
Les superclasses (respectivement, les superinterfaces) d’un type brut sont les effacements des superclasses (superinterfaces) de l’une des paramésortingsations du type générique.
Le type d’un constructeur, d’une méthode d’instance ou d’
static
champ nonstatic
d’un type brutC
qui 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 static
champs non static
sont également effacés .
Prenons l’exemple suivant:
class MyType { List getNames() { return Arrays.asList("John", "Mary"); } public static void main(Ssortingng[] args) { MyType rawType = new MyType(); // unchecked warning! // required: List found: List List names = rawType.getNames(); // compilation error! // incompatible types: Object cannot be converted to Ssortingng for (Ssortingng str : rawType.getNames()) System.out.print(str); } }
Lorsque nous utilisons le MyType
brut, getNames
est également effacé, de sorte qu’il renvoie une List
brute!
JLS 4.6 continue d’expliquer ce qui suit:
L’effacement de type mappe également la signature d’un constructeur ou d’une méthode sur une signature qui n’a pas de types paramétrés ni de variables de type. L’effacement d’une signature de constructeur ou de méthode
s
est une signature composée du même nom ques
et les effacements de tous les types de parameters formels donnés ens
.Le type de retour d’une méthode et les parameters de type d’une méthode ou d’un constructeur générique sont également effacés 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 aucun paramètre de type.
Le rapport de bogue suivant contient quelques reflections de Maurizio Cimadamore, un développeur de compilateur, et 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 simplifie la spécification.)
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 le 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.
Effective Java 2nd Edition doit également append ceci:
Étant donné que vous ne devriez 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 lorsque les génériques ont été introduits, 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 rest légal et interopérable avec le nouveau code qui utilise des génériques. Il devait être légal de passer des instances de types paramétrés à des méthodes conçues pour être utilisées avec des types ordinaires, et inversement. Cette exigence, appelée compatibilité de migration , a motivé la décision de prendre en charge les types bruts.
En résumé, les types bruts ne doivent JAMAIS être utilisés dans le nouveau code. Vous devez toujours utiliser des types paramétrés .
Malheureusement, les génériques Java n’étant pas réifiés, il existe deux exceptions où les types bruts doivent être utilisés dans le nouveau code:
List.class
classe, par exemple List.class
, pas List.class
instanceof
opérande, par exemple o instanceof Set
, pas o instanceof Set
Collection.class
illégal? Que sont les types bruts en Java et pourquoi est-ce que j’entends souvent dire qu’ils ne devraient pas être utilisés dans du nouveau code?
Les types bruts sont une histoire ancienne du langage Java. Au début, il y avait des Collections
et ils ne contenaient des Objects
ni plus ni moins. Chaque opération sur Collections
requirejses transfère d’ Object
vers le type souhaité.
List aList = new ArrayList(); Ssortingng s = "Hello World!"; aList.add(s); Ssortingng c = (Ssortingng)aList.get(0);
Bien que cela ait fonctionné la plupart du temps, des erreurs se sont produites
List aNumberList = new ArrayList(); Ssortingng one = "1";//Number one aNumberList.add(one); Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here
Les anciennes collections non typées ne pouvaient pas appliquer la sécurité de type, le programmeur devait donc se souvenir de ce qu’il stockait dans une collection.
Les génériques ayant été inventés pour contourner cette limitation, le développeur déclarait le type stocké une fois et le compilateur le faisait à la place.
List aNumberList = new ArrayList (); aNumberList.add("one"); Integer iOne = aNumberList.get(0);//Comstack time error Ssortingng sOne = aNumberList.get(0);//works fine
En comparaison:
// Old style collections now known as raw types List aList = new ArrayList(); //Could contain anything // New style collections with Generics List aList = new ArrayList (); //Contains only Ssortingngs
Plus complexe l’interface Comparable:
//raw, not type save can compare with Other classes class MyCompareAble implements CompareAble { int id; public int compareTo(Object other) {return this.id - ((MyCompareAble)other).id;} } //Generic class MyCompareAble implements CompareAble { int id; public int compareTo(MyCompareAble other) {return this.id - other.id;} }
Notez qu’il est impossible d’implémenter l’interface compareTo(MyCompareAble)
avec compareTo(MyCompareAble)
avec des types bruts. Pourquoi vous ne devriez pas les utiliser:
Object
stocké dans une Collection
doit être moulé avant de pouvoir être utilisé Object
Que fait le compilateur? Les génériques sont compatibles avec les versions antérieures, ils utilisent les mêmes classes java que les types bruts. La magie se produit surtout au moment de la compilation.
List someSsortingngs = new ArrayList (); someSsortingngs.add("one"); Ssortingng one = someSsortingngs.get(0);
Sera compilé comme:
List someSsortingngs = new ArrayList(); someSsortingngs.add("one"); Ssortingng one = (Ssortingng)someSsortingngs.get(0);
C’est le même code que vous écririez si vous utilisiez directement les types bruts. Bien que je ne sois pas sûr de ce qui se passe avec l’interface de CompareAble
, je suppose qu’elle crée deux fonctions compareTo
, l’une prenant un object MyCompareAble
et l’autre prenant un Object
et le passant à la première après l’avoir lancé.
Quelles sont les alternatives aux types bruts: Utilisez des génériques
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:
public class Box { public void set(T t) { /* ... */ } // ... }
Pour créer un type paramétré de Box
, vous fournissez un argument de type réel pour le paramètre de type formel T
:
Box intBox = new Box<>();
Si l’argument de type réel est omis, vous créez un type brut de Box
:
Box rawBox = new Box();
Par conséquent, Box
est le type brut du type générique Box
. Toutefois, une classe ou un type 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 – une Box
vous donne des Object
. Pour la compatibilité ascendante, l’affectation d’un type paramétré à son type brut est autorisée:
Box ssortingngBox = new Box<>(); Box rawBox = stringBox; // OK
Mais si vous affectez un type brut à un type paramétré, vous recevez un avertissement:
Box rawBox = new Box(); // rawBox is a raw type of Box Box intBox = rawBox; // warning: unchecked conversion
Vous recevez é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:
Box ssortingngBox = new Box<>(); Box rawBox = stringBox; rawBox.set(8); // warning: unchecked invocation to set(T)
L’avertissement indique que les types bruts contournent les vérifications de type génériques, reportant la capture du code non sécurisé à l’exécution. Par conséquent, vous devriez éviter d’utiliser des types bruts.
La section Type Erasure contient plus d’informations sur la manière dont le compilateur Java utilise les types bruts.
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 semblables aux suivants:
Remarque: Example.java utilise des opérations non contrôlées ou non sécurisées.
Remarque: Recomstackr avec -Xlint: décoché pour plus de détails.
Cela peut se produire lors de l’utilisation d’une ancienne API qui fonctionne sur des types bruts, comme illustré dans l’exemple suivant:
public class WarningDemo { public static void main(Ssortingng[] args){ Box bi; bi = createBox(); } static Box createBox(){ return new Box(); } }
Le terme “décoché” 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 assurer la sécurité du type. L’avertissement “non coché” est désactivé par défaut, bien que le compilateur donne un indice. Pour voir tous les avertissements “non contrôlés”, recomstackz avec -Xlint: non cochée.
La recompilation de l’exemple précédent avec -Xlint: désélectionnée révèle les informations supplémentaires suivantes:
WarningDemo.java:4: warning: [unchecked] unchecked conversion found : Box required: Box bi = createBox(); ^ 1 warning
Pour désactiver complètement les avertissements non vérifiés, utilisez l’indicateur -Xlint: -unchecked. L’ @SuppressWarnings("unchecked")
supprime les avertissements non cochés. Si vous ne connaissez pas la syntaxe @SuppressWarnings
, reportez-vous à Annotations.
Source d’origine: Tutoriels Java
private static List list = new ArrayList ();
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 pour prendre en charge les génériques: public class List
. Cela permet de nombreuses opérations sécurisées, qui sont vérifiées à la compilation.
Un type “brut” en Java est une classe non générique qui traite des objects “bruts”, plutôt que des parameters de type génériques sûrs pour le type.
Par exemple, avant que les génériques Java soient disponibles, vous utiliseriez une classe de collection comme celle-ci:
LinkedList list = new LinkedList(); list.add(new MyObject()); MyObject myObject = (MyObject)list.get(0);
Lorsque vous ajoutez votre object à la liste, son type importe peu, et lorsque vous le récupérez dans la liste, vous devez explicitement le transtyper vers le type que vous attendez.
En utilisant des génériques, vous supprimez le facteur “inconnu”, car vous devez spécifier explicitement le type d’objects pouvant figurer dans la liste:
LinkedList list = new LinkedList (); list.add(new MyObject()); MyObject myObject = list.get(0);
Notez qu’avec les génériques, il n’est pas nécessaire de convertir l’object 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. Cela change une source d’erreurs d’exécution en quelque chose qui peut être vérifié lors de la compilation.
Qu’est-ce qu’un type brut et pourquoi j’entends souvent dire qu’il ne devrait pas être utilisé dans un nouveau code?
Un “type brut” est l’utilisation d’une classe générique sans spécifier d’argument (s) de type pour ses types paramétrés, par exemple en utilisant List
au lieu de List
. Lorsque les génériques ont été introduits dans Java, plusieurs classes ont été mises à jour pour utiliser des génériques. L’utilisation de ces classes en tant que “type brut” (sans spécifier d’argument de type) permettait au code hérité de continuer à être compilé.
Les “types bruts” sont utilisés pour la compatibilité ascendante. 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 puissant, ce qui peut améliorer la compréhensibilité du code et permettre de détecter les problèmes potentiels plus tôt.
Quelle est l’alternative si nous ne pouvons pas utiliser de types bruts, et comment est-il meilleur?
L’alternative recommandée consiste à utiliser les classes génériques comme prévu – avec un argument de type approprié (par exemple, List
). Cela permet au programmeur de spécifier les types de manière plus spécifique, donne plus de signification aux futurs responsables de la maintenance sur l’utilisation prévue d’une structure de variable ou de données et permet au compilateur de renforcer la sécurité de type. La combinaison de ces avantages peut améliorer la qualité du code et aider à prévenir certaines erreurs de codage.
Par exemple, pour une méthode où le programmeur veut s’assurer qu’une variable de liste nommée ‘noms’ ne contient que des chaînes:
List names = new ArrayList (); names.add("John"); // OK names.add(new Integer(1)); // comstack error
Le compilateur veut que vous écriviez ceci:
private static List list = new ArrayList ();
sinon, vous pourriez append le type de votre choix à la list
, rendant l’instanciation new ArrayList
inutile. Les génériques Java étant uniquement une fonctionnalité de compilation, un object créé avec un new ArrayList
acceptera avec JFrame
éléments Integer
ou JFrame
s’il est affecté à une référence de la liste “type brut” – l’object lui-même ne sait pas quels types il est supposé contenir, seul le compilateur en contient.
Ici, je considère plusieurs cas à travers lesquels vous pouvez clarifier le concept
1. ArrayList arr = new ArrayList (); 2. ArrayList arr = new ArrayList(); 3. ArrayList arr = new ArrayList ();
ArrayList
est une variable de référence ArrayList
de type Ssortingng
qui fait référence à un object ArralyList
de type Ssortingng
. Cela signifie qu’il ne peut contenir que Object de type Ssortingng.
C’est un ssortingct pour Ssortingng
pas un type brut alors, il ne déclenchera jamais un avertissement.
arr.add("hello");// alone statement will comstack successfully and no warning. arr.add(23); //prone to comstack time error. //error: no suitable method found for add(int)
Dans ce cas, ArrayList
est un type ssortingct, mais votre object new ArrayList();
est un type brut.
arr.add("hello"); //alone this comstack but raise the warning. arr.add(23); //again prone to comstack time error. //error: no suitable method found for add(int)
ici arr
est un type ssortingct. Donc, il va générer une erreur de compilation lors de l’ajout d’un integer
.
Avertissement : – Un object de type
Raw
est référencé à une variable référencée de typeSsortingct
deArrayList
.
Dans ce cas, ArrayList arr
est un type brut mais votre new ArrayList
object new ArrayList
est un type ssortingct.
arr.add("hello"); arr.add(23); //comstacks fine but raise the warning.
Il y appenda n’importe quel type d’object car arr
est un type brut.
Avertissement : – Un object de type
Ssortingct
est référencé à une variable référencée de typeraw
.
Un type brut est l’absence d’un paramètre de type lors de l’utilisation d’un type générique.
Le type brut ne doit pas être utilisé car cela pourrait provoquer des erreurs d’exécution, comme l’insertion d’un double
dans ce qui était supposé être un Set
d’ int
.
Set set = new HashSet(); set.add(3.45); //ok
Lors de la récupération des éléments de l’ Set
, vous ne savez pas ce qui va sortir. Supposons que vous vous attendiez à ce qu’il soit entièrement int
, vous le transmettez à Integer
; exception à l’exécution lorsque le double
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 ne se produise lors de l’exécution (gain de temps et d’effort).
Set set = new HashSet (); set.add(3.45); //NOT ok.
Ce que vous dites, c’est que votre list
est une List
d’objects non spécifiés. En d’autres termes, Java ne sait pas quel type d’objects se trouvent dans la liste. Ensuite, lorsque vous souhaitez parcourir la liste, vous devez convertir chaque élément pour pouvoir accéder aux propriétés de cet élément (dans ce cas, Ssortingng).
En règle générale, il est préférable de paramétrer les collections. Ainsi, vous n’aurez aucun problème de conversion, vous ne pourrez append que des éléments du type paramétré et votre éditeur vous proposera les méthodes appropriées pour la sélection.
private static List list = new ArrayList ();
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:
public class Box { public void set(T t) { /* ... */ } // ... }
Pour créer un type paramétré de Box, vous devez fournir un argument de type réel pour le paramètre de type formel T:
Box intBox = new Box<>();
Si l’argument de type réel est omis, vous créez un type brut de Box:
Box rawBox = new Box();
Voici un autre cas où les types bruts vont vous mordre:
public class StrangeClass { @SuppressWarnings("unchecked") public X getSomethingElse() { return (X)"Testing something else!"; } public static void main(Ssortingng[] args) { final StrangeClass
Comme indiqué dans la réponse acceptée, vous perdez toute prise en charge des 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, n’est que Object
).
J’ai trouvé cette page après avoir fait quelques exemples d’exercices et eu exactement le même étonnement.
============== Je suis passé de ce code tel que fourni par l’exemple ===============
public static void main(Ssortingng[] args) throws IOException { Map wordMap = new HashMap(); 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()); }
===================== Pour ce code =======================
public static void main(Ssortingng[] args) throws IOException { // replace with TreeMap to get them sorted by name Map wordMap = new HashMap(); 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();) { Entry entry = i.next(); System.out.println(entry.getKey() + " :\t" + entry.getValue()); } }
=============================================== =============================
C’est peut-être plus sûr mais il a fallu 4 heures pour comprendre la philosophie ...
Les types bruts sont bien quand ils expriment ce que vous voulez exprimer.
Par exemple, une fonction de désérialisation peut renvoyer une List
, mais elle ne connaît pas le type d’élément de la liste. Donc, la List
est le type de retour approprié ici.