简体   繁体   中英

Problems with inheriting generics from Java

An error was reported when the find method was called.

interface Node<N extends Node<N>> {
    void setNext(N next);
    N getNext();
}

interface Entry<K, V> extends Node<Entry<K, V>> {
    K getKey();
    void setValue(V value);
    V getValue();
}

class Test {
    public static <N extends Node<N>> N find(N base, Object obj) {
        for (N node = base; node != null; node = node.getNext())
            if (node.equals(obj))
                return node;
        return null;
    }

    public static <K, V, E extends Entry<K, V>> E getEntry(E[] table, K key) {
        return find(table[0], key);
    }
}

Bound mismatch: The generic method find(N, Object) of type Test is not applicable for the arguments (E, K). The inferred type E is not a valid substitute for the bounded parameter >

I do not know why this is so.

The problem is here:

interface Node<N extends Node<N>> {
    void setNext(N next);
    N getNext();
}
interface Entry<K, V> extends Node<Entry<K, V>> {
    K getKey();
    void setValue(V value);
    V getValue();
}

You have E extends Entry<E, V> . What does E.getNext() return? Since Entry<K, V> extends Node<Entry<K, V>> , E.getNext() would at least return Entry<K, V> , that's for sure.

But will it be E ? Entry<K, V>.getNext() is only guaranteed to return some instance of Entry<K, V> . But it is not guaranteed to return exactly the same type that Entry<K, V> actually is. There's nothing in the code forcing E.getNext() to return E , only some instance assignment-compatible to Entry<K, V> .

Therefore the best what can be inferred for your find method is Entry<K, V> which is not necessarily compatible to E .

We know

E extends Entry<K, V>

and

Entry<K, V> extends Node<Entry<K, V>>

These two things together mean that

E extends Node<Entry<K, V>>

However in order for the find method to be applicable we need

E extends Node<E>

but this does not follow, because E is only a subtype of Entry<K, V> , not equal to it.

The problem is that while Node has a type parameter representing its own concrete implementing type ( N ), Entry does not. You can fix it by adding a third type parameter for this purpose.

interface Entry<K, V, E extends Entry<K, V, E>> extends Node<E> {
    K getKey();
    void setValue(V value);
    V getValue();
}

public static <K, V, E extends Entry<K, V, E>> E getEntry(E[] table, K key) {
    return find(table[0], key);
}

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