如何在 Java 中将类型作为方法参数传递
Posted
技术标签:
【中文标题】如何在 Java 中将类型作为方法参数传递【英文标题】:How to pass a type as a method parameter in Java 【发布时间】:2011-01-15 11:41:42 【问题描述】:在 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 中的代码会非常小(一两行),并且会使用一些私有类变量。
【问题讨论】:
您可以像 private void foo(Class c) 一样传递 Class 类型并像 foo(String.class) 一样使用 【参考方案1】:你可以传递一个Class<T>
in.
private void foo(Class<?> cls)
if (cls == String.class) ...
else if (cls == int.class) ...
private void bar()
foo(String.class);
更新:OOP方式取决于功能需求。最好的办法是定义foo()
的接口和实现foo()
的两个具体实现,然后在您手头的实现上调用foo()
。另一种方式可能是Map<Class<?>, Action>
,您可以拨打actions.get(cls)
。这很容易与接口和具体实现相结合:actions.get(cls).foo()
。
【讨论】:
我将在问题中添加要求的详细信息。 我现在决定使用简单版本,因为所讨论的类型总是原始的(int、string 等)。但是,我一定会牢记 oop 方式。谢谢。String
在 Java 中不是原语 ;)
@Padawan - 还不够继续。 BalusC 使用 Map 的答案就足够了。你接受它是对的。
您也可以使用Class<?> cls
进行比较以外的其他用途。虽然你不能写:cls value = (cls) aCollection.iterator().next();
你可以调用 cls.cast(aCollection.iterator().next()); Class javadoc【参考方案2】:
你可以传递一个代表类型的 java.lang.Class 的实例,即
private void foo(Class cls)
【讨论】:
【参考方案3】:你应该传递一个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)
有用吗?【参考方案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>
我不知道这是不是你的想法。
【讨论】:
现在只有 int 和 string。执行此操作的 oop 方法是什么? “任何时候你发现自己在编写“如果对象是 T1 类型,那么做某事,但如果它是 T2 类型,那么做其他事情”形式的代码,“打自己一巴掌。” javapractices.com/topic/TopicAction.do?Id=31 @The Feast:感谢您的链接。我想我明白在说什么,但在这里我没有任何对象的实例。我希望 foo 为 int 和 string 生成不同的字符串。我是否必须创建两个从其他对象派生的对象实例才能以 oop 方式进行操作?这种情况可能有点过头了? 我现在决定使用简单版本,因为所讨论的类型总是原始的(int、string 等)。但是,我一定会牢记 oop 方式。谢谢。 @Padawan,对不起,我不是故意居高临下的 - duffymo 的评论让我想起了那句话!【参考方案5】:如果你想传递类型,那么Java中的等价物就是
java.lang.Class
如果你想使用弱类型方法,那么你只需使用
java.lang.Object
以及对应的运算符
instanceof
例如
private void foo(Object o)
if(o instanceof String)
//foo
但是,在 Java 中存在原始类型,它们不是类(即您示例中的 int),因此您需要小心。
真正的问题是你在这里真正想要实现什么,否则很难回答:
或者有没有更好的方法?
【讨论】:
【参考方案6】:我有一个类似的问题,所以我在下面找到了一个完整的可运行答案。我需要做的是将一个类 (C) 传递给一个不相关类的对象 (O),并让该对象 (O) 在我请求它们时将类 (C) 的新对象返回给我。
下面的示例显示了这是如何完成的。您可以使用 Projectile 类的任何子类型(Pebble、Bullet 或 NuclearMissle)加载一个 MagicGun 类。有趣的是,您使用 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 类应该是一个接口,并且您的示例不需要序列号,
我能想到的唯一原因是阅读类名可能有用。 pastebin.com/v9UyPtWT 但是,您可以使用枚举。 pastebin.com/Nw939Js1以上是关于如何在 Java 中将类型作为方法参数传递的主要内容,如果未能解决你的问题,请参考以下文章