Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confused by generics in Java

Tags:

java

generics

Can anyone explain why the following piece of code compiles?

List<Long> longNums = new ArrayList(Arrays.asList("one", "two", "three"));

Is it due to type erasure?

If I have the following method:

public <T> T readProperty(String propName, Class<T> type);

How can I make sure that it will return, say a List<Long> and not a List<String>? Obviously, at the type of calling the method I can only supply List.class and pray.

//run and pray
List<Long> longNums = readProperty("prop", List.class);

It has already happened to me that such a method incorrectly assigned a list of String objects to a list of long number, and it wasn't until I ran it, that I saw the ClassCastException.

like image 557
Preslav Rachev Avatar asked Aug 06 '15 10:08

Preslav Rachev


People also ask

What is generic error in Java?

In cases where a transaction fails, the API Gateway can use a Generic Error to convey error information to the client based on the message type (for example, SOAP or JSON). By default, the API Gateway returns a very basic error to the client when a message filter fails.

Why do we use generics instead of object?

Generics could be used to develop a better solution using a container that can have a type assigned at instantiation, otherwise referred to as a generic type, allowing the creation of an object that can be used to store objects of the assigned type.

What is the difference between polymorphism and generics?

Using Java Generic concept, we might write a generic method for sorting an array of objects, then invoke the generic method with Integer arrays, Double arrays, String arrays and so on, to sort the array elements. Polymorphism is the ability of an object to take on many forms.


3 Answers

You shouldn't expect the program to behave correctly, because you don't use Generics correctly.

First, you should not mix Generics with Raws, which means that this statement

List<Long> longNums = new ArrayList(Arrays.asList("one", "two", "three"));

is invalid (in terms of correctness). If it were:

List<Long> longNums = new ArrayList<Long>(Arrays.asList("one", "two", "three"));

it wouldn't even compile and you would get the error at compile-time (not at Runtime, which may be more confusing and scary).

So, in order to get compiled, your list should be defined as:

List<String> longNums = new ArrayList<>(Arrays.asList("one", "two", "three"));

Further, with regards to this statement

//run and pray
List<Long> longNums = readProperty("prop", List.class);

there actually no way to make sure that readProperty will return List<Long>, so you will have to either do a cast or add a @SuppressWarnings annotation. The reason for this is the type-erasure feature of the compiler - the parameterized type Long get erased and it's gone at Runtime (when actually the readProperty() is executed and the value of prob is obtained via Reflection).

like image 165
Konstantin Yovkov Avatar answered Oct 14 '22 05:10

Konstantin Yovkov


These are two separate questions really.

List<Long> longNums = new ArrayList(Arrays.asList("one", "two", "three"));

For source compatibility reasons a raw type is allowed in these cases. You shouldn't rely on this because as you can see, it defeats the whole idea of generics.

As for the second question, you can sidestep the issue by doing something like this:

public <T> List<T> readListProperty(String propName, Class<T> type);
...
List<Long> longNums = readProperty("prop", Long.class);

It's more of a workaround than a solution and isn't always applicable. (For example when you need even more complex return types, like Map<String,List<String>>)

like image 40
biziclop Avatar answered Oct 14 '22 06:10

biziclop


You missed diamond <> (this will not compile):

List<Long> longNums = new ArrayList<>(Arrays.asList("one", "two","three"));
like image 27
ka4eli Avatar answered Oct 14 '22 05:10

ka4eli