784 votes

Ce qui est un type de brut et pourquoi ne devrais ' t nous l’utiliser ?

<h3>Questions relatives aux :</h3> <ul> <li>Quels sont les types raw en Java, et pourquoi j’entends souvent dire qu’ils ne devraient pas être utilisés dans le nouveau code ?</li> <li>Quelle est l’alternative si nous ne pouvons pas utiliser les types raw et comment est-ce mieux ?</li> </ul> <h3>Questions similaires</h3> <ul> <li><a href="http://stackoverflow.com/questions/233628/should-java-raw-types-be-deprecated">Java Types Raw devrait être déconseillé ?</a></li> </ul>

856voto

polygenelubricants Points 136838

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 un List<String> pour un paramètre de type List, vous ne pouvez pas passer à un paramètre de type List<Object>. Il y a des règles de sous-typage pour les génériques, et List<String> est un sous-type de la crue de type List, mais pas du type paramétré List<Object>. En conséquence, vous perdez de sécurité de type si vous utilisez raw type List, mais pas si vous utilisez un type paramétré comme List<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, pas List<String>.class
  • instanceof opérande, par exemple, o instanceof Set, pas o instanceof Set<String>

Voir aussi

67voto

josefx Points 8417

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

32voto

Adio Points 1712

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 Objects. 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

20voto

Bozho Points 273663
<pre><code></code><p><p><a href="http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html">médicaments génériques</a> doivent être paramétrées, plutôt que d’utiliser leur forme brute.</p><p><code></code><code></code>. Cela permet de nombreuses opérations de type sécurisé, checkées compilation.</p></pre>

14voto

Michael Borgwardt Points 181658

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.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X