问题
I'm trying to write the prototype of a Java function that can be called with any number of integers and strings:
myMethod(1, 2, 3, "Hello", "World"); // Valid call
myMethod(4, "foo", "bar", "foobar"); // Valid call
Ideally, I would like the ints and strings to be given in any order (and possibly mixed):
myMethod(1, "Hello", 2, "World", 3); // Valid call
I thought of using varargs, but there can be only one in the prototype. Another idea I've had is to use the following prototype:
public void myMethod(Object ... objs) { [...] }
...but I feel that there should be a compilation error in case it is called with something other than the expected types. Of course, a runtime check (instanceof
) could be performed, but that wouldn't be a very elegant solution, would it?
How would you do it?
回答1:
There is no way in the Java programming language to get it to work so that you can pass an arbitrary number of strings and integers, and have the compiler give an error when you pass something else than a string or integer.
回答2:
If you want it to be type safe, I'd go with this:
public myMethod(Thing<?>... thing) { ... }
And then create your Thing classes:
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;
}
}
I'll leave it to your imagination to figure out how to write StringThing. Obviously, use a better name than "Thing", but I can't help you with that one.
You then make two static methods:
public static Thing<Integer> thing(int value) {
return new IntThing(value);
}
public static Thing<String> thing(String value) {
return new StringThing(value);
}
Then you wrap each object in a call to thing
:
myMethod(thing(1), thing(2), thing(3), thing("Hello"), thing("World"));
Messy? Yup. Unfortunately, Java doesn't have the capability to hide this stuff away like other languages. Scala's implicit defs would help you here, but that comes with a whole barrel of other problems. Personally, I'd go with the instanceof
checks, but this one will make sure your code is safe at compile-time.
回答3:
There is no way to use generics to match two types, eg
public <T extends String | Integer> void myMethod(T... objs); // You can't do this
回答4:
The only possible solution to the problem you've described is the one that already stated, where the function takes in a varargs argument of type Object
. This is due to the restriction in Java where there can only be one vararg in a method signature, and that it has to be the last parameter.
It's hard to say what an alternative elegant solution might be without knowing the details of what you intend myMethod
to do.
回答5:
(Workaround)
Add to your lib:
package mylib;
public class Lang {
public static <T> T[] varargs (T...ts) {
return ts;
}
}
In your program:
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")
);
}
}
(Breaking many coding style rules)
回答6:
The syntax is allowed
public class Foo<T extends Number & List> {
...
}
The type variable T
allow types that are subtypes of Number
and List
at same type (for example, types that implementing multiple interfaces).
来源:https://stackoverflow.com/questions/6322129/multiple-object-types-for-varargs-in-a-method-prototype