Reputation: 42592
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?
Upvotes: 4
Views: 424
Reputation: 2083
This is a type system subject.
It is possible to assign new Object[]{1, 2L, "3"}
to Object[]
and it is also possible to assign new Integer[]{1, 2, 3}
to Object[]
as Arrays are covariant in Java. It isn't possible to assign int[]
to Object[]
, but it is possible to assign int[]
to Object... args
.
A method which takes Object[]
as a parameter will accept an array of Objects of any type, before or after Java 1.5. But a method which takes Object... args
as a parameter (only after Java 1.5) can also accept int[]
.
Upvotes: 0
Reputation: 73538
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.
Upvotes: 1
Reputation: 6703
ReturnType1 suspect1(Object... args){}
Since all objects inherit from the Object
class, its useless for the compiler to perform the compile-time type-checking.
<T> ReturnType2 suspect2(T... args){}
Also here, the variable type T
may be everything you want at runtime therefore its useless for the compiler to check the type.
To know If using vararg you lose type-checking, write a few lines of code using vararg and deliberately pass not allowed types as vararg: you'll see if the compiler fails o if will be thrown an exception at runtime.
Upvotes: 0