As we all know the Generics about Java Collections that E or a wildcard ? is required to instantiate the allowed contents / objects in a particular collection.
My question is there a way we could know the wildcard or object of a particular collection from the code below?
Object inbound = java.io.ObjectInputStream().readObject();
if(inbound instanceof List<?>) {
// know `?.getClass()`
}
No. Due to type erasure, during runtime there is no way to differentiate between Lists.
You can only find the type parameters if inbound is a class that defines its type parameters in a type declaration. For example, suppose you serialized an instance of NodeList that was declared like this:
final class NodeList extends ArrayList<Node> { }
Then when you deserialize it, you can do this:
Object inbound = ois.readObject();
if (inbound instanceof List<?>) {
Type t = inbound.getClass().getGenericSuperclass();
if (t instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) t;
for (Type p : pt.getActualTypeArguments()) {
if (p instanceof TypeVariable<?>)
System.out.println("Unknown");
else
System.out.println(p); /* Prints "interface Node" */
}
}
}
You could if you would be certain that the list contains at least one element, in which case you could simply call getClass on that.
Otherwise this wouldn't really be possible, although you could serialize the correct Class object along with the List.
IMHO, the best solution if you need to do this is with Guice: http://blog.publicobject.com/2008/11/guice-punches-erasure-in-face.html.
As others have mentioned, type erasure is the source of the problems. A good explanation is at http://docs.oracle.com/javase/tutorial/java/generics/erasure.html.
You can take a look at the source for ArrayList and see an example of how this works. The ArrayList is holding an Object[] (line 111). It doesn't know the types of the objects. You can see that the 'type safety' is actually just achieved via casts, e.g. line 371.
Related
So, I want to have a List of types, then loop through the List and check if an Object is instance of the type in that list.
This is how I would imagine it to work, but that is no Java syntax.
Type1.class also doesn't work
List<Object> types = new ArrayList();
types.add(Type1);
types.add(Type2);
for (Object type : types) {
if (someObject instanceof type) {
doSomething();
}
}
or the same thing with List<Class> or something like that
this clearly doesn't work, but I dont know whats the best way to do it. Of course I could just hardcode every Object I want to check, but that doesn't seem that elegant.
From the Java docs :
In Java instances of the Class class represent classes and interfaces in a running Java application.
You could use Class::isInstance method to determine if object is instance of given type and then apply processing based on this evaluation:
List<Class<?>> types = new ArrayList<>();
types.add(String.class);
types.add(Integer.class);
String someObject = "someString";
for (Class<?> type : types) {
if (type.isInstance(someObject)) {
// do smoething
}
}
These kinds of requirements call for the use of reflection. There is a class in Java meant to represent the type of an object: class Class. Instances of that class effectively represent the types of objects. So you could do:
List<Class<?>> types = new ArrayList<>();
types.add(Type1.class);
types.add(Type2.class);
for (Class<?> type : types) {
if (type.isAssignableFrom(someObject.getClass())) {
doSomething();
}
}
Note that in this situation it's important to know whether you want to check if your target object has exactly the same type as a type in a list, or can be assigned to the type in the list. The code sample covers the second option because it's closer to the original intent. If you need an exact match, you would do:
object.getClass() == type;
See also Class.isInstance vs Class.isAssignableFrom
I have a list and am trying to add some members of Custom Class type.
List<MyCustomClass> myList = new ArrayList<MyCustomClass>();
myList.addAll(queryResponse.getRecords());
Actually queryResponse is again a custom class which has 2 members;
private Long totalRecords;
private List<T> records;
My question is I want to cast the individual members of myList (i.e. queryResponse.getRecords()) to MyCustomClass.
They are of type "Object" at runtime once the query is executed.
How do I do that ?
Assuming queryResponse.getRecords() return Object, you can type caste it like this
myList.addAll((MyCustomClass)queryResponse.getRecords());
myList.addAll((List)queryResponse.getRecords());
should work, producing a type safety warning.
By doing this you bypass the compile time type safety guarantee, so it's up to you to make sure you don't get ClassCastException somewhere later.
What about:
List<MyCustomClass> myList = new ArrayList<MyCustomClass>();
for (Object element : queryResponse.getRecords()) {
if (element instanceof MyCustomClass) {
// this will never fail because of the check above
myList.add((MyCustomClass)element);
}
else {
// do something here in case element has the wrong type
System.err.println("Found incompatible record!");
}
}
This uses the instanceof operator to ensure the cast won't fail. What you do exactly when the type of the object is incompatible depends on your requirements.
Hi guys i got a problem with an unsafe cast operation.
Here is the problem. I gotta Constructor which accepts different types of Orders (PlayList, UserOperations, etc.) or should. So i decided to give it a Parameter as Object and check the type of the received once called. The Problem is one of those is a parameterized ArrayList (ArrayList < PlayList >) and since it is impossible to check a parameterized ArrayList I have to "dig" in. At first step i check if it is an ArrayList, at second I go into it an check the type of its content.
The problem afterwards is I get an unsafe cast warning which i dunno yet how to handle.
Greetings
public Order(int aTyp, Object aOrderContent) {
this.orderTyp = aTyp;
if (aOrderContent instanceof ArrayList< ? >) {
ArrayList<?> objList = (ArrayList< ? >)aOrderContent;
if (objList.get(0) != null && (objList.get(0)) instanceof PlayList) {
playList.addAll((ArrayList<PlayList>)aOrderContent) ;
}
} else if (aOrderContent instanceof UserOP) {
}
}
Rethink your design. Don't make the constructor take an Object. This is too opaque and allows consumers of your code to pass any type. It sounds like you should be using a generic class instead (though it's hard to tell based on your partial example). Possible solution:
// Might need an upper bound on T if you want to limit the allowed parameterizations
class Order<T> {
private final int orderTyp;
private final List<T> someList = new ArrayList<>();
public Order(int aTyp, List<t> aOrderContent) {
this.orderTyp = aTyp;
someList.addAll(aOrderContent);
}
}
Keep in mind it may be better to use an enum instead of int for the orderTyp, if you know (at compile time) all the possible type values.
Side note: if a List is empty, List#get(0) with throw an exception, not return null.
Instead of making the constructor take an Object overload you constructor. Have one take an List<?> and one take a UserOP ect. Also, it would be ideal if all the options for the List extended from the same interface so you could have List<MyInterface> instead of List<?>
I have this code below (which is deserializing a class):
....
Type type = field.getGenericType();
if (type instanceof ParameterizedType) {
ParameterizedType ptype = (ParameterizedType) type;
if(c.getSimpleName().equals("Vector")){
Class pta = (Class) ptype.getActualTypeArguments()[0];
Vector<what to put here> v = (Vector)field.get(obj);
if(v == null){
v = new Vector<what to put here>();
field.set(obj, v);
}
....
My question is how do I change the Vector to take a certain type of data just from knowing the class name of what it took before (which would be the pta var)?
Generics are resolved at compile time, so there is no way to do this as you have listed. Just use a Vector<Object> or Vector
Using Vector instead of Vector<what to put here> will work. Anyway on runtime the generic erasure logic is used and your vector will not have a specified type anymore.
Regarding your comment related to the primitive type, note that you will not be even able to insert primitive types into an Vector. From javadoc: "The Vector class implements a growable array of objects". When you are adding primitives autoboxing is used to convert them into their object counter part.
interface Foo<T> { ... }
class Bar implements Foo<Baz> { ... }
I've got a Bar object. How to get the value of T for it (Baz)?
So far, I only managed to get the interface and T, but I can't see a way to get its value.
Thanks in advance.
Type type = bar.getClass().getGenericInterfaces()[0];
if (type instanceof ParameterizedType) {
Type actualType = ((ParameterizedType) type).getActualTypeArguments()[0];
System.out.println(actualType);
}
Of course, in the general case, you should iterate over the array, rather than assuming it has excatly one element ([0]). With the above example, you can cast actualType to java.lang.Class. In other cases it may be different (see comment by meriton)
If you already have Guava on the classpath, this is a bit more robust as you specify the interface/superclass by type rather than index.
TypeToken<?> baz = TypeToken.of(Bar.class).resolveType(Foo.class.getTypeParameters()[0]);
System.out.println(baz.getRawType()); // class Baz