Confusedly generic in Java

Can someone explain why the following code fragment 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 it returns, say, List<Long> , not List<String> ? Obviously, when I call the method, I can only put 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 long numbers to the list of String objects, and only when I started it did I see a ClassCastException .

+5
source share
5 answers

You should not expect the program to behave correctly because you are not using Generics correctly.

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

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

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

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

it doesn't even compile, and you get an error at compile time (not at runtime, which can be more confusing and intimidating).

So, in order to compile, your list must be defined as:

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

Further, regarding this statement

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

there really is no way to make sure that readProperty returns a List<Long> , so you will either have to throw it or add the @SuppressWarnings annotation. The reason for this is the compiler type erase function - the parameterized Long type is erased and returned to Runtime (when readProperty() is actually executed, and prob obtained through Reflection).

+9
source

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

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

These are two different questions.

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

For reasons of source compatibility, a raw type is allowed in these cases. You should not rely on this because, as you can see, he defeats the whole idea of ​​generics.

Regarding the second question, you can work around the problem by doing something like this:

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

This is a workaround rather than a solution, and it is not always applicable. (For example, when you need even more complex return types, such as Map<String,List<String>> )

+1
source

If you define List as an ArrayList , java does not know which object it is in. You can assign it to ArrayList<Long> , but you will get an error when calling methods or properties of elements, because the type does not match.

0
source

General class:

 public abstract class GenericClass<T> { private T managedClass; public List<T> readListProp(String propName,T object){ //do stuff using T type instead of Long,String,Double,etc } Other classes: public class FirstClass extends GenericClass<String> {... //you have a class where T from generic is replaced with String } public class SecClass extends GenericClass<Double> {... //you have a class where T from generic is replaced with Double } 
0
source

All Articles