Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting a generic class. (cast) vs Class.cast()

I have searched for my use case and found some interesting answers but they are not as suitable as i need. What would the appropriate way to do this:

@SuppressWarnings("unchecked")
public <T> T newInstance(String name) throws ClassCastException, InstantiationException, IllegalAccessException, ClassNotFoundException {
    return (T) loadClass(name).newInstance();
}

or a little different:

public <T> T newInstance(String name, Class<T> c) throws ClassCastException, InstantiationException, IllegalAccessException, ClassNotFoundException {
    return c.cast(loadClass(name).newInstance());
}

I think that both methods do the same. From my point of view method 1 is better because of less parameters. Boths throw a ClassCastException which will be fine for me. Truly, the @SuppressWarnings("unchecked") annotation is not nice.

Can someone tell me if there are any advantages for one method towards the other?

Edit: Jon Skeet's answer is correct. The following snippet can provide additional clarification.

public class Test {
    public static void main(String[] args) {
        Object o = new Object();
        // Exception at c.cast(o)
        Test.<String>realCast(o, String.class);
    }

    private static <T> T realCast(Object o, Class<T> c) {
        return c.cast(o);
    }
}

Using realCast() produces an Exception when o can't be cast to c. In comparison to that fakeCast() only gives a promise that the method's result is type of T.

like image 335
mr.b Avatar asked Mar 08 '16 06:03

mr.b


1 Answers

I think that both methods do the same.

No, they don't. Because at execution time, the first code doesn't know the type of T due to type erasure. That means the cast basically does nothing within the method. The calling code might implicitly cast to whatever T it is specifying, but if the caller is another generic method (with the T used here as another type parameter), even that wouldn't want.

Here's a simple example of that:

public class Test {
    public static void main(String[] args) {
        Object o = new Object();
        // No exception
        Test.<String>fakeCast(o);
        // Exception at the point of assignment:
        // the code is effectively String x = (String) ...;
        String x = Test.<String>fakeCast(o);
    }

    private static <T> T fakeCast(Object o) {
        return (T) o;
    }
}

The second code knows the type of T in the form of Class<T>, so it can perform a real cast at execution time, at exactly the point you're performing it.

like image 92
Jon Skeet Avatar answered Sep 21 '22 12:09

Jon Skeet