如何在Java中将类型作为方法参数传递
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2240646/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to pass a type as a method parameter in Java
提问by
In Java, how can you pass a type as a parameter (or declare as a variable)?
在 Java 中,如何将类型作为参数传递(或声明为变量)?
I don't want to pass an instanceof 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 instanceof type t?
Or do I have to use my own int constants or enum?
Or is there a better way?
Java 中有没有不传递t 类型实例的方法?
还是我必须使用自己的 int 常量或枚举?
或者,还有更好的方法?
Edit: Here is the requirement for foo:
Based on type t, it generates a different short, xml string.
The code in the if/else will be very small (one or two lines) and will use some private class variables.
编辑:这是对 foo 的要求:
基于类型 t,它生成不同的短 xml 字符串。
if/else 中的代码将非常小(一两行)并且将使用一些私有类变量。
采纳答案by BalusC
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. 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. Another way may be a Map<Class<?>, Action>
which you could call by actions.get(cls)
. This is easily to be combined with an interface and concrete implementations: actions.get(cls).foo()
.
更新:OOP 方式取决于功能需求。最好的办法是定义一个接口foo()
和两个具体的实现foo()
,然后调用foo()
你手头的实现。另一种方式可能是 a Map<Class<?>, Action>
,您可以通过actions.get(cls)
. 这很容易与接口和具体实现相结合:actions.get(cls).foo()
.
回答by ghallio
You can pass an instance of java.lang.Class that represents the type, i.e.
你可以传递一个代表类型的 java.lang.Class 的实例,即
private void foo(Class cls)
回答by Mark Elliot
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);
}
回答by duffymo
Oh, but that's ugly, non-object-oriented code. The moment you see "if/else" and "typeof", you should be thinking polymorphism. This is the wrong way to go. I think generics are your friend here.
哦,但那是丑陋的、非面向对象的代码。当您看到“if/else”和“typeof”时,您应该考虑多态性。这是错误的方法。我认为泛型在这里是你的朋友。
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. Start with the interface XmlGenerator (enough with "foo"):
如果您只是在谈论 String 和 int,那么您可以采用以下一种方法。从接口 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.
不知道你是不是这么想的。
回答by Dieter
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
e.g.
例如
private void foo(Object o) {
if(o instanceof String) {
}
}//foo
However, in Java there are primitive types, which are not classes (i.e. 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?
或者,还有更好的方法?
回答by JohnnyLambada
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). The interesting is you load it with subtypes of Projectile, but not actual objects of that type. The MagicGun creates the actual object when it's time to shoot.
下面的示例显示了这是如何完成的。您可以使用 Projectile 类的任何子类型(Pebble、Bullet 或NuclearMissle)加载一个 MagicGun 类。有趣的是你用 Projectile 的子类型加载它,而不是该类型的实际对象。当需要射击时,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;
}