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?
Sort of, but not really. The
Twill be erased at runtime. A simple example isArrays.asList(1, 2L, "3")which packs anInteger,LongandString. This results in the compile-time type ofTbecoming<Serializable & Comparable>(which is the supertype of all those 3 classes). So depending on what you pass, theT"adapts" becomingObjectin the widest case.Arrays.asList()will just assign each element in the input array to a list. Due to varargs, theint[] {1, 2, 3}will be one element (soTbecomesint[]sinceintis not an object, as opposed toInteger {1, 2, 3}whereTbecomesInteger). 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 convertsint[]toList<Integer>, but that would break the generics (int[]becomesIntegersuddenly), and that wouldn't be the only problem with it.