Java Generators and Type Erasure

Given the following code:

public void example(Object o) { if(o instanceof List<MyType>) //do something } 

I understand that this is not possible (and why this is not possible), given how Java handles generics and erases the type.

My question is: what is the best / cleanest way to achieve this? Or the only thing I can do is check if o List<?> ?

+4
source share
5 answers

You cannot check more than o instanceof List<?> .

The type of security you get from Java generics only happens at compile time. A method like yours (which takes an object and then tries to figure out what to do) doesn't work very well with this design. I can understand why such a dynamic method was necessary at one time, but consider supplementing it with versions for typed parameters:

 public void example(Object o) { if(o instanceof List<?>) example((List)o); // can only hope that the type is correct here } public void example(List<MyType> list){ // do something } 

In cases where they can be used, you get the full benefit of the generics. In other cases, you should depend on people reading your Javadoc and passing only in the right types.

What even the above approach cannot do are two different code paths for List<TypeA> and List<TypeB> . If this is really necessary for you, consider using your own cover types ListOfTypeA , ListOfTypeB .

Depending on what you need to do, it’s not even necessary to look at the erased type of the list as a whole and just work with the types of individual elements:

  for (Object o: list){ if (o instanceof TypeA){ } if (o instanceof TypeB){ } } 
+2
source

Without checking the types of all the elements in the list, it is impossible to determine the type of the general parameter in Java, since this exists only at compile time and is deleted before execution.

My suggestion would be if you absolutely did not need the method to accept an object (for example, to conform to the interface specification or override Object.equals) to take the correct type that you want as a parameter for the method and overload the method with various other types that may be required to run the method with.

0
source

Java erases the type information for generics after compilation, so you cannot dynamically check the type parameter.

If all paths to this code limit the type parameter, then:

 // Return true if object is a list of MyType, false if it is not a list, or is // empty boolean isListOfMyType(Object o) { if (o instanceof List) { List<?> l = (List<?) o; return (l.size() > 0 && (l.get(0) instanceof MyType) } return true; } 

is typical, although it will only work if the list is not empty. If not, you will need to modify the above to check if all elements of testof test pass (or if they are null if you allow null in the list).

Another alternative is to create a subclass that extends the ArrayList<MyType> expression and uses this to validate instanceof .

Finally, but not least, the existence of a subclass that implements List<MyType> will allow you to obtain a type parameter using the Class.getGenericInterfaces() method. See more details.

For any of these last two working methods, you must make sure that creating a list always creates one of these types. I.e. if the caller goes and creates his own ArrayList<MyType> , it will not work.

0
source

In contrast to the generally accepted and rarely known style erasure, you can avoid it, which means that the caller has the opportunity to find out what common parameters were used during the conversation.

Please take a look at: Using TypeTokens to Retrieve Common Parameters

thanks

0
source

Perhaps by checking the type of the object at runtime, maybe something like:

 if (o.getClass() == List.class) ... 

Obviously, you will have to go deeper into the class type of the object to find out if it matches the exact correspondence of List<> and the types of list items.

-3
source

Source: https://habr.com/ru/post/1300828/


All Articles