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?
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.