Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Having being taught during my C++ days about evils of the C-style cast operator I was pleased at first to find that in Java 5 java.lang.Class had acquired cast method.

I thought that finally we have an OO way of dealing with casting.

Turns out Class.cast is not the same as static_cast in C++. It is more like reinterpret_cast. It will not generate compilation error where it is expected and instead will defer to runtime. Here is a simple test case to demonstrate different behaviors.

package test;

import static org.junit.Assert.assertTrue;

import org.junit.Test;


public class TestCast
{
    static final class Foo
    {
    }

    static class Bar
    {
    }

    static final class BarSubclass
        extends Bar
    {
    }

    @Test
    public void test ( )
    {
        final Foo foo = new Foo( );
        final Bar bar = new Bar( );
        final BarSubclass bar_subclass = new BarSubclass( );

        {
            final Bar bar_ref = bar;
        }

        {
            // Compilation error
            final Bar bar_ref = foo;
        }
        {
            // Compilation error
            final Bar bar_ref = (Bar) foo;
        }

        try
        {
            // !!! Compiles fine, runtime exception
            Bar.class.cast( foo );
        }
        catch ( final ClassCastException ex )
        {
            assertTrue( true );
        }

        {
            final Bar bar_ref = bar_subclass;
        }

        try
        {
            // Compiles fine, runtime exception, equivalent of C++ dynamic_cast
            final BarSubclass bar_subclass_ref = (BarSubclass) bar;
        }
        catch ( final ClassCastException ex )
        {
            assertTrue( true );
        }
    }
}

So, these are my questions.

  1. Should Class.cast() be banished to
    Generics land? There it has quite a few legitimate uses.
  2. Should compilers generate compile errors when Class.cast() is used and illegal conditions can be determined at compile time?
  3. Should Java provide a cast operators as a language construct similar to C++?
share|improve this question
2  
Simple answer: (1) Where is "Generics land"? How is that different from how the cast operator is used now? (2) Probably. But in 99% of all Java code ever written, it is extremely unlikely for anyone to use Class.cast() when illegal conditions can be determined at compile time. In that case, everybody but you just uses the standard cast operator. (3) Java does have a cast operator as a language construct. It is not similar to C++. That is because many of Java's language constructs are not similar to C++. Despite the superficial similarities, Java and C++ are quite different. – Daniel Pryden Oct 12 '09 at 16:24
1  
Why -1--------- – Alexander Pogrebnyak Apr 26 '12 at 22:40

5 Answers

up vote 18 down vote accepted

I've only ever used Class.cast(Object) to avoid warnings in "generics land". I often see methods doing things like this:

@SuppressWarnings("unchecked")
<T> T doSomething() {
    Object o;
    // snip
    return (T) o;
}

It's often best to replace it by

<T> T doSomething(Class<T> cls) {
    Object o;
    // snip
    return cls.cast(o);
}

That's the only usecase for Class.cast(Object) I've ever come across.

Regarding compiler warnings: I suspect that Class.cast(Object) isn't special to the compiler. It could be optimized when used statically (i.e. Foo.class.cast(o) rather than cls.cast(o)) but I've never seen anybody using it - which makes the effort of building this optimization into the compiler somewhat worthless.

share|improve this answer
My last word is that if Foo.class.cast(o) would behave like (Foo) and (Foo) were prohibited it would lead to 2 outcomes: less casual casting ( nobody likes to type a lot ). Easier search for cast instances in the source code. With that I'll leave the Dream Land and banish the Class.cast to Generics Land :). – Alexander Pogrebnyak Oct 12 '09 at 16:31
3  
I think the correct way in this case would be to do an instance of check first like this: if (cls.isInstance(o)){ return cls.cast(o); } Except if you're sure the type will be correct, of course. – Puce Jan 19 '12 at 8:57
I think that cast() works quite nicely in some factory type patterns. For example casting data from some XDR to some internal representation based on a .class definition. This works much like ObjectiveC casting – Daniel Voina Jun 19 at 11:06

It's always problematic and often misleading to try and translate constructs and concepts between languages. Casting is no exception. Particularly because Java is a dynamic language and C++ is somewhat different.

All casting in Java, no matter how you do it, is done at runtime. Type information is held at runtime. C++ is a bit more of a mix. You can cast a struct in C++ to another and it's merely a reinterpretation of the bytes that represent those structs. Java doesn't work that way.

Also generics in Java and C++ are vastly different. Don't concern yourself overly with how you do C++ things in Java. You need to learn how to do things the Java way.

share|improve this answer
Not all information is held at runtime. As you can see from my example (Bar) foo does generate an error at compile time, but Bar.class.cast(foo) does not. In my opinion if it is used in this manner it should. – Alexander Pogrebnyak Oct 12 '09 at 15:56
1  
@Alexander Pogrebnyak: Don't do that then! Bar.class.cast(foo) explicitly tells the compiler that you want to do the cast at runtime. If you want a compile-time check on the validity of the cast, your only choice is to do the (Bar) foo style cast. – Daniel Pryden Oct 12 '09 at 16:17

First, you are strongly discouraged to do almost any cast, so you should limit it as much as possible! You lose the benefits of Java's compile-time strongly-typed features.

In any case, Class.cast() should be used mainly when you retrieve the Class token via reflection. It's more idiomatic to write MyObject myObject = (MyObject)object rather than MyObject myObject = MyObject.class.cast(object).

EDIT: Errors at compile time

Over all, Java performs cast checks at run time only. However, the compiler can issue an error if it can prove that such casts can never succeed (e.g. cast a class to another class that's not a supertype and cast a final class type to class/interface that's not in its type hierarchy). Here since Foo and Bar are classes that aren't in each other hierarchy, the cast can never succeed.

share|improve this answer
I totally agree that casts should be used sparingly, that's why having something that can be easily searched would be of a great benefit for code refactoring/maintaining. But the problem is that although at a first glance Class.cast seem to fit the bill it creates more problems than it solves. – Alexander Pogrebnyak Oct 12 '09 at 16:01

Class.cast() is rarely ever used in Java code. If it is used then usually with types that are only known at runtime (i.e. via their respective Class objects and by some type parameter). It is only really useful in code that uses generics (that's also the reason it wasn't introduced earlier).

It is not similar to reinterpret_cast, because it will not allow you to break the type system at runtime any more than a normal cast does (i.e. you can "break" generic type parameters, but can't "break" "real" types).

The evils of the C-style cast operator generally don't apply to Java. The Java code that looks like a C-style cast is most similar to a dynamic_cast<>() with a reference type in Java (remember: Java has the runtime type information).

Generally comparing the C++ casting operators with Java casting is pretty hard since in Java you can only ever cast reference and no conversion ever happens to objects (only primitive values can be converted using this syntax).

share|improve this answer
dynamic_cast<>() with a reference type. – Tom Hawtin - tackline Oct 12 '09 at 16:01
@Tom: is that edit correct? My C++ is very rusty, I had to re-google a lot of it ;-) – Joachim Sauer Oct 12 '09 at 16:03
+1 for: "The evils of the C-style cast operator generally don't apply to Java." Quite true. I was just about to post those exact words as a comment on the question. – Daniel Pryden Oct 12 '09 at 16:15

C++ and Java are different languages.

The Java C-style cast operator is much more restricted than the C/C++ version. Effectively the Java cast is like the C++ dynamic_cast if the object you have cannot be cast to the new class you will get a run time (or if there is enough information in the code a compile time) exception. Thus the C++ idea of not using C type casts is not a good idea in Java

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.