Подтвердить что ты не робот

Как передать тип в качестве параметра метода в Java

В Java, как вы можете передать тип в качестве параметра (или объявить как переменную)?

Я не хочу передавать экземпляр типа, но сам тип (например, int, String и т.д.).

В С# я могу это сделать:

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 будет очень мал (одна или две строки) и будет использовать некоторые частные переменные класса.

4b9b3361

Ответ 1

Вы можете передать 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().

Ответ 2

У меня был аналогичный вопрос, поэтому я разработал полный runnable ответ ниже. То, что мне нужно было сделать, - передать класс (C) объекту (O) несвязанного класса и вернуть этот объект (O) новым объектам класса (C), когда я их попрошу.

В следующем примере показано, как это делается. Существует класс MagicGun, который вы загружаете любым подтипом класса Projectile (Pebble, Bullet или NuclearMissle). Интересно, что вы загружаете его подтипами снаряда, но не фактическими объектами этого типа. 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 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;
}

Ответ 3

Вы должны передать Class...

private void foo(Class<?> t){
    if(t == String.class){ ... }
    else if(t == int.class){ ... }
}

private void bar()
{
   foo(String.class);
}

Ответ 4

О, но этот уродливый, не объектно-ориентированный код. В тот момент, когда вы видите "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>

Я не знаю, было ли это то, что вы имели в виду.

Ответ 5

Если вы хотите передать тип, то эквивалент в Java будет

java.lang.Class

Если вы хотите использовать слабо типизированный метод, вы просто используете

java.lang.Object

и соответствующий оператор

instanceof

например.

private void foo(Object o) {

  if(o instanceof String) {

  }

}//foo

Однако в Java существуют примитивные типы, которые не являются классами (т.е. int из вашего примера), поэтому вам нужно быть осторожным.

Реальный вопрос - это то, чего вы на самом деле хотите достичь здесь, иначе сложно ответить:

Или есть лучший способ?

Ответ 6

Вы можете передать экземпляр java.lang.Class, который представляет тип, т.е.

private void foo(Class cls)