The struggle for the development of APIs with interfaces and universal sets

I am trying my best to come up with a simple API because generics are not covariant

This is my new problem: I cannot get Set <>, which does what I need. I tried to read various manuals, but they all use a lot of words that I lose.

Consider the following classes

public class Parent {}
public class Child extends Parent {}
interface Store {
    public Set<Parent> getParents(); //PROBLEM!! This needs to change
}

At a minimum, I need these operations to work.

Set<Parent> parents = store.getParents();
parents.add(new Parent()); 
parents.add(new Child()); 
store.getParents().add(new Child()); //Note the lack of generics

for(Parent curEntry : store.getParents()) {

}

Classes that implement the Store should be able to work with Child (this means that they have a Set, which is a child). They need to expose children as parents, albeit for the outside world.


Attempt # 1

interface Store {
    public Set<Parent> getParents();
}

class ConcreteStore implements Store {
    Set<Child> childs;
    public Set<Parent> getParents() {
        return (Set<? extends Parent>)childs; //ERROR: inconvertible types
    }
}

Attempt # 2

interface Store {
    public Set<? extends Parent> getParents();
}

class ConcreteStore implements Store {
    Set<Child> childs;
    public Set<Child> getParents() {
        return childs;
    }
}

Store store = new ConcreteStore();
Set<? extends Parent> parents = store.getParents();
parents.add(new Child()); //ERROR: cannot find symbol
parents.add(new Parent()); //ERROR: cannot find symbol. What?!

for (Parent curEntry : store.getParents()) {
}

, , , Set Concrete . . , .

№ 3

interface Store<T extends Parent> {
    public Set<T> getParents();
}

public static class ConcreteStore implements Store<Child> {
    Set<Child> childs;

    @Override
    public Set<Child> getParents() {
        return childs;
    }
}

Store store = new ConcreteStore();
Set<Parent> parents = store.getParents();
parents.add(new Parent());
parents.add(new Child());

for (Parent curEntry : store.getParents()) { //ERROR: incompatible types. Found object, requited Parent
}

, , Store<Child> store = new DatabaseStore(), - , . , , , .

-

, . , . -

+3
4

, .

  • A Set<Parent> - , Parent, , , - Parent.
  • A Set<Child> - , Child, , , Child.

, , : Parent, , Child. , ConcreteStore " ", - .

Java , - , , , , - .

  • A Set<? extends Parent> Parent. , ( ), , , Parent objects.

  • A Set<? super Child> Child. , Child, , ( Object, ).

:

Set<Parent> parents = store.getParents();
parents.add(new Parent()); 
parents.add(new Child()); 
store.getParents().add(new Child()); //Note the lack of generics

for(Parent curEntry : store.getParents()) {

}

, , :

public class Parent {}
public class Child extends Parent {}
interface Store {
    public Set<Parent> getParents();
}

, Childs, Parents.

Store :

interface Store<X extends Parent> {
   public Set<X> getParents();
}

class ConcreteStore implements Store<Child> {
    Set<Child> childs;
    public Set<Child> getParents() {
        return childs;
    }
}

, , - , Store<Parent>, .

+4

, . - , - . Child from Parent. , , , - .

, Human, . , .

+1

№2 - . cannot find symbol on add.
: Parent [] (), .

0

This is probably a comment, but my rep is still too ...

What is the point of creating a concrete class that can only contain Child?

I would save:

class ConcreteStore implements Store {
    Set<Parent> parents;
    public Set<Parent> getParents() {
        return parents;
    }
}
0
source

All Articles