I've got the following 3 tests. The first two work, the last one doesn't. My motivation for asking this question is that I'd like to be able to cast object A
so that it has the same class as object B
, when A
is known to be a subtype of B
.
@Test
public void testWorks() {
Object bar = "foobar";
String blah = (String) bar;
System.out.println(blah); // Outputs foobar
}
@Test
public void testAlsoWorks() {
Object bar = "helloworld";
String blah = String.class.cast(bar);
System.out.println(blah); // Outputs helloworld
}
@Test
public void testfails() {
Object bar = "foobar";
String thetype = "hello";
Class stringclass = thetype.getClass();
String blah = stringclass.cast(bar); // Compiler error: incompatible types: Object cannot be converted to String
System.out.println(blah);
}
Can anyone explain why the last case fails when the first two succeed, and why this is the case? And what would be a better approach to achieve this?
You need to specify the type parameter of Class
:
Class<String> stringclass = (Class<String>) thetype.getClass();
or
Class<? extends String> stringclass = thetype.getClass();
java.lang.Class.cast(Object obj)
casts an object to the class or interface represented by this Class object.
Without specifying the type, you are not telling the compiler what class or interface is represented by the Class
instance stringclass
.
When you call String.class
, the Class
object is implicitly parametrized with the String
type.
The Java Language Specification states
The type of
C.class
, whereC
is the name of a class, interface, or array type (§4.3), isClass<C>
.
So the type of the expression
String.class
is Class<String>
. Class
is a generic class where the method cast
uses the generic type variable in its return type. So the result of
String.class.cast(bar);
is an expression of type T
, where T
has been bound to String
in this invocation.
The return type of Object#getClass()
is Class<? extends T>
where T
is the erased type of the expression it's invoked on.
In this case, that is
Class<? extends String>
However, you are assigning it to a raw reference.
Class stringclass = thetype.getClass();
Since the variable stringclass
is raw, any uses of its methods that depend on the generic type variable are erased.
So Class#cast(Object)
now has a return type of Object
which is not assignable to a String
variable.
Had you done
Class<? extends String> stringclass = thetype.getClass();
you'd be fine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With