Réponses
Trop de publicités?Qu'est ce qu'une crue de type?
Le Langage Java Spécification définit une crue de type comme suit:
JLS 4.8 Raw Types
Une crue de type est défini comme:
- Le nom générique d'une déclaration de type utilisé sans aucune mesure d'accompagnement réel des paramètres de type.
- Tout non-statique type de membre d'une crue de type
R
qui n'est pas hérité d'une super-classe ou superinterface d'R
.
Voici un exemple pour illustrer:
public class MyType<E> {
class Inner { }
static class Nested { }
public static void main(String[] 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<Object> mt1; // no warning: type parameter given
MyType<?> mt2; // no warning: type parameter given (wildcard OK!)
}
}
Ici, MyType<E>
est un type paramétré (JLS 4.5). Il est courant de familièrement, se référer à ce type que simplement MyType
pour les courts, mais, techniquement, le nom est MyType<E>
.
mt
a une crue de type (et génère une compilation d'avertissement) par le premier point, dans la définition ci-dessus; inn
a également une crue du type de la deuxième puce.
MyType.Nested
n'est pas un type paramétré, même si c'est un type de membre d'un type paramétré MyType<E>
, parce que c'est static
.
mt1
, et mt2
sont à la fois déclarée avec le type réel les paramètres, de sorte qu'ils ne sont pas crus types.
Quel est si spécial à propos de raw types?
Essentiellement, raw types se comporte exactement comme ils étaient avant les génériques ont été introduites. Qui est, 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 très bien, mais supposons que vous avez également la suivante:
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 nous heurtons à des difficultés au moment de l'exécution, parce qu' names
contient quelque chose qui n'est pas un instanceof String
.
Sans doute, si vous souhaitez names
ne contiennent qu' String
, vous pourriez peut-être toujours utiliser une crue de type et de vérifier manuellement chaque add
vous-même, et ensuite manuellement en fonte d' String
chaque élément à partir d' names
. Mieux encore, cependant, est de ne PAS utiliser une crue de type et de laisser le compilateur fait tout le travail pour vous, en exploitant la puissance de Java génériques.
List<String> names = new ArrayList<String>();
names.add("John");
names.add("Mary");
names.add(Boolean.FALSE); // compilation error!
Bien sûr, si vous NE souhaitez names
afin de permettre à un Boolean
, alors vous pouvez la déclarer comme List<Object> names
, et le code ci-dessus serait de compiler.
Voir aussi
Comment raw d'un type différent de l'utilisation de <Object>
que les paramètres de type
Ce qui suit est une citation de Efficace Java 2nd Edition, Point 23: Ne pas utiliser des types dans le nouveau code:
Juste quelle est la différence entre le brut de type
List
et le type paramétréList<Object>
? Grosso modo, l'ancien a opté générique vérification de type, tandis que le second dit explicitement au compilateur qu'il est capable de tenir des objets de tout type. Alors que vous pouvez passer unList<String>
pour un paramètre de typeList
, vous ne pouvez pas passer à un paramètre de typeList<Object>
. Il y a des règles de sous-typage pour les génériques, etList<String>
est un sous-type de la crue de typeList
, mais pas du type paramétréList<Object>
. En conséquence, vous perdez de sécurité de type si vous utilisez raw typeList
, mais pas si vous utilisez un type paramétré commeList<Object>
.
Pour illustrer ce point, considérons la méthode suivante, qui prend en List<Object>
et ajoute un new Object()
.
void appendNewObject(List<Object> list) {
list.add(new Object());
}
Les médicaments génériques en Java sont invariantes. Un List<String>
n'est pas un List<Object>
, de sorte que la suivante serait de générer un avertissement du compilateur:
List<String> names = new ArrayList<String>();
appendNewObject(names); // compilation error!
Si vous aviez déclaré appendNewObject
de prendre une crue de type List
en paramètre, alors ce serait de la compilation, et vous seriez donc de perdre le type de sécurité que vous obtenez à partir de génériques.
Voir aussi
Comment raw d'un type différent de l'utilisation de <?>
comme un paramètre de type?
List<Object>
, List<String>
, etc sont tous List<?>
, de sorte qu'il peut être tentant de simplement dire qu'ils sont juste List
à la place. Cependant, il existe une différence majeure: depuis un List<E>
ne définit qu' add(E)
, vous ne pouvez pas ajouter n'importe quel objet à un List<?>
. D'autre part, depuis la crue de type List
n'a pas de type de sécurité, vous pouvez add
n'importe quoi à un List
.
Considérons la suite de la variation de l'extrait précédent:
static void appendNewObject(List<?> list) {
list.add(new Object()); // compilation error!
}
//...
List<String> names = new ArrayList<String>();
appendNewObject(names); // this part is fine!
Le compilateur fait un excellent travail de vous protéger contre les violations potentielles du type de l'invariance de la List<?>
! Si vous aviez déclaré le paramètre comme la crue de type List list
, alors le code à compiler, et vous violez le type d'invariant de List<String> names
.
Si c'est dangereux, pourquoi est-il autorisé à utiliser une crue de type?
Voici une autre citation de JLS 4.8:
L'utilisation de matières premières des types est autorisé uniquement comme une concession à la compatibilité du code de legs. L'utilisation de matières premières des types dans le code écrit après l'introduction de genericity dans le langage de programmation Java est fortement déconseillée. Il est possible que les futures versions de Java langage de programmation permettra d'interdire l'utilisation de matières premières des types.
Efficace Java 2nd Edition dispose également d'ajouter:
Étant donné que vous ne devriez pas utiliser des types, pourquoi la langue des concepteurs de leur permettre? 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 y avait une énorme quantité de code Java dans l'existence, qui n'a pas utiliser des génériques. Il a été jugé essentiel que tout ce code demeure légale et interopérable avec le nouveau code qui n'utiliser des génériques. Il a dû être légal de faire passer les instances de type paramétré à des méthodes qui ont été conçus pour une utilisation avec des types, et vice versa. Cette condition, connue comme la migration de compatibilité, a conduit à la décision de prendre en charge les types.
En résumé, raw types ne doit JAMAIS être utilisé dans le nouveau code. Vous devriez toujours utiliser le type paramétré.
Il n'y a pas des exceptions?
Malheureusement, parce que Java génériques sont non-réifié, il y a deux exceptions où les types doivent être utilisés dans le nouveau code:
- Classe littéraux, par exemple,
List.class
, pasList<String>.class
-
instanceof
opérande, par exemple,o instanceof Set
, paso instanceof Set<String>
Voir aussi
Ce sont crus types en Java, et pourquoi j'entends souvent dire qu'ils ne devraient pas être utilisés dans le nouveau code?
Raw-types sont de l'histoire ancienne de la langue de Java. Au début il y avait des Collections et ils ont tenu Objets rien de plus et rien de moins. Chaque opération sur les collections nécessaires jette de l'Objet pour le type désiré.
List aList = new ArrayList(); String s = "Hello World!"; aList.add(s); String c = (String)aList.get(0);
Bien que cela a fonctionné la plupart du temps, les erreurs ne se produisent
List aNumberList = new ArrayList(); String one = "1";//Number one aNumberList.add(one); Integer iOne = (Integer)aNumberList.get(0);//Insert ClassCastException here
L'ancien sans type de collections ne pouvaient pas faire valoir de sécurité du type de sorte que le programmeur devait se rappeler ce qu'il a stockées au sein d'une collection.
Les génériques où inventé pour contourner cette limitation, le développeur devra déclarer la stockées type une fois le compilateur pourrait le faire à la place.List<String> aNumberList = new ArrayList<String>(); aNumberList.add("one"); Integer iOne = aNumberList.get(0);//Compile time error String sOne = aNumberList.get(0);//works fine
Pour La Comparaison:
// Old style collections now known as raw types List aList = new ArrayList(); //Could contain anything // New style collections with Generics List<String> aList = new ArrayList<String>(); //Contains only Strings
Plus complexe, le Compareable interface:
//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<MyCompareAble> { int id; public int compareTo(MyCompareAble other) {return this.id - other.id;} }
Notez qu'il est impossible de mettre en œuvre la CompareAble interface avec compareTo(MyCompareAble) avec des types. Pourquoi vous ne devriez pas les utiliser:
- Tout Objet stocké dans une collection doit être jeté avant de pouvoir être utilisé
- L'utilisation de génériques permet de compiler des contrôles de
- À l'aide de matières types est le même que le stockage de chaque valeur en tant qu'Objet
Ce que le compilateur n': Les génériques sont rétro-compatibles, ils utilisent les mêmes classes java bruts des types. La magie se produit généralement au moment de la compilation.
List<String> someStrings = new ArrayList<String>(); someStrings.add("one"); String one = someStrings.get(0);
Seront compilés en tant que:
List someStrings = new ArrayList(); someStrings.add("one"); String one = (String)someStrings.get(0);
C'est le même code que vous écrirez si vous avez utilisé les raw directement les types de. Pensais que je ne suis pas sûr de ce qui se passe avec le CompareAble interface, je suppose que ça crée deux compareTo fonctions, l'une tenant un MyCompareAble et l'autre de prendre un Objet et de le transmettre à la première après la coulée.
Quelles sont les alternatives à raw types: Utilisation des génériques
Un raw type est le nom générique d'une classe ou d'une interface sans n'importe quel type d'arguments. Par exemple, étant donné le générique de la classe de Boîte:
public class Box<T> {
public void set(T t) { /* ... */ }
// ...
}
Pour créer un paramétrée type d' Box<T>
, vous offre un réel argument de type pour le type formel paramètre T
:
Box<Integer> intBox = new Box<>();
Si le type de l'argument est omis, vous créez une crue de type d' Box<T>
:
Box rawBox = new Box();
Par conséquent, Box
est la crue de type de type générique, Box<T>
. Cependant, un non-générique de la classe ou de type d'interface n'est pas une crue de type.
Raw types apparaître dans l'ancien code, parce que beaucoup de classes de l'API (tels que les Collections de classes) ne sont pas génériques avant JDK 5.0. Lors de l'utilisation de raw types de, vous avez essentiellement obtenir une pré-génériques de comportement - Box
vous donne Object
s. Pour des raisons de compatibilité ascendante, l'affectation paramétrée type de crue type est autorisé:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox; // OK
Mais si vous affectez une crue de type d'un type paramétré, vous obtenez un avertissement:
Box rawBox = new Box(); // rawBox is a raw type of Box<T>
Box<Integer> intBox = rawBox; // warning: unchecked conversion
Vous bénéficiez également d'un avertissement si vous utilisez une crue de type d'invoquer des méthodes génériques définies dans le type générique:
Box<String> stringBox = new Box<>();
Box rawBox = stringBox;
rawBox.set(8); // warning: unchecked invocation to set(T)
L'avertissement indique que les types de dérivation de type générique, de contrôles, de reporter la prise de risque du code à l'exécution. Par conséquent, vous devez éviter d'utiliser raw types.
Le Type d'Effacement de l'article a plus d'informations sur la façon dont le compilateur Java utilise raw types.
Décoché Les Messages D'Erreur
Comme mentionné précédemment, lorsque l'on mélange de l'héritage de code avec le code générique, vous pouvez rencontrer des messages d'avertissement semblable au suivant:
Note: Example.java utilise non contrôlée ou activités dangereuses.
Remarque: Recompiler avec -Xlint:désactivée pour plus de détails.
Cela peut se produire lorsque vous utilisez une ancienne API qui fonctionne sur des types, comme le montre l'exemple suivant:
public class WarningDemo {
public static void main(String[] args){
Box<Integer> bi;
bi = createBox();
}
static Box createBox(){
return new Box();
}
}
Le terme "unchecked" signifie que le compilateur n'a pas suffisamment d'informations pour effectuer toutes les vérifications de type nécessaires pour assurer la sécurité de type. "Unchecked" l'avertissement est désactivé par défaut, si le compilateur donne un indice. Pour voir tous les "unchecked" mises en garde, de recompiler avec -Xlint:décoché.
La recompilation de l'exemple précédent avec -Xlint:décoché 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 incontrôlée des avertissements, utilisez l'option-Xlint:-case à cocher drapeau. L' @SuppressWarnings("unchecked")
d'annotation supprime pas cochée avertissements. Si vous n'êtes pas familier avec l' @SuppressWarnings
de la syntaxe, voir les Annotations.
Source d'origine: Java Tutoriels
Le compilateur veut que vous écrivez ceci:
private static List<String> list = new ArrayList<String>();
parce que sinon, vous pouvez ajouter n'importe quel type que vous aimez dans list
, faisant de l'instanciation comme new ArrayList<String>()
inutile. Java les génériques sont une compilation de fonctionnalité, de sorte qu'un objet créé avec new ArrayList<String>()
accepterions volontiers Integer
ou JFrame
éléments s'ils sont affectés à une référence de la "crue de type" List
- l'objet lui-même ne sait rien au sujet de quels types il est censé contenir, seul le compilateur ne.