Как в Java передать тип как параметр (или объявить как переменную)?
Я хочу передавать не экземпляр типа, а сам тип (например, int, String и т. Д.).
В C # я могу сделать это:
private void foo(Type t)
{
if (t == typeof(String)) { ... }
else if (t == typeof(int)) { ... }
}
private void bar()
{
foo(typeof(String));
}
Есть ли способ в Java без передачи экземпляра типа t?
Или мне нужно использовать собственные константы int или перечисление?
Или есть способ лучше?
Изменить: вот требование для foo: на
основе типа t он генерирует другую короткую строку xml.
Код в if / else будет очень маленьким (одна или две строки) и будет использовать некоторые переменные частного класса.
Ответы:
Вы могли бы сдать
Class<T>
.private void foo(Class<?> cls) { if (cls == String.class) { ... } else if (cls == int.class) { ... } } private void bar() { foo(String.class); }
Обновление : способ ООП зависит от функциональных требований. Лучшим вариантом будет определение интерфейса
foo()
и реализация двух конкретных реализаций,foo()
а затем просто вызовfoo()
той реализации, которая у вас под рукой. Другой способ -Map<Class<?>, Action>
это позвонитьactions.get(cls)
. Это легко сочетать с интерфейсом и конкретными реализациями:actions.get(cls).foo()
.источник
String
не является примитивом в Java;)Class<?> cls
что-то другое, кроме сравнения. Пока вы не можете писать:cls value = (cls) aCollection.iterator().next();
вы можете вызвать cls.cast (aCollection.iterator (). Next ()); Class javadocУ меня был аналогичный вопрос, поэтому я дал полный рабочий ответ ниже. Мне нужно было передать класс (C) объекту (O) несвязанного класса и заставить этот объект (O) выдавать мне новые объекты класса (C), когда я их просил.
Пример ниже показывает, как это делается. Существует класс MagicGun, который вы загружаете с любым подтипом класса Projectile (Pebble, Bullet или NuclearMissle). Интересно то, что вы загружаете его подтипами Projectile, но не реальными объектами этого типа. MagicGun создает реальный объект, когда приходит время стрелять.
Выход
You've annoyed the target! You've holed the target! You've obliterated the target! click click
Код
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; }
источник
List<Class<? extends Projectile>> projectiles = new ArrayList<Class<? extends Projectile>>()
. Класс Projectile должен быть интерфейсом, и серийный номер в вашем примере не обязателен,О, но это уродливый, не объектно-ориентированный код. В тот момент, когда вы видите «if / else» и «typeof», вы должны думать о полиморфизме. Это неправильный путь. Я думаю, что дженерики здесь ваш друг.
Со сколькими типами вы планируете иметь дело?
ОБНОВИТЬ:
Если вы просто говорите о String и int, вот один из способов сделать это. Начнем с интерфейса XmlGenerator (достаточно «foo»):
package generics; public interface XmlGenerator<T> { String getXml(T value); }
И конкретная реализация 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(">"); } }
Если запустить это, я получу следующий результат:
integer: <java.lang.Integer>42<java.lang.Integer> string : <java.lang.String>foobar<java.lang.String>
Не знаю, имел ли ты это в виду.
источник
Вы должны пройти
Class
...private void foo(Class<?> t){ if(t == String.class){ ... } else if(t == int.class){ ... } } private void bar() { foo(String.class); }
источник
method_foo(Type fooableType)
менее полезны, чемmethod_foo(Class<?> fooableClass)
?Если вы хотите передать тип, то эквивалент в Java будет
Если вы хотите использовать метод со слабой типизацией, просто используйте
и соответствующий оператор
instanceof
например
private void foo(Object o) { if(o instanceof String) { } }//foo
Однако в Java есть примитивные типы, которые не являются классами (например, int из вашего примера), поэтому вам нужно быть осторожным.
Настоящий вопрос в том, чего вы действительно хотите здесь достичь, иначе сложно ответить:
источник
Вы можете передать экземпляр java.lang.Class, который представляет тип, т.е.
private void foo(Class cls)
источник