6

I'd like to implement a method that takes an Object as argument, casts it to an arbitrary type, and if that fails returns null. Here's what I have so far:

public static void main(String[] args) {
    MyClass a, b;
    a = Main.<MyClass>staticCast(new String("B"));
}

public static class MyClass {
}

public static <T> T staticCast(Object arg) {
    try {
        if (arg == null) return null;
        T result = (T) arg;
        return result;
    } catch (Throwable e) {
        return null;
    }
}

Unfortunately the class cast exception is never thrown/caught in the body of the staticCast() function. It seems Java compiler generates the function String staticCast(Object arg) in which you have a line String result = (String) arg; even though I explicitly say that the template type should be MyClass. Any help? Thanks.

1
  • By the way, you should be catching only ClassCastException, not Throwable. Catching Throwable can cause serious problems. Commented Mar 11, 2009 at 17:55

5 Answers 5

10

Because generic type information is erased at runtime, the standard way to cast to a generic type is with a Class object:

public static <T> T staticCast(Object arg, Class<T> clazz) {
    if (arg == null) return null;
    if (!clazz.isInstance(arg))
        return null;
    T result = clazz.cast(arg);
    return result;
}

Then call it like this:

a = Main.staticCast("B", MyClass.class);
Sign up to request clarification or add additional context in comments.

4 Comments

using Class.isInstance would be more direct.
hmm, clazz? is that like a klass?
isInstance will only work if the object is an instance of clazz, not if it's a subclass of clazz. isAssignableFrom will work on anything that's castable to clazz, even subclasses.
@Paul: The Javadocs say, "This method is the dynamic equivalent of the Java language instanceof operator. The method returns true if the specified Object argument is non-null and can be cast to the reference type represented by this Class object without raising a ClassCastException."
6

You cannot do what you want... at least not this way. The compiler removed all of the information so you wind up with (T) being Object in the cast - and that works.

The problem is that later on you are doing MyClass = (String)object; and that isn't allowed.

You have bypassed the compilers checking and made it fail at runtime.

So what is it exactly that you are trying to do? If you tell us why you want to do this we can probably tell you the Java way of doing it.

Given your comment you might try something like:

public class Main
{
    public static void main(String[] args)
    {
        String a;
        MyClass b;
        a = staticCast(new String("B"), String.class);
        b = staticCast(new String("B"), MyClass.class);
        System.out.println(a);
    }

    public static class MyClass
    {
    }

    public static <T> T staticCast(Object arg, final Class clazz)
    {
        // edit - oops forgot to deal with null...
        if(arg == null)
        {
            return (null);
        }

        // the call to Class.cast, as mmeyer did, might be better... probably is better... 
        if(arg.getClass() != clazz)
        {
            // Given your answer to Ben S...
            return (null);

            // throw new ClassCastException("cannot cast a " + arg.getClass() + " to a " + clazz);
        }

        return ((T)arg);
    }
}

1 Comment

I see, so T is an object in the cast. I want a separate method for each T that will cast the argument to (T), and if that fails an exception is caught and not thrown. According to Paul Tomblin (below post) that's not going to happen.
4

You mean like Class<T>.cast(Object obj)?

Something like:

Class.forName("YourClass").cast(obj);

Should do pretty much what you want.

Be aware that this is quite smelly though and is probably a sign of poor design.

2 Comments

Thanks. The problem is this will throw class cast exception if it fails. It's identical to the code: (YourClass) object and you get an exception thrown on error which you have to check every time you use that line of code. I'd like to catch and hide that exception inside cast() method.
Do you want asSubclass or getConstructor().newInstance().cast?
1

Don't mistake Java generics for C++ templates. There is only going to be one staticCast method that's called with different type erasure, not one for each T.

Not using Generics at all, I would write it this way:

public static void main(String[] args) {
    MyClass a, b;
    a = (MyClass)Main.staticCast(new String("B"), MyClass.class);
}

public static class MyClass {
}

public static staticCast(Object arg, Class class) {
        if (arg != null && class.isAssignableFrom(arg))
          return arg;
        return null;
}

Or stealing from another answer, using generics:

public static <T> T staticCast(Object arg, Class<T> class) {
        if (arg != null && class.isAssignableFrom(arg))
        {
           T result = class.cast(arg);
           return result;
        }
        return null;
}

5 Comments

I forgot that CCE was a RuntimeException and didn't require a catch block, or I'd have done it like your second method originally.
Can you elaborate why Java compiler doesn't generate the function MyClass staticCast(Object arg); when I explicitly specify the type T in the line: a = Main.<MyClass>staticCast(new String("B")); I explicitly told it to...I thought A link to some reading would be great.
@Budric: Try java.sun.com/docs/books/tutorial/java/generics/erasure.html. Also, search for questions tagged [java] [generics]. There are some pretty interesting ones around.
isAssignableFrom should be isInstance, and no need to check for null.
Correct me if I'm wrong, but I thought isAssignableFrom will find subclasses of the given classes, not just ones that are exactly that type?
1

I agree with Ben, however, I prefer the following notation:

MyClass.class.cast(obj);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.