use varargs can loose type-checking in compile time?

Leem.fin :

In the Effective Java book, Item 42 talks about varargs method.

It says:

ReturnType1 suspect1(Object... args){}
<T> ReturnType2 suspect2(T... args){}

Methods with either of these signatures will accept any parameter list. Any compile-time type-checking that you had prior to the retrofit will be lost.

I get confused.

Question one: why retrofit/refactor method to varargs could loose type-checking had before in the method? In above two method singature, isn't Object and T the type specified there? In which way we could loose type-checking exactly? The book explained that by referring to an example author made but I don't get it:

======= the example author use to convince readers =======

the author made an example of Arrays.asList(...), that before Java 1.5, the following code would raise compile time error for type checking:

int[] digits = {3,1,4}
// Compiler error: asList(Object[]) in Arrays can't be applied to (int[])
System.out.println(Arrays.asList(digits));

and since java1.5 and above, due to the introduction of varargs, the above code is fine with compiler. The Arrays.asList(digits) wraps the whole int[] to one object so that the Arrays.asList(digits) returns a one-element array of arrays List<int[]>.

Question two: I understand this example, it indeed is an example of loosing type-checking, but the action of wrapping primitive int array(digits) to an object is conducted by Arrays.asList() method, not the vargars usage (or am I wrong here?), why the author use this example to say the all methods with those two signatures can loose type-checking during compiler time? how? Any examples to convince me?

Kayaman :

In above two method singature, isn't Object and T the type specified there?

Sort of, but not really. The T will be erased at runtime. A simple example is Arrays.asList(1, 2L, "3") which packs an Integer, Long and String. This results in the compile-time type of T becoming <Serializable & Comparable> (which is the supertype of all those 3 classes). So depending on what you pass, the T "adapts" becoming Object in the widest case.

..the action of wrapping primitive int array(digits) to an object is conducted by Arrays.asList() method, not the vargars usage (or am I wrong here?)

Arrays.asList() will just assign each element in the input array to a list. Due to varargs, the int[] {1, 2, 3} will be one element (so T becomes int[] since int is not an object, as opposed to Integer {1, 2, 3} where T becomes Integer). Of course the code could be written so that it checks if there's a single input element, then checks if it's an array, then converts int[] to List<Integer>, but that would break the generics (int[] becomes Integer suddenly), and that wouldn't be the only problem with it.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=305479&siteId=1