Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java generic type parameter with newInstance

Tags:

java

generics

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 {

    }

}
like image 677
cyberoblivion Avatar asked Apr 22 '26 11:04

cyberoblivion


2 Answers

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());
like image 180
Sergey Kalinichenko Avatar answered Apr 25 '26 01:04

Sergey Kalinichenko


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

like image 27
Itay Maman Avatar answered Apr 25 '26 01:04

Itay Maman



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!