Wie können Sie in Java einen Typ als Parameter übergeben (oder als Variable deklarieren)?
Ich möchte keine Instanz des Typs übergeben, sondern den Typ selbst (z. B. int, String usw.).
In C # kann ich das tun:
private void foo(Type t)
{
if (t == typeof(String)) { ... }
else if (t == typeof(int)) { ... }
}
private void bar()
{
foo(typeof(String));
}
Gibt es in Java einen Weg, ohne eine Instanz vom Typ t zu übergeben?
Oder muss ich meine eigenen int-Konstanten oder Aufzählungen verwenden?
Oder gibt es einen besseren Weg?
Bearbeiten: Hier ist die Anforderung für foo:
Basierend auf Typ t wird eine andere kurze XML-Zeichenfolge generiert.
Der Code im if / else ist sehr klein (ein oder zwei Zeilen) und verwendet einige private Klassenvariablen.
Antworten:
Sie könnten ein
Class<T>
in übergeben.private void foo(Class<?> cls) { if (cls == String.class) { ... } else if (cls == int.class) { ... } } private void bar() { foo(String.class); }
Update : Der OOP-Weg hängt von den funktionalen Anforderungen ab. Am besten wäre es, eine Schnittstelle zu definieren
foo()
und zwei konkrete Implementierungen zu implementierenfoo()
und dann einfachfoo()
die Implementierung aufzurufen, die Sie zur Hand haben. Ein anderer Weg könnte ein sein, überMap<Class<?>, Action>
den Sie anrufen könnenactions.get(cls)
. Dies lässt sich leicht mit einer Schnittstelle und konkreten Implementierungen kombinieren :actions.get(cls).foo()
.quelle
String
ist keinClass<?> cls
in etwas anderem als Vergleich verwenden. Während Sie nicht schreiben können:cls value = (cls) aCollection.iterator().next();
Sie können cls.cast (aCollection.iterator (). Next ()) aufrufen; Klasse JavadocIch hatte eine ähnliche Frage, daher habe ich unten eine vollständige ausführbare Antwort ausgearbeitet. Ich musste eine Klasse (C) an ein Objekt (O) einer nicht verwandten Klasse übergeben und dieses Objekt (O) neue Objekte der Klasse (C) an mich zurücksenden lassen, wenn ich danach fragte.
Das folgende Beispiel zeigt, wie dies gemacht wird. Es gibt eine MagicGun-Klasse, die Sie mit einem beliebigen Subtyp der Projectile-Klasse (Pebble, Bullet oder NuclearMissle) laden. Das Interessante ist, dass Sie es mit Untertypen von Projectile laden, aber nicht mit tatsächlichen Objekten dieses Typs. Die MagicGun erstellt das eigentliche Objekt, wenn es Zeit zum Schießen ist.
Die Ausgabe
You've annoyed the target! You've holed the target! You've obliterated the target! click click
Der Code
import java.util.ArrayList; import java.util.List; public class PassAClass { public static void main(String[] args) { MagicGun gun = new MagicGun(); gun.loadWith(Pebble.class); gun.loadWith(Bullet.class); gun.loadWith(NuclearMissle.class); //gun.loadWith(Object.class); // Won't compile -- Object is not a Projectile for(int i=0; i<5; i++){ try { String effect = gun.shoot().effectOnTarget(); System.out.printf("You've %s the target!\n", effect); } catch (GunIsEmptyException e) { System.err.printf("click\n"); } } } } class MagicGun { /** * projectiles holds a list of classes that extend Projectile. Because of erasure, it * can't hold be a List<? extends Projectile> so we need the SuppressWarning. However * the only way to add to it is the "loadWith" method which makes it typesafe. */ private @SuppressWarnings("rawtypes") List<Class> projectiles = new ArrayList<Class>(); /** * Load the MagicGun with a new Projectile class. * @param projectileClass The class of the Projectile to create when it's time to shoot. */ public void loadWith(Class<? extends Projectile> projectileClass){ projectiles.add(projectileClass); } /** * Shoot the MagicGun with the next Projectile. Projectiles are shot First In First Out. * @return A newly created Projectile object. * @throws GunIsEmptyException */ public Projectile shoot() throws GunIsEmptyException{ if (projectiles.isEmpty()) throw new GunIsEmptyException(); Projectile projectile = null; // We know it must be a Projectile, so the SuppressWarnings is OK @SuppressWarnings("unchecked") Class<? extends Projectile> projectileClass = projectiles.get(0); projectiles.remove(0); try{ // http://www.java2s.com/Code/Java/Language-Basics/ObjectReflectioncreatenewinstance.htm projectile = projectileClass.newInstance(); } catch (InstantiationException e) { System.err.println(e); } catch (IllegalAccessException e) { System.err.println(e); } return projectile; } } abstract class Projectile { public abstract String effectOnTarget(); } class Pebble extends Projectile { @Override public String effectOnTarget() { return "annoyed"; } } class Bullet extends Projectile { @Override public String effectOnTarget() { return "holed"; } } class NuclearMissle extends Projectile { @Override public String effectOnTarget() { return "obliterated"; } } class GunIsEmptyException extends Exception { private static final long serialVersionUID = 4574971294051632635L; }
quelle
List<Class<? extends Projectile>> projectiles = new ArrayList<Class<? extends Projectile>>()
. Die Projectile-Klasse sollte eine Schnittstelle sein, und die Seriennummer ist für Ihr Beispiel nicht erforderlichOh, aber das ist hässlicher, nicht objektorientierter Code. In dem Moment, in dem Sie "if / else" und "typeof" sehen, sollten Sie an Polymorphismus denken. Dies ist der falsche Weg. Ich denke, Generika sind dein Freund hier.
Mit wie vielen Typen planen Sie umzugehen?
AKTUALISIEREN:
Wenn Sie nur über String und int sprechen, können Sie dies auf folgende Weise tun. Beginnen Sie mit der Schnittstelle XmlGenerator (genug mit "foo"):
package generics; public interface XmlGenerator<T> { String getXml(T value); }
Und die konkrete Implementierung XmlGeneratorImpl:
package generics; public class XmlGeneratorImpl<T> implements XmlGenerator<T> { private Class<T> valueType; private static final int DEFAULT_CAPACITY = 1024; public static void main(String [] args) { Integer x = 42; String y = "foobar"; XmlGenerator<Integer> intXmlGenerator = new XmlGeneratorImpl<Integer>(Integer.class); XmlGenerator<String> stringXmlGenerator = new XmlGeneratorImpl<String>(String.class); System.out.println("integer: " + intXmlGenerator.getXml(x)); System.out.println("string : " + stringXmlGenerator.getXml(y)); } public XmlGeneratorImpl(Class<T> clazz) { this.valueType = clazz; } public String getXml(T value) { StringBuilder builder = new StringBuilder(DEFAULT_CAPACITY); appendTag(builder); builder.append(value); appendTag(builder, false); return builder.toString(); } private void appendTag(StringBuilder builder) { this.appendTag(builder, false); } private void appendTag(StringBuilder builder, boolean isClosing) { String valueTypeName = valueType.getName(); builder.append("<").append(valueTypeName); if (isClosing) { builder.append("/"); } builder.append(">"); } }
Wenn ich dies ausführe, erhalte ich das folgende Ergebnis:
integer: <java.lang.Integer>42<java.lang.Integer> string : <java.lang.String>foobar<java.lang.String>
Ich weiß nicht, ob Sie das im Sinn hatten.
quelle
Sie sollten eine
Class
...private void foo(Class<?> t){ if(t == String.class){ ... } else if(t == int.class){ ... } } private void bar() { foo(String.class); }
quelle
method_foo(Type fooableType)
weniger nützlich sind alsmethod_foo(Class<?> fooableClass)
?Wenn Sie den Typ übergeben möchten, wäre dies das Äquivalent in Java
Wenn Sie eine schwach typisierte Methode verwenden möchten, verwenden Sie einfach
und der entsprechende Operator
instanceof
z.B
private void foo(Object o) { if(o instanceof String) { } }//foo
In Java gibt es jedoch primitive Typen, die keine Klassen sind (dh int aus Ihrem Beispiel), daher müssen Sie vorsichtig sein.
Die eigentliche Frage ist, was Sie hier eigentlich erreichen wollen, sonst ist es schwer zu beantworten:
quelle
Sie können eine Instanz von java.lang.Class übergeben, die den Typ darstellt, d. H.
private void foo(Class cls)
quelle