简体   繁体   English

如何在Java中将类型作为方法参数传递

[英]How to pass a type as a method parameter in Java

In Java, how can you pass a type as a parameter (or declare as a variable)? 在Java中,如何将类型作为参数传递(或声明为变量)?

I don't want to pass an instance of the type but the type itself (eg. int, String, etc). 我不想传递类型的实例 ,而是传递类型本身(例如int,String等)。

In C#, I can do this: 在C#中,我可以这样做:

private void foo(Type t)
{
    if (t == typeof(String)) { ... }
    else if (t == typeof(int)) { ... }
}

private void bar()
{
    foo(typeof(String));
}

Is there a way in Java without passing an instance of type t? Java中有没有传递类型为t的实例的方法?
Or do I have to use my own int constants or enum? 或者我必须使用自己的int常量或枚举?
Or is there a better way? 或者,还有更好的方法?

Edit: Here is the requirement for foo: 编辑:这是foo的要求:
Based on type t, it generates a different short, xml string. 基于类型t,它生成一个不同的短xml字符串。
The code in the if/else will be very small (one or two lines) and will use some private class variables. if / else中的代码将非常小(一行或两行)并将使用一些私有类变量。

You could pass a Class<T> in. 你可以传入一个Class<T>

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

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

Update : the OOP way depends on the functional requirement. 更新 :OOP方式取决于功能要求。 Best bet would be an interface defining foo() and two concrete implementations implementing foo() and then just call foo() on the implementation you've at hand. 最好的选择是定义foo()的接口和实现foo()两个具体实现,然后在你手头的实现上调用foo() Another way may be a Map<Class<?>, Action> which you could call by actions.get(cls) . 另一种方法可能是Map<Class<?>, Action> ,您可以通过actions.get(cls)调用它。 This is easily to be combined with an interface and concrete implementations: actions.get(cls).foo() . 这很容易与接口和具体实现相结合: actions.get(cls).foo()

I had a similar question, so I worked up a complete runnable answer below. 我有一个类似的问题,所以我在下面编写了一个完整的可运行答案。 What I needed to do is pass a class (C) to an object (O) of an unrelated class and have that object (O) emit new objects of class (C) back to me when I asked for them. 我需要做的是将一个类(C)传递给一个不相关的类的对象(O),当我要求它时,让该对象(O)向我发出类(C)的新对象。

The example below shows how this is done. 下面的示例显示了如何完成此操作。 There is a MagicGun class that you load with any subtype of the Projectile class (Pebble, Bullet or NuclearMissle). 您可以使用Projectile类的任何子类型(Pebble,Bullet或NuclearMissle)加载MagicGun类。 The interesting is you load it with subtypes of Projectile, but not actual objects of that type. 有趣的是你用Projectile的子类型加载它,但不是那种类型的实际对象。 The MagicGun creates the actual object when it's time to shoot. 在拍摄时,MagicGun会创建实际物体。

The Output 输出

You've annoyed the target!
You've holed the target!
You've obliterated the target!
click
click

The 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;
}

You should pass a Class ... 你应该通过一个Class ......

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

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

Oh, but that's ugly, non-object-oriented code. 哦,但那是丑陋的,非面向对象的代码。 The moment you see "if/else" and "typeof", you should be thinking polymorphism. 你看到“if / else”和“typeof”的那一刻,你应该考虑多态性。 This is the wrong way to go. 这是错误的方式。 I think generics are your friend here. 我认为仿制药是你的朋友。

How many types do you plan to deal with? 您打算处理多少种类型?

UPDATE: 更新:

If you're just talking about String and int, here's one way you might do it. 如果您只是在谈论String和int,那么这是您可以采用的一种方式。 Start with the interface XmlGenerator (enough with "foo"): 从界面XmlGenerator开始(足够用“foo”):

package generics;

public interface XmlGenerator<T>
{
   String getXml(T value);
}

And the concrete implementation XmlGeneratorImpl: 并具体实现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(">");
    }
}

If I run this, I get the following result: 如果我运行它,我得到以下结果:

integer: <java.lang.Integer>42<java.lang.Integer>
string : <java.lang.String>foobar<java.lang.String>

I don't know if this is what you had in mind. 我不知道这是不是你的想法。

If you want to pass the type, than the equivalent in Java would be 如果你想传递类型,那么就比Java中的等价物要好

java.lang.Class

If you want to use a weakly typed method, then you would simply use 如果你想使用弱类型的方法,那么你只需使用

java.lang.Object

and the corresponding operator 和相应的操作员

instanceof

eg 例如

private void foo(Object o) {

  if(o instanceof String) {

  }

}//foo

However, in Java there are primitive types, which are not classes (ie int from your example), so you need to be careful. 但是,在Java中有原始类型,它们不是类(即您的示例中的int),因此您需要小心。

The real question is what you actually want to achieve here, otherwise it is difficult to answer: 真正的问题是你真正希望在这里实现的目标,否则很难回答:

Or is there a better way? 或者,还有更好的方法?

您可以传递表示类型的java.lang.Class实例,即

private void foo(Class cls)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM