Em Java, como você pode passar um tipo como um parâmetro (ou declarar como uma variável)?
Não quero passar uma instância do tipo, mas o próprio tipo (por exemplo, int, String, etc).
Em C #, posso fazer isso:
private void foo(Type t)
{
if (t == typeof(String)) { ... }
else if (t == typeof(int)) { ... }
}
private void bar()
{
foo(typeof(String));
}
Existe uma maneira em Java sem passar uma instância do tipo t?
Ou eu tenho que usar minhas próprias constantes int ou enum?
Ou há um modo melhor?
Edit: Aqui está o requisito para foo:
Com base no tipo t, ele gera uma string xml curta diferente.
O código em if / else será muito pequeno (uma ou duas linhas) e usará algumas variáveis de classe privada.
Respostas:
Você poderia passar por
Class<T>
dentro.private void foo(Class<?> cls) { if (cls == String.class) { ... } else if (cls == int.class) { ... } } private void bar() { foo(String.class); }
Atualização : o modo OOP depende do requisito funcional. A melhor aposta seria uma definição de interface
foo()
e duas implementações concretas de implementaçãofoo()
e, em seguida, basta chamarfoo()
a implementação que você tem em mãos. Outra forma pode ser através de umaMap<Class<?>, Action>
chamadaactions.get(cls)
. Isto é facilmente para ser combinado com uma interface e implementações concretas:actions.get(cls).foo()
.fonte
String
não é um primitivo em Java;)Class<?> cls
em algo diferente de comparação. Embora você não possa escrever:cls value = (cls) aCollection.iterator().next();
você pode chamar cls.cast (aCollection.iterator (). Next ()); Classe javadocEu tinha uma pergunta semelhante, então criei uma resposta executável completa abaixo. O que eu precisava fazer era passar uma classe (C) para um objeto (O) de uma classe não relacionada e fazer com que esse objeto (O) emitisse novos objetos da classe (C) de volta para mim quando eu os solicitasse.
O exemplo abaixo mostra como isso é feito. Existe uma classe MagicGun que você carrega com qualquer subtipo da classe Projétil (Pebble, Bullet ou NuclearMissle). O interessante é que você o carrega com subtipos de Projétil, mas não com objetos reais desse tipo. O MagicGun cria o objeto real na hora de atirar.
A saída
You've annoyed the target! You've holed the target! You've obliterated the target! click click
O 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; }
fonte
List<Class<? extends Projectile>> projectiles = new ArrayList<Class<? extends Projectile>>()
. A classe Projétil deve ser uma interface, e o serial não é necessário para seu exemplo,Ah, mas esse é um código feio e não orientado a objetos. No momento em que você vê "if / else" e "typeof", você deve estar pensando em polimorfismo. Este é o caminho errado a seguir. Acho que os genéricos são seus amigos aqui.
Com quantos tipos você planeja lidar?
ATUALIZAR:
Se você está falando apenas sobre String e int, aqui está uma maneira de fazer isso. Comece com a interface XmlGenerator (basta com "foo"):
package generics; public interface XmlGenerator<T> { String getXml(T value); }
E a implementação 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(">"); } }
Se eu executar isso, obtenho o seguinte resultado:
integer: <java.lang.Integer>42<java.lang.Integer> string : <java.lang.String>foobar<java.lang.String>
Não sei se é isso que você tinha em mente.
fonte
Você deveria passar por um
Class
...private void foo(Class<?> t){ if(t == String.class){ ... } else if(t == int.class){ ... } } private void bar() { foo(String.class); }
fonte
method_foo(Type fooableType)
sejam menos úteis do quemethod_foo(Class<?> fooableClass)
?Se você deseja passar o tipo, então o equivalente em Java seria
Se você quiser usar um método de digitação fraca, basta usar
e o operador correspondente
instanceof
por exemplo
private void foo(Object o) { if(o instanceof String) { } }//foo
No entanto, em Java existem tipos primitivos, que não são classes (ou seja, int do seu exemplo), portanto, você precisa ter cuidado.
A verdadeira questão é o que você realmente deseja alcançar aqui, caso contrário, é difícil responder:
fonte
Você pode passar uma instância de java.lang.Class que representa o tipo, ou seja,
private void foo(Class cls)
fonte