【问题标题】:How to pass a type as a method parameter in Java如何在 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) 一样使用

标签: java types


【解决方案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&lt;Class&lt;?&gt;, Action&gt;,您可以拨打actions.get(cls)。这很容易与接口和具体实现相结合:actions.get(cls).foo()

【讨论】:

  • 我将在问题中添加要求的详细信息。
  • 我现在决定使用简单版本,因为所讨论的类型总是原始的(int、string 等)。但是,我一定会牢记 oop 方式。谢谢。
  • String 在 Java 中不是原语 ;)
  • @Padawan - 还不够继续。 BalusC 使用 Map 的答案就足够了。你接受它是对的。
  • 您也可以使用Class&lt;?&gt; 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&lt;?&gt; 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&lt;Class&lt;? extends Projectile&gt;&gt; projectiles = new ArrayList&lt;Class&lt;? extends Projectile&gt;&gt;() 修复它们的警告。 Projectile 类应该是一个接口,并且您的示例不需要序列号,
      • 我能想到的唯一原因是阅读类名可能有用。 pastebin.com/v9UyPtWT 但是,您可以使用枚举。 pastebin.com/Nw939Js1
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-26
      • 1970-01-01
      相关资源
      最近更新 更多