I have a generic function foo, which accepts any type and prints them out.
public static <T> T foo(T... arg) {
List<T> foo = Arrays.asList(arg);
for (T t : foo) {
System.out.println(t);
}
return null;
}
How do I make sure that the arguments received are of only 1 type. For example, {1,'a',3} should be invalid. It should either be all numbers or all characters. I want to accept either ALL integers or ALL Characters.
You can in fact do something like this:
static <T extends Comparable<T>> void f(T... args) {
System.out.println(java.util.Arrays.toString(args));
}
public static void main(String[] args) {
// all one type -- all of these compile!
f(1, 2, 3); // prints "[1, 2, 3]"
f('a', 'b', 'c'); // prints "[a, b, c]"
f("a", "b", "c"); // prints "[a, b, c]"
f(1D, 2D, 3D); // prints "[1.0, 2.0, 3.0]"
// this is not preventable
f(1, (int)'a', 3); // prints "[1, 97, 3]"
// mixture of types -- none of these compile!
//f(1, 'a', 3); // compilation error!
//f(1, '2', "3"); // compilation error!
//f("a", "b", 'c'); // compilation error!
//f(1, 2, 3D); // compilation error!
}
This takes advantage of the fact that:
Integer implements Comparable<Integer>
Character implements Comparable<Character>
String implements Comparable<String>
Double implements Comparable<Double>
So to match those types (and possibly others), we bound T
as follows:
This does include things eg java.util.Date
, which implements Comparable<Date>
, and countless many other types, but is probably the best that you can do if you also want to allow Integer
and Character
.
Nonetheless, do keep in mind that Integer
, Character
, String
, are all Object
, so in fact a bunch of those mixed together IS a list of one type: Object
.
Thankfully, it's NOT the case that Object implements Comparable<Object>
; otherwise the above solution wouldn't work.
The T
part means that all the args
will be the same type.
If you wanted to restrict your generic type to be only a certain type or sub-type (eg Integer) you can do the following:-
public static <T extends Integer> T foo(T... arg) {
List<T> foo = Arrays.asList(arg);
for (T t : foo) {
System.out.println(t);
}
return null;
}
I'm not a java developer but what you can do as one possible option is use generic collection of objects of type T.
public static <T> T foo(List<T> arg) {
List<T> foo = arg;
for (T t : foo) {
System.out.println(t);
}
return null;
}
You can do what you want to do like this:
YourClass.<Type>foo(params);
Specifically:
YourClass.<Integer>foo(1, 2, 3);
and
YourClass.<Character>foo('a', 'b', 'c');
You can take advantage of the fact that foo
returns the same type <T>
as the input parameters.
You can infer <T>
by defining the return type:
Integer i1 = 4;
String s = "string";
final Integer i2 = foo(i1, s); // error, only Integer allowed
If you do not specify a return type, the type <T>
will be inferred as Object
, and thus all sub-classes will be accepted.
Alternatively, as @Finbarr mentions, you can infer the type via
Foo.<Integer>foo(i1, s); // error, only Integer allowed
To declare a bounded type parameter, list the type parameter's name, followed by the extends keyword, followed by its upper bound.
Following method will only accept numbers as it's parameters.
public static <T extends Comparable<T>> T maximum(T firstNumber, T secondNumber)
{
system.out.println(secondNumber.compareTo(firstNumber));
}
If you don't extend it with Comparable then compareTo()
will not be available.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.