2009-01-26 5 views
8

Ich besitze derzeit eine Liste von Objekten (mit Java 1.3), und sagen wir, dass ich eines der Objekte aus list.get (i) zu einem Typ, von dem ich nur den Namen der Klasse als String kenne. Im Wesentlichen, wie kann ich Object o = (Klassenname) list.get (i); Dabei ist Klassenname eine String-Variable eines Klassennamens.Casting zu unbekanntem Typ Wenn Klassenname nur als String dieses Typs gegeben wird

Ich dachte, dass ich (Class.forName (className)) list.get (i) verwenden könnte, aber ich erhielt einen Syntaxfehler, der behauptet, dass ich ein Semikolon vergessen habe.

Leider, da ich Java 1.3 verwende, habe ich keinen Zugriff auf die Class.cast (Object) -Methode.

Wie lautet der Name der Klasse, die beim Umwandeln in Java 1.3 verwendet wird? Gibt es eine Methode, die mir den korrekten Typ, den ich brauche, mit einem String-Parameter des Klassennamens geben kann?

+0

Wenn Sie Ihre Version von Java aktualisieren, gehen Sie direkt zu Java 6, da Java 5 im Oktober EOL sein wird. : -] –

Antwort

5

Nein, und Sie können dies in den meisten Sprachen nicht tun.

Der Grund dafür ist, dass der Typ, in den umgewandelt werden soll, zur Kompilierzeit bekannt sein muss, nicht zur Laufzeit (was Sie gerade versuchen).

Wenn Sie darüber nachdenken, macht es Sinn, denn da die Variable einen beliebigen Typnamen haben kann, wie sollen Sie auf die verschiedenen Mitglieder zugreifen? Dies ist nicht möglich, es sei denn, sie sind in einem Basistyp/Interface definiert, den alle Instanzen implementieren. In diesem Fall sollten Sie nur dieses verwenden.

1

Ich nehme an, dass Sie wirklich Folgendes schreiben wollten, anstatt Object auf der linken Seite zu verwenden. Ansonsten geht es nur darum zu prüfen, ob das Objekt in der Liste den richtigen Typ hat.

ClassName o = (classname)list.get(i); 

Nun, Java ist statisch getippt. Es ist nicht möglich, dass Sie ihm eine Zeichenfolge geben, und es gibt Ihnen den entsprechenden statischen Typ, so dass Sie ohne Casting gehen können. Auch bei Generics und Class<T>.cast wird der Cast-Zieltyp nicht durch eine Zeichenfolge angegeben, sondern durch das generische Typargument T, das zur Kompilierzeit bekannt ist. Sie müssen manuell in den richtigen Typ umwandeln oder den gebräuchlichsten Typ verwenden (in Ihrem Fall möglicherweise Objekt).

Wenn Sie Class.forName(className) tun, gibt es Ihnen wieder ein Objekt des Typs Class, die Informationen über den Typ zur Laufzeit enthält, so dass es Ihnen

Class.forName("my.stuff.MyClass").newInstance() 

zu tun, erlaubt aber die Besetzung eine Art will - nicht ein Objekt irgendeiner Art. Deshalb hat der Compiler Ihnen gesagt, dass etwas mit diesem Code nicht stimmt.

Der statische Typ der von diesem zurückgegebenen Referenz lautet Object. Dies ist wichtig: Der dynamische Typ eines Objekts, auf das verwiesen wird, und der statische Typ der Referenz, die auf dieses Objekt verweist. Der dynamische Typ des Objekts ist, was durch einen String "gesteuert" werden kann (durch Verwendung von Class.forName), aber der statische Typ des Verweises, den Sie zur Kompilierungszeit haben müssen, und der (um nur ein Beispiel zu nennen) verwendet wird um Funktionen auszuwählen, die sich gegenseitig überlasten, kann nicht durch eine Zeichenkette bestimmt werden.

10

Worauf kommt es an, wenn Sie nur das Ergebnis dem Objekt zuweisen? Alles, was Sie erreichen würden, wäre eine Ausnahme, wenn es nicht die Schnittstelle/extend implementiert hätte oder die Klasse war oder gar nichts getan hätte.

Dazu ein einfaches:

public static boolean IsInstance(object x, String className) 
    { 
    Class cls = Class.forName(className); 
    return cls.isInstance(x); 
    } 

ausreichend (und sauberer)

Wenn Sie auf die Verwendung Reflexion waren auf den Feldern zu erhalten/Methoden der Klasse, die gerade fein ist

+0

Das ist genau der Punkt --- schnell, mit einer Ausnahme, genau dort, wo das Problem ist, eher als einige unbestimmte spätere Zeit und Ort. – erickson

+0

Danke !!! Das war sehr hilfreich –

0

Die Frage war answered bereits, aber ich möchte hinzufügen, dass es ein wenig zweifelhaft scheint, dass Sie eine Liste haben sollten, in der Sie mehrere verschiedene Arten von Objekten (in diesem Fall beliebige Objekte) halten, aber Sie würden ein bitte rufen Sie Operationen auf, die spezifisch für jeden unterschiedlichen Typ sind ...

Was ist der Sinn dieser Sammlung? Haben die Instanzen, die Sie darin aufbewahren, nicht gemeinsam irgendetwas - irgendeinen üblichen Supertyp, in den Sie sie werfen könnten?

2

Ein Szenario, in dem dies erforderlich ist, ist die Durchsetzung der Typensicherheit mit einem Legacy-System. Angenommen, Sie haben ein Persistenzsystem wie Hibernate, das eine rohe List Ergebnisse von einer "Finder" -Methode bietet. Wird dieser rohe List in einen parametrisierten Typ umgewandelt, führt dies zu einer ungeprüften Warnung, und wenn die Liste ein Objekt des falschen Typs enthält, kann zu einem unbestimmten Zeitpunkt in einem entfernt verwandten Code ClassCastException ausgelöst werden. Es ist vielleicht am besten, den Inhalt der Liste zu validieren, indem Sie einen Mechanismus verwenden, wie er vom OP vorgeschlagen wird.

Hier ist die Java-Version 1.3 (ohne Generika):

private static void checkType(Collection objs, String className) 
    throws ClassNotFoundException 
{ 
    Class clz = Class.forName(className); 
    Iterator i = objs.iterator(); 
    while (i.hasNext()) { 
    Object obj = i.next(); 
    if (!clz.isInstance(obj)) { 
     throw new ClassCastException(); 
    } 
    } 
} 

In Java 5 und später mit Generika, können Sie etwas ähnliches mit der Class.cast() Methode zu tun, den Inhalt einer Sammlung, um zu überprüfen, die Verwendung rechtfertigen einer SuppressWarns-Annotation. In unserem Überprüfungsprozess wird das Unterdrücken einer Warnung ohne einen "Beweis", dass sie sicher ist, als Fehler gespeichert.

Verwandte Themen