2

I am hoping to produce some base classes that will include something like the following

class Container<T extends Containee>
{
     T containee;
     public T getContents(){return containee;}
     public void setContents(T contents){ containee = contents; containee.setContainer(this); }
}

class Containee<T extends Container>
{
     T container;
     public T getContainer(){return container;}
     public void setContainer(T container){this.container = container;}
}

There is a circular definition problem here which I thought I could ease using wildcards

class Container<T extends Containee<?>>
class Containee<T extends Container<?>>

except that the compiler complains about containee.setContainer(this). I have hacked a couple of ad-hoc solutions that will get the super-classes to compile, but nothing that will work for sub-classes, e.g.

class Foo extends Container<Bar>
class Bar extends Containee<Foo> 

The generics tutorial and FAQ didn't seem to have anything obvious relating to this. How does one express such a relationship using generics?

Thanks

thekindamzkyoulike
  • 244
  • 1
  • 2
  • 7
  • 1
    I asked the same question earlier, the short answer is its not possible with generics see: http://stackoverflow.com/questions/2567595/creating-circular-generic-references – M. Jessup Mar 09 '11 at 16:23

4 Answers4

2

Perhaps something like:

abstract class Container<
    THIS extends Container<THIS, T>,
    T extends Containee<T, THIS>
> {
    T containee;

    protected abstract THIS getThis();

    public T getContents() {
        return containee;
    }
    public void setContents(T contents){
        containee = contents;
        containee.setContainer(getThis());
    }
}

class Containee<
    THIS extends Containee<THIS, T>,
    T extends Container<T, THIS>
> {
    T container;
    public T getContainer() {
        return container;
    }
    public void setContainer(T container) {
        this.container = container;
    }
}

(Or perhaps something with less generics.)

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
2

Try this:

class Container<T extends Containee<Container<T>>>
{
   T containee;
   public T getContents(){return containee;}
   public void setContents(T contents){ containee = contents; containee.setContainer(this); }
}

class Containee<T extends Container<? extends Containee<T>>>
{
   T container;
   public T getContainer(){return container;}
   public void setContainer(T container){this.container = container;}
}

class Bar extends Containee<Container<Bar>> {  
}

class Foo extends Container<Bar> {
}

Foo now is a container accepting Bar objects whereas Bar would be addable to any container extending Container, so this would be possible as well:

class Baz extends Container<Bar> {
}

Baz is a container for Bar objects, too.

Thomas
  • 87,414
  • 12
  • 119
  • 157
  • This is nice, but not quite what I need. For example, in Bar's methods I would like to be able to write `Foo f = this.getContainer()` without casting. The idea is that the container provides an API for the containee, as well as vice-versa, both of which will be subclass-specific. Thanks anyway. – thekindamzkyoulike Mar 09 '11 at 18:48
1

Would this be better with plain old polymorphism?

class Container
{
    Containee containee;
    public Containee getContents(){return containee;}
    public void setContents(Containee contents){ containee = contents; containee.setContainer(this); }
}

class Containee
{
    Container container;
    public Container getContainer(){return container;}
    public void setContainer(Container container){this.container = container;}
}
Matt Dunn
  • 5,106
  • 6
  • 31
  • 55
  • That depends. Polymorphism doesn't capture that the Containee needs a container of a particular type. For instance, if I have `class Fish extends Containee {} class Aquarium extends Container{} class Desert extends Container {}`, your solution allows me to place a Fish in the Desert rather than an Aquarium. In Tom's solution, the compiler prevents this. (barring unchecked casts, of course) – meriton Mar 09 '11 at 14:25
0

what is the problem with your first solution?

class Container<T extends Containee>
class Containee<T extends Container>
irreputable
  • 44,725
  • 9
  • 65
  • 93