简体   繁体   中英

Generics, Inheritance and Type Erasure problem

I can't wrap my head around, why the following code snippet including generics and wildcards is not valid.

package test;

public class App {

    private interface Condition {
        String get();
    }

    private interface Processor<T extends Condition> {
        boolean process(final T condition);
    }

    private static class HolderClass<T extends Condition> {

        private final Processor<T> processor;
        private final T condition;

        public HolderClass(final Processor<T> processor, final T condition) {
            this.processor = processor;
            this.condition = condition;
        }

        public Processor<T> getProcessor() {
            return processor;
        }

        public T getCondition() {
            return condition;
        }

    }

    private static class FirstCondition implements Condition {
        @Override
        public String get() {
            return "concrete";
        }
    }

    private static class FirstProcessor implements Processor<FirstCondition> {
        @Override
        public boolean process(FirstCondition condition) {
            System.out.println(condition.get());
            return false;
        }
    }

    public static void main(String[] args) {
        final HolderClass<? extends Condition> holder = new HolderClass<>(new FirstProcessor(), new FirstCondition());
        holder.getProcessor().process(holder.getCondition()); // error here
    }

}

This fails with Compilation failure .../test/App.java:[58,46] incompatible types: test.App.Condition cannot be converted to capture#1 of ? extends test.App.Condition Compilation failure .../test/App.java:[58,46] incompatible types: test.App.Condition cannot be converted to capture#1 of ? extends test.App.Condition

I already have read a lot about type erasure, but can anyone try to explain what's the actual problem and maybe provide an counter example why this is not allowed?

Thanks.

? extends ? extends used to declare a generic class is classic. You use that to set the boundaries of your generic class.
But as you instantiate a generic type, you generally specify the type that you need to manipulate and you don't use still declare that with an upper bounded wildcard because this sets some rules that give you some possibilities (assignation it from subtypes variable) but also some constraints.

A example that should help you to understand :

List<? extends Number> numbers = null;
numbers.add(1); // Doesn't compile for same reason

If you want to add numbers you declare :

List<Number> numbers = null;
numbers.add(1);

In a general way, a variable Foo<? extends Bar> Foo<? extends Bar> cannot be invoked with a generic parameter for type safety reasons :

List<? extends Number> numbers = null;
List<? extends Float> floats = null;
numbers = floats;  // valid
numbers.add(Long.valueOf(1)); // doesn't compile since no type safe

So specify the type that you manipulate ( FirstCondition ):

final HolderClass<FirstCondition> holder = new HolderClass<>(new FirstProcessor(), new FirstCondition());
holder.getProcessor().process(holder.getCondition()); 

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