【问题标题】:Optional Anonymous Parameters Passing in Java在 Java 中传递可选的匿名参数
【发布时间】:2012-09-10 18:58:33
【问题描述】:

我有两个类 A 和 B。A 有一个方法,比如 foo,它可以有任意数量的任意类型的参数。该方法将这些参数传递给具有预定数量的预定类型参数的方法。

Class A{
   foo(<?> ... params){
      (new B()).bar(params);
   }
} 

Class B{
   bar(int a, int b){
       Log.v("The params passed are "+a+" and "+b);
   }
}

Class Caller{

    callingMethod(){
        (new A()).foo(1, 2);
    }
}

我知道编译器不允许我为 foo 写下的签名;我写它只是为了解释我想要实现的目标。

我不想在 B 类的 bar(int, int) 中进行任何转换。

【问题讨论】:

  • 有人可能会争辩说,如果您在 Java 方法中需要这种开放式方法参数,您可能做错了什么。该语言实际上不允许这样做,在您的示例中,这种间接性似乎没有意义。
  • 我要避免的是使用 Bundle (/HashMap),在这种情况下,callingMethod 必须知道其内容。此外,对于可以推送到 Bundle 的内容没有任何限制。这种“Bundle 方法”是用于 Android 中 Activity 的生命周期回调方法 (savedInstanceState)。

标签: java parameter-passing anonymous-types optional-parameters


【解决方案1】:

您可以添加有限数量的参数,这些参数在可变参数之前是固定的。 这是在EnumSet中实现的

我已更改为 foo 方法以接受 3 个参数 E e1, E e2, E... params 确保我至少有 2 个参数来调用 bar(e1, e2) 方法。

&lt;E extends Number&gt; 确保您可以传递Number 的任何子类Integer 恰好是一个。

static class A {
    <E extends Number> void foo(E e1, E e2, E... params) {
        (new B<E>()).bar(e1, e2);
    }
}

static class B<E extends Number> {
    public void bar(E a, E b) {

    }
}

public static void main(String[] args) {

    A name = new A();
    name.foo(1, 2, 123);
}

【讨论】:

    【解决方案2】:

    你可以使用可变参数...

    public static void foo(Object... parameters ){
    
    }
    

    【讨论】:

    • 这并不能完全回答如何解压缩parameters 以将它们传递到B 的新实例中。我有点假设 OP 希望重载决议仍然发生,这当然不是微不足道的。
    • 但是,callingMethod() 必须知道将参数转换为什么类型,这对我来说是个问题。
    • @SyedFahadSultan - 你可以通过反射来做到这一点,但自动装箱使这更难。我仍然认为您可能试图解决错误的问题,应该退后一步,看看设计本身并避免这个问题。
    • @Flexo 我猜你是对的。请参阅我上面对马特 b 的评论。如果没有其他人遇到我在该评论中提到的问题,我会感到惊讶。
    【解决方案3】:

    Java 中的可变参数:

    foo(Object... objs) {}
    

    例子:

    public static void main(String... args) {}
    

    等价于

    public static void main(String[] args) {}
    

    注意:只要方法签名中没有剩余参数,就相当于使用数组。

    【讨论】:

    • 如何解压 var args 以在 B 中调用 bar
    • 您必须检查 params[0] 和 params[1] 是否为整数并转换它们。它是脏的。但最初的问题是关于 foo 的签名以使其编译。
    • 当然,但是你的不能编译 (new B()).bar(objs); 不起作用。
    【解决方案4】:

    正如其他人所建议的,您可以接受可变数量的Objects 作为函数参数。棘手的一点是打开包装以在B 上调用bar。我已经整理了一个示例,说明如何使用反射来做到这一点:

    import java.lang.reflect.Method;
    
    public class test {
      static class A {
        private final Class cl;
        A(Class cl) { 
          this.cl = cl;
        }
        void foo(Object ... params) throws Exception {
          Object obj = cl.newInstance();
          for (Method m : cl.getMethods()) {
            if (m.getName().equals("bar")) {
              try {
                m.invoke(obj, params);
                return;
              }
              catch(IllegalArgumentException ex) {} // try next overload
            }
          }
          throw new IllegalArgumentException();
        }
      }
    
      static class B {
        public void bar() {
          System.out.println("Got nothing");
        }
    
        public void bar(double a, double b) {
          System.out.println("Got doubles");
        }
    
        public void bar(int a, int b) {
          System.out.println("Got: " + a + " and " + b);
        }
      }
    
      public static void main(String argv[]) throws Exception {
        new A(B.class).foo(1,2);
        new A(B.class).foo();
        new B().bar(1,2);
        new A(B.class).foo("Hello");
      }
    }
    

    但是您会注意到,这里的重载解决方案远非完美,并且在调用 double,doublebar 中传递 1,2。要解决这个问题,您需要对Method 对象数组进行排序,使其与给定的每个对象的Class 最佳匹配,但据我所知,这远非微不足道。

    【讨论】:

    • 我无法评论 Android 问题,但这至少部分解决了调度问题。
    • 感谢柔印!真的很好的答案!只有一件事:为什么不在 m 上调用 invoke 之前,我们调用 getParameterTypes() 或 getTypeParameters() 并将方法接受的参数数量与参数长度进行比较。这将减少抛出 IllegalArgumentException 的次数。我想知道我们是否也可以使用 getParameterTypes() 或 getTypeParameters() 来比较来自 params 的类型。让我知道你的想法。不过,再次感谢!
    • @SyedFahadSultan 这正是您想要做的以使其更健壮,以及检查类型是否匹配。问题在于,一般而言,规则非常复杂,例如,在两个重载之间进行选择,一个需要隐式向上转换,一个需要更好地匹配 Object,但需要 int->long 提升选的?我不知道我脑海中的规则,如果你想要它们,它们位于:docs.oracle.com/javase/specs/jls/se7/html/…
    • 我去看看。附言一个人要怎么做才能得到对这里问题的支持?因为我似乎无法获得任何:P
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-24
    • 1970-01-01
    • 2023-01-30
    • 2012-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多