En Java, ¿cómo se puede pasar un tipo como parámetro (o declarar como variable)?
No quiero pasar una instancia del tipo, sino el tipo en sí (por ejemplo, int, String, etc.).
En C #, puedo hacer esto:
private void foo(Type t)
{
if (t == typeof(String)) { ... }
else if (t == typeof(int)) { ... }
}
private void bar()
{
foo(typeof(String));
}
¿Hay alguna forma en Java sin pasar una instancia de tipo t?
¿O tengo que usar mis propias constantes int o enumeración?
¿O hay un mejor camino?
Editar: aquí está el requisito para foo:
basado en el tipo t, genera una cadena xml corta diferente.
El código en if / else será muy pequeño (una o dos líneas) y usará algunas variables de clase privadas.
Respuestas:
Podrías pasar una entrada
Class<T>
.private void foo(Class<?> cls) { if (cls == String.class) { ... } else if (cls == int.class) { ... } } private void bar() { foo(String.class); }
Actualización : la forma OOP depende del requisito funcional. Lo mejor sería definir una interfaz
foo()
e implementar dos implementaciones concretasfoo()
y luego simplemente recurrirfoo()
a la implementación que tenga a mano. Otra forma puede ser por laMap<Class<?>, Action>
que podrías llamaractions.get(cls)
. Esto es fácilmente para ser combinado con una interfaz y implementaciones concretas:actions.get(cls).foo()
.fuente
String
no es un primitivo en Java;)Class<?> cls
en algo más que en la comparación. Si bien no puede escribir:cls value = (cls) aCollection.iterator().next();
puede llamar a cls.cast (aCollection.iterator (). Next ()); Clase javadocTenía una pregunta similar, así que elaboré una respuesta completa ejecutable a continuación. Lo que tenía que hacer era pasar una clase (C) a un objeto (O) de una clase no relacionada y hacer que ese objeto (O) me emitiera nuevos objetos de clase (C) cuando los pedí.
El siguiente ejemplo muestra cómo se hace esto. Hay una clase MagicGun que carga con cualquier subtipo de la clase Proyectil (Pebble, Bullet o NuclearMissle). Lo interesante es que lo cargas con subtipos de Proyectil, pero no con objetos reales de ese tipo. MagicGun crea el objeto real cuando llega el momento de disparar.
La salida
You've annoyed the target! You've holed the target! You've obliterated the target! click click
El código
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; }
fuente
List<Class<? extends Projectile>> projectiles = new ArrayList<Class<? extends Projectile>>()
. La clase Proyectil debe ser una interfaz, y la serie no es necesaria para su ejemplo,Oh, pero eso es un código feo, no orientado a objetos. En el momento en que veas "if / else" y "typeof", deberías estar pensando en polimorfismo. Este es el camino equivocado. Creo que los genéricos son tus amigos aquí.
¿Con cuántos tipos planeas lidiar?
ACTUALIZAR:
Si solo está hablando de String e int, aquí hay una forma en que puede hacerlo. Comience con la interfaz XmlGenerator (suficiente con "foo"):
package generics; public interface XmlGenerator<T> { String getXml(T value); }
Y la implementación concreta 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(">"); } }
Si ejecuto esto, obtengo el siguiente resultado:
integer: <java.lang.Integer>42<java.lang.Integer> string : <java.lang.String>foobar<java.lang.String>
No sé si esto es lo que tenías en mente.
fuente
Deberías pasar un
Class
...private void foo(Class<?> t){ if(t == String.class){ ... } else if(t == int.class){ ... } } private void bar() { foo(String.class); }
fuente
method_foo(Type fooableType)
sean menos útiles quemethod_foo(Class<?> fooableClass)
?Si desea pasar el tipo, el equivalente en Java sería
Si desea utilizar un método débilmente tipado, simplemente debería utilizar
y el operador correspondiente
instanceof
p.ej
private void foo(Object o) { if(o instanceof String) { } }//foo
Sin embargo, en Java hay tipos primitivos, que no son clases (es decir, int de su ejemplo), por lo que debe tener cuidado.
La verdadera pregunta es qué es lo que realmente quiere lograr aquí, de lo contrario, es difícil de responder:
fuente
Puede pasar una instancia de java.lang.Class que represente el tipo, es decir
private void foo(Class cls)
fuente