Search code examples
javagenericsbounded-types

Incompatible bounds on two types extending Set


I don't understand why this won't work. I have a generic class Test<K,E extends Set> that accepts a type E as a second arguments which is at least a Set.

I have another inner static class called Pair which also takes a second typeF which is also at least a Set.

public class Test <K,E extends Set> {
    public static class Pair<L,F extends Set> {
        private L l;
        private F f;

        public Pair(L l, F f) {
            this.l = l;
            this.f = f;
        }
    }

    private Set<Pair<K,E>> pairs = new HashSet<>();

    private void test(K k){
        Set set = new HashSet<>();
        pairs.add(new Pair<>(k,set));
    }



}

Yet, I cannot add an object of type K and Set to my pairs set and I can't figure out why.

Error log:

Error:(26, 14) java: no suitable method found for add(test.o.Utils.Test.Pair<K,java.util.Set>)
    method java.util.Collection.add(test.o.Utils.Test.Pair<K,E>) is not applicable
      (argument mismatch; cannot infer type arguments for test.o.Utils.Test.Pair<>
          reason: inference variable F has incompatible bounds
            equality constraints: E
            lower bounds: java.util.Set)
    method java.util.Set.add(test.o.Utils.Test.Pair<K,E>) is not applicable
      (argument mismatch; cannot infer type arguments for test.o.Utils.Test.Pair<>
          reason: inference variable F has incompatible bounds
            equality constraints: E
            lower bounds: java.util.Set)

Solution

  • Are you expecting others to be able to specify the type of set that can be used with Test? If you aren't there is no reason to have the second generic:

    public class Test<K> {
        public static class Pair<L> {
            private L l;
            private Set f;
    
            public Pair(L l, Set f) {
                this.l = l;
                this.f = f;
            }
        }
    
        private Set<Pair<K, Set>> pairs = new HashSet<>();
    
        private void test(K k){
            Set set = new HashSet();
            pairs.add(new Pair<>(k,set));
       }
    }
    

    What you probably wanted was to specify what was inside of the set.

    public class Test<K, E> {
        public static class Pair<L, F> {
            private L l;
            private Set<F> fs;
    
            public Pair(L l, Set<F> fs) {
                this.l = l;
                this.fs = fs;
            }
        }
    
        private Set<Pair<K, E>> pairs = new HashSet<>();
    
        private void test(K k){
            Set<E> set = new HashSet<>();
            pairs.add(new Pair<>(k,set));
       }
    }
    

    Not sure exactly what you are going for but you should check out a Multimap. Guava has a pretty good implementation. It allows associating one key with multiple values (inside a set) which is essentially what you are doing here.