如何在Java中扩展参数?

时间:2012-02-16 10:23:51

标签: java python parameter-passing

以下Python代码段完全符合我的意思:

def function(a, b, c):
    print("%i :: %s :: %f" % (a,b,c))

a = 1
b = "abc"
c = 1.0

function(a, b, c)

list = [a, b, c]

# This is what I am searching for in Java
function(*(list))

所以我有一个类似列表的结构,我不知道它有多少个参数,但我知道它有正确数量的参数,具有正确的类型和格式。我想把它们传递给一个方法。所以我必须“扩大”这些论点。有人知道如何在Java中这样做吗?

6 个答案:

答案 0 :(得分:5)

Java没有这种功能,因为作为一种静态的强类型语言,一个方法采用统一类型值的集合并不常见,这些值可以全部存储在某个复合对象(数组,列表等)中。 )。 Python没有这个问题,因为一切都是动态类型的。您可以通过定义一个辅助方法来在Java中执行此操作,该方法将单个对象保存所有参数,然后在调用实际方法时将它们展开。

希望这有帮助!

答案 1 :(得分:3)

您可以使用Object...声明可选参数,以便您可以传递任意数量的参数,然后将每个参数转换为所需的类型:

public void method1(String p1, Integer p2) {
}

public void method2(Object... params) {
    method1((String)params[0], (Integer)params[1];
}

您可以将method2称为:

method2("abc", 1);

当然,这个例子有点多余,因为你可以直接调用method1,但这不是我想说明的。 :)

答案 2 :(得分:1)

你做不到。在Java中,在编译时检查方法参数,并且由于数组的内容仅在运行时定义,因此无法进行此检查。

您最接近的解决方案是让一个方法将数组作为参数,并最终扩展参数以调用目标方法。

答案 3 :(得分:0)

你可以这样做:

import java.util.Formatter;

// ...

StringBuilder target = new StringBuilder();
Formatter formatter = new Formatter(target);

List<Integer> integers = new ArrayList<Integer>();
integers.add(1);
integers.add(2);
integers.add(3);

formatter.format("%d %d %d", integers.toArray());
System.out.println(target.toString());

修改: Javadoc for java.util.Formatter

答案 4 :(得分:0)

我认为这与使用类似语法的初始代码完全相同...

public class MultiArgs {

    public static void main(String[] args) {
        int a = 1;
        String b = "abc";
        double c = 1.0;
        List<?> list = Arrays.asList(a, b, c);

        System.out.println(function(a, b, c)); // 1 :: abc :: 1.000000
        System.out.println(function(list.toArray())); // 1 :: abc :: 1.000000
    }

    private static <T extends Object> String function(T... objects) {
        return String.format("%d :: %s :: %f", objects);
    }
}

答案 5 :(得分:0)

不推荐(作为templatetypedef的答案说明,对于强类型语言来说这是一种非常罕见的模式),但你可以使用反射做你想做的事。

SomeType foo = //obtained from elsewhere
List<?> args = //obtained from somewhere else

//this bit obtains the method handle
Method theMethod = null;
for (Method m : foo.getClass().getMethods()) {
    if (m.getName().equals("theMethodIWant") {
        theMethod = m;
        break;
    }
}

theMethod.invoke(foo, args.toArray()); //this is the line that does the magic

一些相当严重的警告:

  • 与直接调用相比,反射可以产生显着的性能影响 - 远远超过像python这样的动态语言。这可能或不重要。如有疑问,请测量。

  • 如果找不到具有此名称的方法,则获取方法句柄的块将导致空指针

  • 参数列表必须具有正确数量的参数,并且类型正确。您有责任在其他地方验证。这比在动态语言中更难,因为运行时会为你做很多(如果有的话)类型强制。

  • method.invoke()可以抛出此示例忽略的大量异常(IllegalAccessException,IllegalArgumentException,InvocationTargetException等)。你必须适当地抓住并处理这些错误

  • 如果被调用的方法不公开,你将需要做更多的工作来调用它。

  • 这个例子甚至没有尝试处理你有重载方法的情况。两个名为“theMethodIWant”的方法具有不同的参数列表,需要采用不同的方法来获取方法句柄。

总而言之,如果可能,我建议不要使用反射。