Java两种方法中的varargs

有没有办法在java中创建一个方法,期待两个不同的varargs? 我知道,由于编译器不知道从哪里开始或结束,因此使用相同的对象类型是不可能的。 但为什么它也不可能与不同的对象类型?

例如:

public void doSomething(String... s, int... i){ //... //... } 

有没有办法创建这样的方法? 谢谢!

只有一个vararg,对不起。 但使用asList()使它几乎同样方便:

  public void myMethod(List args1, List args2) { ... } ----------- import static java.util.Arrays.asList; myMethod(asList(1,2,3), asList(4,5,6)); 

在Java中,只允许一个varargs参数,它必须是签名的最后一个参数。

但无论如何它只是将它转换为数组,所以你应该让你的两个参数显式数组:

 public void doSomething(String[] s, int[] i){ 

一种可能的API设计,其中调用代码看起来像

  doSomething("a", "b").with(1,2); 

通过“流畅”的API

 public Intermediary doSomething(String... strings) { return new Intermediary(strings); } class Intermediary { ... public void with(int... ints) { reallyDoSomething(strings, ints); } } void reallyDoSomething(String[] strings, int[] ints) { ... } 

如果程序员忘了with(...)打电话会有危险

  doSomething("a", "b"); // nothing is done 

也许这会好一点

  with("a", "b").and(1, 2).doSomething(); 

只允许一个vararg 。 这是因为多个vararg参数不明确。 例如,如果你传入两个相同类的varargs怎么办?

 public void doSomething(String...args1, String...args2); 

args1 end和args2从哪里开始? 或者这里有些令人困惑的事情。

 class SuperClass{} class ChildClass extends SuperClass{} public void doSomething(SuperClass...args1, ChildClass...args2); 

ChildClass扩展了SuperClass,因此可以合法地存在于args1或args2中。 这种混淆是为什么只允许一个varargs

varargs也必须出现在方法声明的末尾。

只需将特定类型声明为2个数组。

虽然这种事情偶尔会有用,但通常如果你发现你在Java中受到限制,你可能会重新设计一些东西并且会更好。 以下是一些可能的其他方式来看待它……

如果这两个列表完全相关,那么您可能希望为两个不同的列表创建一个包装类并传入包装器。 集合周围的包装几乎总是一个好主意 – 它们为您提供了添加与集合相关的代码的位置。

如果这是一种初始化数据的方法,请从字符串中解析它。 例如,“abc,123:def,456:jhi,789”几乎非常容易分割出2个分割语句和一个循环(2-3行代码)。 您甚至可以创建一个小的自定义解析器类,将类似的字符串解析为您提供给方法的结构。

嗯 – 诚实地说,从初始化数据来看,我甚至都不知道为什么你想要这样做,任何其他情况,我希望你会传递2个集合,根本不会对varags感兴趣。

您可以执行此类操作,然后可以在该方法中强制转换和添加其他逻辑。

 public void doSomething(Object... stringOrIntValues) { ... ... } 

并使用这样的方法:

 doSomething(stringValue1, stringValue2, intValue1, intValue2, intValue3); 

这是一个老线程,但我认为无论如何这都会有所帮助。

我找到的解决方案不是很整洁,但它的工作原理。 我创建了一个单独的类来处理繁重的工作。 它只有我需要的两个变量和它们的吸气剂。 构造函数自己处理set方法。

我需要传递方向对象和相应的Data对象。 这也解决了数据对不均匀的可能问题,但这可能仅限于我的使用需求。

 public class DataDirectionPair{ Data dat; Directions dir; public DataDirectionPair(Data dat, Directions dir) { super(); this.dat = dat; this.dir = dir; } /** * @return the node */ public Node getNode() { return node; } /** * @return the direction */ public Directions getDir() { return dir; } } 

然后我会将此类作为方法的vararg传递

 public void method(DataDirectionPair... ndPair){ for(DataDirectionPair temp : ndPair){ this.node = temp.getNode(); this.direction = temp.getDir(); //or use it however you want } } 

这是不可能的,因为Java语言规范是这样说的(见8.4.1。forms参数 ):

方法或构造函数的最后一个forms参数是特殊的:它可以是一个变量arity参数 ,由类型后面的省略号表示。

请注意,省略号(…)本身就是一个标记(§3.11)。 可以在它和类型之间放置空格,但不鼓励这样做。

如果最后一个forms参数是变量arity参数,则该方法是变量arity方法 。 否则,它是一种固定的arity方法

至于为什么只有一个而且只有最后一个参数,这可能是猜测,但可能是因为允许这可能导致不可判定或模糊的问题(例如考虑method(String... strings, Object... objects)会发生什么method(String... strings, Object... objects) ) ,并且只允许非交叉类型会导致复杂化(例如,考虑以前非交叉类型突然发生的重构),当它是否起作用时缺乏清晰度,以及编译器决定何时适用的复杂性。

我刚刚阅读了关于这个“模式”的另一个问题,但它已被删除,所以我想提出一个不同的方法来解决这个问题,因为我没有在这里看到这个解决方案。

相反,强制开发人员将输入参数包装在List或Array上,使用“curry”方法或更好的构建器模式将非常有用。

请考虑以下代码:

 /** * Just a trivial implementation */ public class JavaWithCurry { private List numbers = new ArrayList(); private List strings = new ArrayList(); public JavaWithCurry doSomething(int n) { numbers.add(n); return this; } public JavaWithCurry doSomething(String s) { strings.add(s); return this; } public void result() { int sum = -1; for (int n : numbers) { sum += n; } StringBuilder out = new StringBuilder(); for (String s : strings) { out.append(s).append(" "); } System.out.println(out.toString() + sum); } public static void main(String[] args) { JavaWithCurry jwc = new JavaWithCurry(); jwc.doSomething(1) .doSomething(2) .doSomething(3) .doSomething(4) .doSomething(5) .doSomething("a") .doSomething("b") .doSomething("c") .result(); } } 

正如您可以通过这种方式看到的那样,您可以根据需要添加所需类型的新元素。

所有的实现都被包装好了。

如果你不打算在第一个参数的大部分时间内传递大量的字符串,你可以提供一堆重载,这些重载使用不同数量的字符串并将它们包装在一个数组中,然后再调用一个方法将数组作为第一个论点。

 public void doSomething(int... i){ doSomething(new String[0], i); } public void doSomething(String s, int... i){ doSomething(new String[]{ s }, i); } public void doSomething(String s1, String s2, int... i){ doSomething(new String[]{ s1, s2 }, i); } public void doSomething(String s1, String s2, String s3, int... i){ doSomething(new String[]{ s1, s2, s3 }, i); } public void doSomething(String[] s, int... i) { // ... // ... } 

关于Lemuel Adane(由于缺乏代表而无法对post发表评论:))

如果你使用

 public void f(Object... args){} 

然后你可以循环使用如何确定一个对象的类(在Java中)?

比如说

 { int i = 0; while(i< args.length && args[i] instanceof String){ System.out.println((String) args[i]); i++ ; } int sum = 0; while(i< args.length){ sum += (int) args[i]; i++ ; } System.out.println(sum); } 

或者你打算做的任何事情。

您可以将varargs转换为数组

 public void doSomething(String[] s, int[] i) { ... } 

然后使用一些帮助方法将varargs转换为数组,如下所示:

 public static int[] intsAsArray(int... ints) { return ints; } public static  T[] asArray(T... ts) { return ts; } 

然后,您可以使用这些辅助方法来转换您的变量参数。

 doSomething(asArray("a", "b", "c", "d"), intsAsArray(1, 2, 3));