2011-09-14 5 views
4

Où est la différence entre test1 et test2? Pourquoi erreur de compilation dans test1?Erreur de compilation avec générique

import java.util.ArrayList; 
import java.util.Collection; 

class MyType { 

} 

class MyClass<T> { 
    private Collection<MyType> myTypes = new ArrayList<MyType>(); 
    private Collection<T> myTs = new ArrayList<T>(); 

    public Collection<MyType> getMyTypes() { 
     return myTypes; 
    } 

    public Collection<T> getMyTs() { 
     return myTs; 
    } 
} 



public class TestSimple { 

    public void test1() {  

     MyClass myClass = new MyClass(); 

     for (MyType myType : myClass.getMyTypes()) { 

     } 
    } 

    public void test2() {    
     MyClass myClass = new MyClass(); 

     Collection<MyType> myTypes = myClass.getMyTypes(); 
     for (MyType myType : myTypes) { 

     } 
    } 

    public void test3() { 
     MyClass<Long> myClass = new MyClass<Long>(); 

      for (Long myType : myClass.getMyTs()) { 

      }   
    } 

} 
+5

Pourquoi utilisez-vous 'MyClass' non paramétré dans test1 et test2? –

+0

Parce que je ne sais rien sur le type. Java permet cette utilisation. – Alex

+0

Mais si j'ai "Collection publique getMyTypes()" J'attends collection de MyType – Alex

Répondre

4

Si vous définissez une contrainte générique sur une classe, puis instancier la classe sans fournir aucune contrainte générique (qui est, vous omettez le <> complètement), vous Je suis juste entré dans le royaume de Raw Types, où plus rien n'est pareil.

Selon le Java Language Spec:

The use of raw types is allowed only as a concession to compatibility of legacy code. The use of raw types in code written after the introduction of genericity into the Java programming language is strongly discouraged. It is possible that future versions of the Java programming language will disallow the use of raw types.

Selon excellente de Angelika Langer Java Generics FAQ,

Methods or constructors of a raw type have the signature that they would have after type erasure. A method or constructor call to a raw type generates an unchecked warning if the erasure changes the argument types.

Donc en construisant MyClass comme un type brut (qui est, comme MyClass et non MyClass<?>), vous avez désactivé complètement les génériques, et le type de retour de getMyTypes() est maintenant le type brut Collection, et non Collection<MyType>. Par conséquent, vous ne pouvez pas utiliser la syntaxe améliorée for avec le type MyType, vous devrez utiliser Object à la place.

Bien sûr, la meilleure solution consiste simplement à utiliser MyClass<?> (plutôt que seulement MyClass) lorsque vous voulez dire un MyClass d'un type paramétré inconnu.

+0

merci pour la réponse complète – Alex

0

En test2 puisque vous avez pas paramétrées MyClass, getMyTypes() renverra effectivement Collection<Object>, qui est incessible à Collection<MyType>.

+0

Pourquoi devrait-il besoin d'être paramétrés pour la méthode 'Collection publique getMyTypes()' à paramerterized à 'MyType'? Par exemple, si vous supprimez '' sur 'MyType' et supprimez' Collection getMyTs() 'et supprimez' void test2() 'et' void test3() 'il compile très bien. – corsiKa

+0

@glowcoder oui, mais j'ai "Collection myTs = new ArrayList ();" aussi et il ne peut pas être retiré – Alex

+0

@Alex voir ma réponse ci-dessous. Le problème se manifeste encore même sans ceux-là. – corsiKa

2

J'ai isolé votre problème à un petit exemple, que je montre ci-dessous

import java.util.*; 

public class TestSimple { 

    static class MyClass<T> { 
     private Collection<String> myTypes = new ArrayList<String>(); 

     public Collection<String> getMyTypes() { 
      return myTypes; 
     } 
    } 

    public void test1() {  
     MyClass myClass = new MyClass(); 
     for (String myType : myClass.getMyTypes()) { 
     } 
    } 
} 

Je soupçonne que toutes les informations de type est enlevé à moins que vous dire spécifiquement autrement. Donc, ma suggestion est de changer votre déclaration:

before: MyClass myClass = new MyClass(); 
after: MyClass<?> myClass = new MyClass(); 
+0

Hm .. Ça a l'air génial. Merci – Alex

2

Java est trop dur sur les types bruts. Si vous utilisez un type brut de classe générique, toutes les informations génériques de la classe sont ignorées, même celles qui n'ont rien à voir avec les paramètres de type de la classe.

class A<T> implements List<String> 

    Set<Integer> var; 

Si vous utilisez A brut, il est alors traiter comme

class A implements List 

    Set var; 

Ce traitement dure n'est pas nécessaire; ils ne pensaient probablement pas que les types bruts méritaient trop de ressources, alors ils ont pris la route facile, effacer toutes les informations génériques des types bruts sans discernement.

+0

+ 1 Intéressant, je n'avais pas réalisé que sur les types bruts. Devrait probablement changer 'List' en' ArrayList' ou une autre non-interface dans l'exemple. En outre, il ressemble à un type brut implémentant une interface générique de la même manière * * * conserve ces informations de type. Je me demande quelle était la distinction derrière cette décision. –

+1

pour 'A' être brut, il doit être une classe générique en premier. si 'la classe A étend B ', 'A' n'est pas brut, car A n'est même pas générique. – irreputable

Questions connexes