3

I am not sure why Java is requiring me to cast the return of the makeInstance method to T? What am I doing wrong? Is there a better way to accomplish this?

public class Scratch {

    public <T extends Base> T freshen(T instance) {
        //why do I need to cast this to T
        return makeInstance(instance.getClass());
    }

    public <T extends Base> T makeInstance(Class<T> type) {
        try {
            return type.newInstance();
        } catch (InstantiationException ex) {
            Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public static final class Base {

    }

}

3 Answers 3

2

The reason Java wants you to cast the result is that T returned from makeInstance method is not guaranteed to be the same as T of freshen method. The reason for it is that getClass() does not return Class<T>. Instead, it returns Class<? extends X>, where X is the erasure of the static type of instance, i.e. Object. That's where the compiler's chain of inference stops: it cannot infer from that call that the return type would be T, requiring you to do the cast.

An alternative to casting the instance would be casting the class, like this:

return makeInstance((Class<T>)instance.getClass());
Sign up to request clarification or add additional context in comments.

1 Comment

"getClass() returns Class<?>" getClass() actually returns Class<? extends |X|>, where |X| is the erasure of the static type of instance, which in this case is Object.
1

The root cause for your problem is "type erasure": when the Java compiler compiles the body of the freshen() method it essentially replaces the T type with its upper bound, namely: Base.

So here's the reasoning the compiler is doing: - instance is of type Base (as I said, T was replaced with Base) - .getClass() is invoked on a variable of type Base so the return value of this call is Class<? extends Base> - the parameter that is passed to makeInstance() is therefore, from the compiler's point of view, of type Class<? extends Base>. Consequently the T inside makeInstance() is also Base => the method returns Base

2 Comments

Very good explanation. I only picked other because he gave me a good solution. Thanks
@cyberoblivion you can up-vote it to indicate that it is valuable to future readers of your question
0

You can solve this problem using following.

public class Scratch<T extends Base> {

    public T freshen(T instance) {
        // No need to cast this to T
        return makeInstance(instance.getClass());
    }

    public T makeInstance(Class<T> type) {
        try {
            return type.newInstance();
        } catch (InstantiationException ex) {
            Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    public static final class Base {

    }

}

Hope this helps.

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.