在Java中,如何将类型作为参数传递(或声明为变量)?
我不想传递类型的实例,而是传递类型本身(例如.int,String等)。
在C#中,我可以这样做:
private void foo(Type t)
{
if (t == typeof(String)) { ... }
else if (t == typeof(int)) { ... }
}
private void bar()
{
foo(typeof(String));
}
在没有传递类型为t的实例的情况下,Java中有没有办法?
或者我必须使用自己的int常量或枚举?
或者有更好的方法吗?
编辑:这是foo的要求:
基于类型t,它生成一个不同的短xml字符串
if / else中的代码将非常小(一行或两行),并将使用一些私有类变量。
答案 0 :(得分:91)
您可以传递Class<T>
。
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()
。
答案 1 :(得分:13)
我有一个类似的问题,所以我在下面编写了一个完整的可运行答案。我需要做的是将一个类(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;
}
答案 2 :(得分:9)
您应该传递Class
...
private void foo(Class<?> t){
if(t == String.class){ ... }
else if(t == int.class){ ... }
}
private void bar()
{
foo(String.class);
}
答案 3 :(得分:8)
哦,但那是丑陋的,非面向对象的代码。你看到“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>
我不知道这是不是你的想法。
答案 4 :(得分:5)
如果要传递类型,那么Java中的等价物将是
java.lang.Class
如果你想使用弱类型的方法,那么你只需要使用
java.lang.Object
和相应的运算符
instanceof
e.g。
private void foo(Object o) {
if(o instanceof String) {
}
}//foo
但是,在Java中有原始类型,它们不是类(即你的例子中的int),所以你需要小心。
真正的问题是你真正希望在这里实现的目标,否则很难回答:
或者有更好的方法吗?
答案 5 :(得分:0)
您可以传递表示类型的java.lang.Class实例,即
private void foo(Class cls)