Why would I use java.lang.Class.cast [duplicate]
Asked Answered
B

8

20

I recently stumbled upon a piece of code that went like this:

Object o = .. ;
Foo foo = Foo.class.cast(o);

I was actually not even aware that java.lang.Class had a cast method, so I looked into the docs, and from what I gather this does simply do a cast to the class that the Class object represents. So the code above would be roughly equivalent to

Object o = ..;
Foo foo = (Foo)o;

So I wondered, why I would want to use the cast method instead of simply doing a cast "the old way". Has anyone a good example where the usage of the cast method is beneficial over doing the simple cast?

Backrest answered 26/10, 2011 at 8:38 Comment(0)
S
8

I don't think it's often used exactly as you have shown. Most common use I have seen is where folks using generics are trying to do the equivalent of this:

public static <T extends Number> T castToNumber(Object o) {
    return (T)o;
}

Which doesn't really do anything useful because of type erasure.

Whereas this works, and is type safe (modulo ClassCastExceptions):

public static <T extends Number> T castToNumber(Object o, Class<T> clazz) {
    return clazz.cast(o);
}

EDIT: Couple of examples of use from google guava:

Stichter answered 26/10, 2011 at 8:47 Comment(5)
This is still equivalent to (Number) o since a cast has no influence over the actual type of an object.Orator
Not really, but keep in mind this is a simplified example, and usually o and clazz would be determined at runtime, rather than hardcoded. Integer x = castToNumber(o, Integer.class) is valid here, but Integer x = (Number)o wouldn't be. Maybe I should have left off the Number bit for the example? Maybe castToNumber was a bad choice for method name?Stichter
The point I'm trying to make is, that you still need to have a left side to your assignment, where you need to state an explicit class. So you can always simply write T x = (T) o;Orator
I meant T as a general placeholder for any class you might think about, not as a generics construct. In terms of real code like this: Object o = new Object(); Integer i = (Integer) o; Obviously this code will throw a ClassCastException at runtime, but it will show no compiler warning.Orator
I misunderstood your response for a moment, but I think I understand now. Your comment is reasonable for client code, but if you are writing a library, it's not always clear exactly what the uses are going to be. I've added a couple of concrete uses from guava libs.Stichter
G
4

In Java there is often more than one way to skin a cat. Such functionality may be useful in cases where you have framework code. Imagine a method which accepts a Class object instance and an Object instance and returns the Object case as the class:

public static void doSomething(Class<? extends SomeBaseClass> whatToCastAs,Object o)
    {
        SomeBaseClass castObj =  whatToCastAs.cast(o);
        castObj.doSomething();
    }

In general, use the simpler casting, unless it does not suffice.

Greave answered 26/10, 2011 at 8:44 Comment(3)
You're kidding, right? Why would you not simply write ((SomeBaseClass) o).doSomething();?Orator
@nfechner, because you can't always do that. I guess the best example is for (part of) an implementation of the JDBC public <T> T unwrap(Class<T> iface) method. There you could do something like: return iface.cast(this);Stopover
(CastTarget)o is compile time, foo.getClass().cast(0) is runtimeDepot
G
2

In some cases, you only know the type to cast an object to during runtime, and that's when you have to use the cast method.

Graven answered 26/10, 2011 at 8:45 Comment(0)
B
2

There is absolutely no reason to write Foo.class.cast(o), it is equivalent to (Foo)o.

In general, if X is a reifiable type, and Class<X> clazz, then clazz.cast(o) is same as (X)o.

If all types are reifiable, method Class.cast() is therefore redundant and useless.

Unfortunately, due to erasure in current version of Java, not all types are reifiable. For example, type variables are not reifiable.

If T is a type variable, cast (T)o is unchecked, because at runtime, the exact type of T is unknown to JVM, JVM cannot test if o is really type T. The cast may be allowed erroneously, which may trigger problems later.

It is not a huge problem; usually when the programmer does (T)o, he has already reasoned that the cast is safe, and won't cause any problem at runtime. The cast is checked by app logic.

Suppose a Class<T> clazz is available at the point of cast, then we do know what T is at runtime; we can add extra runtime check to make sure o is indeed a T.

check clazz.isInstance(o);
(T)o;

And this is essentially what Class.cast() does.

We would never expect the cast to fail in any case, therefore in a correctly implemented app, check clazz.isInstance(o) must always succeed anway, therefore clazz.cast(o) is equivalent to (T)o - once again, under the assumption that the code is correct.

If one can prove that the code is correct and the cast is safe, one could prefer (T)o to clazz.cast(o) for performance reason. In the example of MutableClassToInstanceMap raised in another answer, we can see obviously that the cast is safe, therefore simple (T)o would have sufficed.

Buckish answered 26/10, 2011 at 11:36 Comment(2)
"If all types are reifiable, method Class.cast() is therefore redundant and useless." Not true. Class.cast() is necessary when you don't know the class at compile time, and only have a class object at runtimeHinson
@Hinson If java is fully reifiable, runtime knows the actual type of T, so it can check (T)o to make sure o is indeed of type T. There is no need for Class<T>.cast(o) then.Buckish
D
1

class.cast is designed for generics type.

When you construct a class with generic parameter T, you can pass in a Class. You can then do the cast with both static and dynamic checking, which (T) does not give you. It also doesn't produce unchecked warnings, because it is checked (at that point).

Dall answered 26/10, 2011 at 8:45 Comment(0)
M
1

The common sample for that is when you retrieve from persistent layer a collection of entity referenced with a Class Object and some conditions. The returned collection could contain unchecked objects, so if you just cast it as pointed G_H, you will throw the Cast Exception at this point, and not when the values are accessed.

One example for this is when you retrieve a collection from a DAO that returns an unchecked collection and on your service you iterate over it, this situation can lead to a ClassCastException.

One way to solve it, as you have the wanted class and the unchecked collection is iterate over it and cast it inside the DAO transforming the collection in a checked collection and afterwards return it.

Monologue answered 26/10, 2011 at 9:4 Comment(0)
S
0

Because you might have something this:

Number fooMethod(Class<? extends Number> clazz) {
    return clazz.cast(var);
}
Srinagar answered 26/10, 2011 at 8:44 Comment(0)
H
0

A "cast" in Java, e.g. (Number)var, where the thing inside the parentheses is a reference type, really consists of two parts:

  • Compile time: the result of the cast expression has the type of the type you cast to
  • Run time: it inserts a check operation, which basically says, if the object is not an instance of that class, then throw a ClassCast Exception (if the thing you're casting to is a type variable, then the class it checks would be the lower bound of the type variable)

To use the syntax, you need to know the class at the time you write the code. Suppose you don't know at compile-time what class you want to cast to; you only know it at runtime.

Now you would ask, then what is the point of casting? Isn't the point of casting to turn the expression into the desired type at compile time? So if you don't know the type at compile time, then there is no benefit at compile-time, right? True, but that is just the first item above. You're forgetting the runtime component of a cast (second item above): it checks the object against the class.

Therefore, the purpose of a runtime cast (i.e. Class.cast()) is to check that the object is an instance of the class, and if not, throw an exception. It is roughly equivalent to this but shorter:

if (!clazz.isInstance(var))
    throw new ClassCastException();

Some people have mentioned that Class.cast() also has a nice return type that is based on the type parameter of the class passed in, but that is just a compile-time feature that is provided by a compile-time cast anyway. So for that purpose there is no point in using Class.cast().

Hinson answered 26/10, 2011 at 20:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.