Leem.fin
Leem.fin

Reputation: 42592

use varargs can loose type-checking in compile time?

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

Answers (3)

goedi
goedi

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

Kayaman
Kayaman

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

user2342558
user2342558

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

Related Questions