我正在尝试编写一个可以用任意数量的整数和字符串调用的 Java 函数的原型:
myMethod(1, 2, 3, "Hello", "World"); // Valid call
myMethod(4, "foo", "bar", "foobar"); // Valid call
理想情况下,我希望整数和字符串以任何顺序给出(并且可能是混合的):
myMethod(1, "Hello", 2, "World", 3); // Valid call
我想过使用varargs,但是原型中只能有一个。我的另一个想法是使用以下原型:
public void myMethod(Object ... objs) { [...] }
...但我觉得如果使用预期类型以外的类型调用它,应该会出现编译错误。当然,可以执行运行时检查(
instanceof
),但这不是一个非常优雅的解决方案,不是吗?
你会怎么做?
如果你希望它类型安全,我会这样做:
public myMethod(Thing<?>... thing) { ... }
然后创建您的 Thing 类:
public interface Thing<T> {
public T value();
}
public class IntThing implements Thing<Integer> {
private final int value;
public IntThing(int value) {
this.value = value;
}
public Integer value() {
return value;
}
}
我将让您发挥想象力来弄清楚如何编写 StringThing。显然,使用一个比“Thing”更好的名字,但我无法帮助你。
然后创建两个静态方法:
public static Thing<Integer> thing(int value) {
return new IntThing(value);
}
public static Thing<String> thing(String value) {
return new StringThing(value);
}
然后将每个对象包装在对
thing
: 的调用中
myMethod(thing(1), thing(2), thing(3), thing("Hello"), thing("World"));
凌乱?是的。不幸的是,Java 没有能力像其他语言一样隐藏这些东西。 Scala 的隐式定义可以在这里帮助您,但这会带来很多其他问题。就我个人而言,我会进行
instanceof
检查,但这将确保您的代码在编译时是安全的。
Java 编程语言中没有办法让它工作,以便您可以传递任意数量的字符串和整数,并且当您传递字符串或整数以外的其他内容时,编译器会给出错误。
没有办法使用泛型来匹配两种类型,例如
// This does NOT compile
public <T extends String | Integer> void myMethod(T... objs);
您所描述的问题的唯一可能的解决方案是已经声明的解决方案,其中该函数采用
Object
类型的 varargs 参数。这是由于 Java 中的限制,方法签名中只能有一个 vararg,并且它必须是最后一个参数。
如果不知道您想要
myMethod
做什么的细节,很难说另一种优雅的解决方案是什么。
(解决方法)
添加到您的库:
package mylib;
public class Lang {
public static <T> T[] varargs (T...ts) {
return ts;
}
}
在你的程序中:
package myprog;
import static mylib.Lang.*;
public class MyProg {
public static void testfunc (Integer[] ints, String[] strs) {
for (int i : ints)
System.out.println(i);
for (String s : strs)
System.out.println(s);
}
public static void main (String[] args) {
testfunc(
varargs(1,2,3),
varargs("Sophia", "Jacob")
);
}
}
(打破了许多编码风格规则)
允许使用语法
public class Foo<T extends Number & List> {
...
}
类型变量
T
允许属于同一类型的 Number
和 List
的子类型(例如,实现多个接口的类型)。