Frage

Wenn ich deklarieren eine Klasse als ein Feld:

Class fooClass;

Eclipse-gibt mir die Warnung:

  

Klasse ist eine rohe Art. Verweise auf   generischer Typ Klasse sollte   parametrisierte

Was bedeutet das in der Praxis? und warum bin ich es zu tun gedrängt? Wenn ich von Eclipse bitte um eine „schnelle Lösung“ es gibt mir:

Class<?> fooClass;

das scheint nicht zu viel Wert hinzufügen, aber nicht mehr gibt eine Warnung aus.

EDIT: Warum ist Klasse generic? Könnten Sie bitte ein Beispiel für die Parametrierung geben, das heißt, es könnte eine gültige Verwendung von etwas anderes als <?>?

EDIT: WOW! Ich hatte die Tiefen dieser nicht realisiert. Ich habe auch die Java-Puzzler beobachtet und es wird sicherlich mir über die Bärenfallen Angst. So werde ich immer mit

Class<MyString> myStringClass = MyString.class;

statt

Class myStringClass = MyString.class;

(Aber Java vom ersten Tag benutzt zu haben, ich habe bemerkt, nicht wirklich, wenn Klasse wurde allgemein);

Hinweis: Ich habe akzeptiert @oxbow_lakes da dies macht Sinn für mich, aber es ist eindeutig ein sehr kompliziertes Gebiet. Ich möchte alle Programmierer fordert die spezifische Class<MyString> zu verwenden, anstatt Class. Und Class<?> ist viel sicherer als Class.

War es hilfreich?

Lösung

Raw-Typen und Unbounded Wildcards

Keine der bisherigen Antworten haben wirklich angesprochen, warum Sie Class<?> über Class vorziehen sollte, wie auf dem Gesicht von ihm, scheint die Erstgenannte nicht mehr Informationen als die letztere zu bieten.

Der Grund, das heißt, die roh Typ , das heißt Class, verhindert, dass der Compiler von Herstellung generischen Typ überprüft. Das heißt, wenn Sie rohe Typen verwenden, Sie subvert der Typ-System . Zum Beispiel:

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

Kann thusly aufgerufen werden (es wird sowohl die Kompilierung und run):

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

Aber nicht durch:

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

Mit dem immer die Nicht-Rohform verwendet wird, auch wenn Sie ? verwenden muss, weil Sie nicht wissen, was der Typ-Parameter ist (oder wird begrenzt durch), können Sie den Compiler Grund, sich über die Richtigkeit des Programms vollständiger erlauben, als wenn Sie verwendeten Ausgangstypen.


Warum überhaupt Raw-Typen haben?

Die Java Language Specification sagt:

  

Die Verwendung von rohen Arten darf nur als Zugeständnis an der Kompatibilität von Legacy-Code

Sie sollten immer sie vermeiden. Die unbeschränkten Wildcard ? ist wahrscheinlich am besten an anderer Stelle, aber im Wesentlichen Mittel beschrieben „Das ist auf irgendeine Art parametriert, aber ich weiß nicht (oder Pflege), was es ist“ . Dies ist nicht das Gleiche wie rohe Typen , die ein Greuel sind und existieren nicht in anderen Sprachen mit Generika, wie Scala .


Warum ist Klasse Parameterized?

Nun, hier ist ein Anwendungsfall. Angenommen, ich eine Service-Schnittstelle haben:

public interface FooService

Und ich mag eine Implementierung davon injizieren, eine Systemeigenschaft mit der Klasse zu definieren, verwendet werden.

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

Ich weiß nicht, an dieser Stelle, dass meine Klasse, ist die korrekte type :

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

Jetzt kann ich eine FooService instanziiert:

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

Andere Tipps

  

das scheint nicht zu viel Wert hinzufügen   aber nicht mehr gibt eine Warnung aus.

Sie haben Recht. Aber dies könnte Wert hinzu:

Class<FooClass> fooClass;

oder, wenn geeignetere:

Class<? extends FooClass> fooClass;

oder

Class<FooInterface> fooClass;

Wie bei Generika in der Regel können Sie Typsicherheit durch Angabe verbessern, welche Art der Klasse Sie die Variable halten wollen. Die Warnung vor rohen Arten soll nur Teile des Codes fangen, wo dieses Potenzial nicht genutzt wird. Durch die Deklaration Class<?> sind Sie im Grunde sagen: „Das ist bedeutet jede Art von Klasse zu halten“.

Da, da JDK 5, Class jetzt parametrisierte Typ hat haben, das macht ein generisches Objekt Class. Dies ist notwendig, (seit der Einführung von Generika) für den Compiler Typprüfung (bei der Kompilierung, natürlich).

zu tun

Class<?> bedeutet eine „Klasse von unbekannten“ wo ? ein Generika Wildcard . Es bedeutet ein, dass fooClass vom Typ Class<?> einen Class Typ, dessen akzeptiert passt alles.

Typisches Beispiel:

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

Sie können, effektiv, einen parametrisierte Typen vorgesehen genauer zu sein, z.

Class<ArrayList> = ArrayList.class;

PS Beachten Sie, dass Class<List> listClass = ArrayList.class; nicht kompiliert (obwohl Arraylist ist der Liste), aber (als Mark Peters auf den Kommentar erwähnt) Class<? extends List> listClass = ArrayList.class; tut Kompilierung (dank der Wildcard).

Die Javadoc der Klasse Klasse nicht gibt eine Vorstellung darüber, warum Typ-Parameter existieren für diese Klasse:

  

T - der Typ der Klasse modelliert   Dieses Class Objekt. Zum Beispiel kann die   Typ String.class ist Class<String>.   Verwenden Class<?>, wenn die Klasse Wesen   modellierten ist nicht bekannt.

Die Verwendung dieses Typs Parameter ist nicht so offensichtlich, aber ein flüchtiger Blick auf den Quellcode der Klasse zeigt, warum der Typ-Parameter manchmal notwendig ist. Betrachten sie die Umsetzung der newInstance Methode:

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

Wenn man nicht bemerkt hat, die Art des Objekts von dieser Methode zurück ist, dass die Typ-Parameter. Dies ist nützlich, in Code, der viel Reflexion nutzt, und wo man besonders vorsichtig sein möchte, dass Objekte von der richtigen Art, um sicherzustellen, instanziiert wird.

Am Beispiel in der Frage, ob die Klasseninstanz statt wie erklärt wurde:

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

dann ist es fast unmöglich, den folgenden Code zu haben, zu kompilieren:

aString = barClass.newInstance();

Kurz gesagt, wenn Sie gehen mit Klassenhierarchien zu arbeiten und Sie wollen strenge Kontrollen der Kompilierung verhängen, um sicherzustellen, dass der Code nicht viel instanceof Kontrollen durchführen muss, dann sind Sie besser dran, die Angabe Typ der Klasse, die Sie verwenden möchten. Angeben ? alle Arten erlaubt, aber es gäbe Fälle, wenn Sie präziser sein müssen.

Da mit rohen Typen statt parametrisierte Typen hat viele Tücken.

Eines davon ist, dass, wenn eine rohe Art verwendet wird, werden alle Generika auf die Klasse verloren. Selbst diejenigen, die pro-Methode.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top