Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Java required type <T> provided <?> generic compilation error

How is Java unable to interpret this code:

    private <T> Class<T> getClass(T object) {
       return object.getClass();
    }

I’m trying to visualise this and when I substitute in for an exmaple

    private Class<String> getClass(String s) {
        return s.getClass();
    } 

I get the same sort of error: required type <String> provided type <? extends String>. I’ve seen code that gets around this error by doing:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

        @SuppressWarnings("unchecked")
        Class<T> clazz = (Class<T>) object.getClass();

What does this mean? What am I not understanding about this generics problem?

>Solution :

getClass follows some specific rules that are a bit unusual. The declared return type of Object::getClass is simply Class<?>, i.e. a class of some type. But as per the docs

The actual result type is Class<? extends |X|> where |X| is the
erasure of the static type of the expression on which getClass is
called.

The erasure for T in your example is simply Object, so the return is Class<? extends Object>. Everything extends Object, so that’s the same as Class<?>.

When the parameter is the specific type String, the erasure is also String, and the result is Class<? extends String>.

Oracle tutorial on type erasure

I guess what happens under the hood is that the compiler effectively "overrides" Object::getClass with a more specific return type. Child classes are allowed to return more specific types than their parents, but not less specific. Consider this valid code:

class Foo {
    public Class<? extends List<?>> foo() { return null; } 
}

class Bar extends Foo {
    @Override
    public Class<? extends ArrayList<?>> foo() { return null; }
}

Because of how this is implemented, T obj; obj.getClass(); will return Class<?>, rather than what you’re expecting which is Class<? extends T>.

In your case, the cast is safe.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading