Question

Si je déclare une classe comme un champ:

Class fooClass;

Eclipse me donne l'avertissement:

  

La classe est un type brut. Les références à   Classe de type générique devrait être   paramétrée

Qu'est-ce que cela signifie concrètement? et pourquoi suis-je exhortés à le faire? Si je demande à Eclipse pour une « solution rapide » il me donne:

Class<?> fooClass;

qui ne semble pas ajouter beaucoup de valeur, mais ne donne plus un avertissement.

EDIT: Pourquoi est-classe générique? Pourriez-vous s'il vous plaît donner un exemple de paramétrage, à savoir pourrait y avoir une utilisation valable autre chose que <?>?

EDIT: WOW! Je ne l'avais pas réalisé les profondeurs de cela. J'ai aussi regardé Java Puzzler et ça me fait peur certainement sur les pièges à ours. Je vais donc toujours utiliser

Class<MyString> myStringClass = MyString.class;

plutôt que

Class myStringClass = MyString.class;

(Mais après avoir utilisé Java à partir d'un jour, je ne l'ai pas vraiment avis quand la classe est devenu générique);

NOTE: Je @oxbow_lakes acceptées comme cela a du sens pour moi, mais il est clairement un domaine très complexe. J'exhorte tous les programmeurs à utiliser la Class<MyString> spécifique plutôt que Class. Et Class<?> est beaucoup plus sûr que Class.

Était-ce utile?

La solution

Types premières et Unbounded Wildcards

Aucune des réponses précédentes ont vraiment abordé pourquoi vous devriez préférer Class<?> sur Class, comme sur le visage de celui-ci, l'ancien semble offrir plus d'informations que celui-ci.

La raison en est que, le type brut , à savoir Class, empêche le compilateur d'effectuer un contrôle de type générique. Autrement dit, si vous utilisez des types premières, subvertir le type système . Par exemple:

public void foo(Class<String> c) { System.out.println(c); }

Peut-on appeler thusly (il sera à la fois la compilation et run):

Class r = Integer.class
foo(r); //THIS IS OK (BUT SHOULDN'T BE)

Mais pas par:

Class<?> w = Integer.class
foo(w); //WILL NOT COMPILE (RIGHTLY SO!)

En utilisant toujours la forme non brute, même si vous devez utiliser ? parce que vous ne pouvez pas savoir ce que le paramètre de type est (ou est limitée par), vous permettez au compilateur de raisonner sur l'exactitude de votre programme plus complètement que si vous avez utilisé les types premières.


Pourquoi Types brutes du tout?

Le Java Language Specification indique:

  

L'utilisation de types bruts est autorisée uniquement comme une concession à la compatibilité du code existant

Vous devriez toujours les éviter. Le caractère générique ? est probablement mieux unbounded décrit ailleurs, mais essentiellement des moyens « cela est paramétrés sur un certain type, mais je ne sais pas (ou de soins), il est » . Ce ne sont pas les mêmes que types premières , qui sont une abomination et n'existe pas dans d'autres langues avec les génériques, comme Scala .


Pourquoi classe paramétrés?

Eh bien, voici un cas d'utilisation. Supposons que j'ai une interface de service:

public interface FooService

Et je veux injecter une mise en œuvre de celui-ci, en utilisant une propriété système pour définir la classe à utiliser.

Class<?> c = Class.forName(System.getProperty("foo.service"));

Je ne sais pas à ce moment que ma classe, est de la bonne type :

//next line throws ClassCastException if c is not of a compatible type
Class<? extends FooService> f = c.asSubclass(FooService.class); 

Maintenant, je peux instancier un FooService:

FooService s = f.newInstance(); //no cast

Autres conseils

  

qui ne semble pas ajouter beaucoup de valeur   mais ne donne plus un avertissement.

Vous avez raison. Mais cela pourrait ajouter de la valeur:

Class<FooClass> fooClass;

ou, si plus approprié:

Class<? extends FooClass> fooClass;

ou

Class<FooInterface> fooClass;

Comme génériques en général, vous pouvez améliorer la sécurité de type en spécifiant quel genre de la classe que vous souhaitez que la variable attente. La mise en garde contre les types premières est juste destiné à attraper des morceaux de code où ce potentiel est pas utilisé. En déclarant Class<?> vous dites essentiellement «c'est signifie pour tout type de classe ».

Parce que, depuis 5 JDK, Class a maintenant le type paramétrées, ce qui fait Class un objet générique. Cela est nécessaire (depuis l'introduction de médicaments génériques) pour le compilateur de faire la vérification de type (au moment de la compilation, bien sûr).

Class<?> signifie une « classe inconnue » où ? est un générique générique . Cela signifie que fooClass de type Class<?> accepte un Class dont le type correspond à tout.

Exemple typique:

Class<?> classUnknown = null;
classUnknown = ArrayList.class; //This compiles.

Vous pouvez, effectivement, à condition d'un type paramétrées pour être plus précis, par exemple:.

Class<ArrayList> = ArrayList.class;

PS Gardez à l'esprit que Class<List> listClass = ArrayList.class; ne compilera pas (même si ArrayList est de la liste), mais (comme Mark Peters mentionné sur le commentaire) Class<? extends List> listClass = ArrayList.class; ne compile (grâce au caractère générique).

Le Javadoc du classe classe ne donne une idée de la raison pour laquelle des paramètres de type existent pour cette classe:

  

T - le type de la classe modélisé par   cet objet Class. Par exemple, la   type de String.class est Class<String>.   Utilisez Class<?> si l'être de classe   modelée est inconnue.

L'utilisation de ce type de paramètre est pas évident, mais un rapide coup d'oeil au code source de la classe, indique pourquoi le paramètre de type est parfois nécessaire. Pensez à la mise en œuvre de la méthode newInstance:

    public T newInstance() 
        throws InstantiationException, IllegalAccessException
    {
    if (System.getSecurityManager() != null) {
        checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader());
    }
    return newInstance0();
    }

Si l'on n'a pas remarqué, le type de l'objet retourné par cette méthode est celle du paramètre de type. Ceci est utile dans le code qui utilise beaucoup de réflexion, et où l'on voudrait être instancié sont très prudent de faire en sorte que les objets du type droit.

En considérant l'exemple dans la question, si l'instance de classe a été déclarée à la place:

Class<String> fooClass;
Class<Integer> barClass;
String aString;

puis, il est presque impossible d'avoir le code suivant pour compiler:

aString = barClass.newInstance();

En bref, si vous allez travailler avec des hiérarchies de classes et que vous souhaitez imposer des contrôles des délais stricts de compilation pour vous assurer que votre code n'a pas besoin d'effectuer beaucoup de contrôles de instanceof, alors vous êtes mieux préciser la type de la classe que vous souhaitez utiliser. Spécification ? permet à tous les types, mais il y aurait des cas où vous aurez besoin d'être plus précis.

Parce que l'utilisation de types bruts au lieu de types paramétrés a de nombreux pièges.

L'un qui est que si un type bruts, tous les génériques sur la classe sont perdus. Même ceux qui sont définis par méthode.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top