Is it possible to use a generic type of a generic Java method to force an argument type?

I would like to use a generic type to ensure that the method arguments are of the same type, for example:

public static <T> void x(T a, T b) 

I would suggest that the two arguments (a and b) that are passed to this method should always be of the same type. But, to my surprise, I managed to pass arguments of any type (even primitives) to the x method, as if T had been erased from Object, no matter what arguments were passed.

The only work I have found so far has been to use "extends" as follows:

 public static <T, U extends T> void x(T a, U b) 

But although I can live with it, this is not what I wanted.

Is there a way to use a generic type to force the type of all method arguments?

+53
java generics types
May 13 '15 at 14:03
source share
6 answers

If I understand your question correctly, you want:

 x(10, "x"); 

compile failure. Now think about it:

 Integer i = 10; String s = "x"; Object o1 = i; Object o2 = s; x(o1, o2); 

In this case, both objects are the same. I don’t think there is any way to really provide what you want - when you pass in your Object argument, you can always call it with two different types without any warnings / errors.

You can specify the type you want to use using it as follows:

 ClassName.<Type>x(obj1, obj2); 

And this is the only way to do it.

+20
May 14 '15 at 3:27
source share

If I understand correctly, one way to do this is to explicitly specify the type T instead of allowing the compiler to make it the most direct superclass in the case of passing two objects of different types as arguments. Take something like this, for example:

 public class Test { public static void main(String[] args) { Test.x(5.0, 5); // This works since type is inferred to be Number Test.<Integer>x(5, 5); // This works since type is stated to be Integer Test.<Integer>x(5.0, 5); // This doesn't; type is stated to be Integer and Double is passed in } public static <T> void x(T a, T b) { } } 
+29
May 13, '15 at 14:13
source share

Why this should be a problem, firstly, for me it is a bit foggy. I suspect that you instead misunderstood how to use the type system.

What can we do with <T> void x(T a, T b) ? Well, not so much. Inside the body of x , T same as Object , so we could do something like call toString on a and b to print them. A.

In fact, there is no practical reason for a , and b must be of the same type. It is simple that they have a common type, and this type is Object or its subtype. In fact, there is no clear reason why <T> void x(T a, T b) should really be common at all.

  • The body of the method does not care what the actual types a and b , because they still cannot use them.
  • The call site doesn't care what the actual types a and b , because x is the void method, so it's a black hole.

It is more typical for a method to have a result, for example, <T> List<T> Arrays.asList(T...) :

 // This will cause a compile error because // the type inferred must be compatible // with the return assignment. List<Integer> r = Arrays.asList(1, 1.0); 

Or rating:

 // We don't care what the actual types of // a and b are, just that we can call bar() // on them. // Note: this method does not need to be generic. <T extends Foo> void x(T a, T b) { a.bar(); a.bar(); } 

Or an assessment that claims some relation:

 // We don't care what the actual types of // a and b are, just that we can compare // them to each other. <T extends Comparable<T>> T max(T a, T b) { return (a.compareTo(b) < 0) ? b : a; } 
+14
May 13 '15 at 3:22
source share

You can explicitly specify the type parameter when calling the method. For example:

  <String>x("hello", "world"); 

However, if you do not explicitly specify a type parameter and rely only on a Java type inference function, I do not think that you can not only in Generics, but also in general.

The method parameter type is not a specific type, but rather something that denotes a set of applicable types (even this set can contain only one type, in the case of final classes, for example).

For example, this method:

 public void x(Something a) { } 

denotes a method that must have a type from a set of types that are compatible with Something (i.e., Something and all its subtypes).

The same goes for Generics.

+11
May 13, '15 at 14:10
source share

Presumably, you are not calling your generic method in a generic way, which is why it was considered as a call to x(Object a, Object b) . In this example:

 public class Test { static <T> void x(T a, T b) { } public static void main(String[] args) { x(1, 2); // compiles Test.<String>x(1, 2); // does not compile Test.<String>x("a", "b"); // compiles } } 

The first call to x is not made in general, so it compiles. The second call equates T to String , so it fails because 1 and 2 not Strings . The third call compiles because it passes correctly in Strings .

+10
May 13 '15 at 14:14
source share

It worked for me

 public static <T> void x(T a, T b, Class<T> cls) { } 

now it compiles

 public static void main(String[] args) throws Exception { x(1, 2, Integer.class); } 

and it is not

 public static void main(String[] args) throws Exception { x(1, "", Integer.class); } 
+7
May 13 '15 at
source share



All Articles