简体   繁体   中英

Java generics & incompatible types: bug in compiler?

I've got "incompatible types" compiler error in condition not yet discussed in stackoverflow (eg Why won't this generic java code compile? ).

My expectation is simple - I'm calling a templated method which does not use any 'generic' classes from containing class, therefore it should extract types of template parameters from method arguments and this should compile in all cases - but I get "incompatible types" compiler error.

I've noticed strange way to fix the problem - adding " < ? extends Data > " to generic datatype in method arguments. How does it change compiler logic?

In my understanding - there should be no difference because (1) DataContainer class' template parameters are not used in method call and (2) restriction " < TData extends Data > " already defines minimal base object class - Data - and therefore it should be automatically assumed when compiling template without arguments.

public void processData(DataContainer<? extends Data> c) {

(explicit type casting can be used, but i believe it is redundant here)

DummyContextClass dcc = (DummyContextClass)c.getContext(DummyContextClass.class);

Code for copy/paste

public class Test {

    public static class Data {
    }

    public static class DataContainer<TData extends Data> {
        public final TData Data;
        private final Map<String, Object> contexts = new HashMap<>();

        public DataContainer(TData data) {
            Data = data;
        }

        public <T> T getContext(Class<T> type) {
            return (T)contexts.get(type.getName());
        }

        public <T> void setContext(Class<T> type, T context) {
            contexts.put(type.getName(), context);
        }
    }

    public static class DummyContextClass {
    }

    public void processData(DataContainer c) {
        c.setContext(DummyContextClass.class, new DummyContextClass());

        // error: incompatible types: Object cannot be converted to DummyContextClass
        DummyContextClass dcc = c.getContext(DummyContextClass.class);
    }
}

The problem has nothing (much) to do with your generic methods.
Your problem is you are using a raw type as the parameter of your method:

public void processData(DataContainer c) { // Oops! DataContainer is a raw type

You should use a parameter with DataContainer :

public void processData(DataContainer<? extends Data> c) {

When you leave off the type of a generic class, you have what is called a raw type, and (due to compatibility requirements with old java versions), all generic information is stripped off the class . That (amongst other things) changes all return types that are declared as generic types into Object , so for compilation purposes, your method now looks like:

public Object getContext(Class type) {

...hence your error.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM