Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is casting the class returned by getClass() of a generic instance type always safe in Java?

I am not sure how to word the title of this question in a concise way. There are a few related questions I have found, for instance this one, but none of them seem to answer the question I have explicitly.

But essentially what I am asking is this:

Consider the following code


static <A, B> Class<? extends A> getLeftClass(Pair<A, B> tuple) {
   A left = tuple.getLeft();
   return left.getClass();
}

As is, this code does not compile. The compilation fails with the error Type mismatch: cannot convert from Class<capture#20-of ? extends Object> to Class<? extends A>

I think this is essentially because getClass returns a type Class<? extends Object> but the compiler is expecting Class<? extends A>.

A solution is to cast the class as follows:


static <A, B> Class<? extends A> getLeftClass(Pair<A, B> tuple) {
   A left = tuple.getLeft();
   return (Class<? extends A>) left.getClass();
}

This compiles. However, there is a warning because of an unchecked cast.

My question is, is the warning justified? Is there a legitimate reason not to do this? Or is this just a case where the compiler can't verify that it is correct, but it will always work as long as tuple.getLeft() is indeed an instance of A?


By the way, the Pair class is this one, from the Apache commons library

like image 719
William Oliver Avatar asked Oct 16 '20 15:10

William Oliver


People also ask

What is class casting in Java?

The java. lang. Class. cast() method casts an object to the class or interface represented by this Class object.

How do you declare a generic type in a class explain?

The declaration of a generic class is almost the same as that of a non-generic class except the class name is followed by a type parameter section. The type parameter section of a generic class can have one or more type parameters separated by commas.

What is generic method in Java?

Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type, but the type parameter's scope is limited to the method where it is declared. Static and non-static generic methods are allowed, as well as generic class constructors.

How do you declare a generic class in Java?

A Generic Version of the Box Class To update the Box class to use generics, you create a generic type declaration by changing the code "public class Box" to "public class Box<T>".


1 Answers

The warning is justified, as it allows in turn other unsafe operations that would not cause a warning. The type parameter of Class allows you to perform dynamic runtime casts and instantiations and the type safety of those operations depends on the validity of the type parameter.

In other words, your method allows the following operation:

Pair<List<String>,?> p = Pair.of(new ArrayList<>(), null);

List<Integer> listOfI = new ArrayList<>(Arrays.asList(1, 2, 3));
List<String> listOfS = getLeftClass(p).cast(listOfI);
listOfS.set(1, "foo");

This situation is called heap pollution and Java's generic type system guarantees that this situation can not occur with warning free source code. You get a warning and have the risk.

Likewise, we could do:

List<String> stringList = getLeftClass(p)
    .getConstructor(Collection.class).newInstance(listOfI);
assert stringList.get(0) instanceof String;// will fail

There are similar 3rd party libraries, e.g. deserializers for XML or JSON, with similar assumptions about the type safety when being provided with a Class object as parameter to describe the assumed return type (or a component of the result).

like image 152
Holger Avatar answered Nov 01 '22 21:11

Holger