0

Say I have a class Foo, a class A and some subclass B of A. Foo accepts A and its sublclasses as the generic type. A and B both require a Foo instance in their constructor. I want A's Foo to be of type A , and B's Foo to be of type B or a superclass of B. So in effect, So I only want this:

Foo<X> bar = new Foo<X>;
new B(bar);

to be possible if X is either A, B, or a both subclass of A and superclass of B.

So far this is what I have:

class Foo<? extends A>{
    //construct
}


class A(Foo<A> bar){
    //construct
}

class B(Foo<? super B> bar){
    super(bar);
    //construct
}

The call to super(...) doesn't work, because <A> is stricter than <? super B>. Is it somehow possible to use the constructor (or avoid code duplication by another means) while enforcing these types?

Edit: Foo keeps a collection of elements of the generic parameter type, and these elements and Foo have a bidirectional link. It should therefore not be possible to link an A to a Foo.

gibberish
  • 145
  • 1
  • 2
  • 6

4 Answers4

1

If you change the A constructor to:

class A(Foo<? extends A> bar){
    //construct
}

will it do what you want ?

If you really want to limit the constructor of A to Foo then you need to provide another protected method (aka usable from derived classes) to set the Foo instance. Something like this:

public class A {

    Foo<?> foo;

    public A(Foo<A> foo) {
        setFoo(foo);
    }

    protected A() {
    }

    protected void setFoo(Foo<?> foo) {
        this.foo = foo;
    }
}

and B

public class B extends A {

    public B(Foo<? super B> foo) {
        setFoo(foo);
    }
}

now this works:

new A(new Foo<A>());
new A(new Foo<B>()); // this fails compilation
new B(new Foo<B>());

In order for foo element in A to be properly typed you might need to make A a parametrized class too.

Mihai Toader
  • 12,041
  • 1
  • 29
  • 33
0

The only way to do this would be to have...

class A(Foo<? extends A> bar) {
  //construct
}

But it appears this isn't what you want. You can't have the other approach because when you create an instance of B you are also creating an instance of A (that is part of the B instance). So B can't take in special fields for the parts in A. I'm not sure why you wouldn't allow A's foo to be of type B, could you perhaps expand on that?

Pace
  • 41,875
  • 13
  • 113
  • 156
  • Well, Foo keeps a collection of elements of the generic parameter type, and these elements and Foo have a bidirectional link. Perhaps I should have mentioned that. So if I have a Foo containing B's, I want to prevent linking an A to it. – gibberish Jan 07 '11 at 14:47
0

The following setup compiled for me:

public interface MarkerInterface {

}

public class A implements MarkerInterface {

    public A(Foo<A> fooA) {

    }
}

public class SuperB implements MarkerInterface {

}


public class B extends SuperB {

    public B(Foo<? super B> fooB) {

    }
}

And with the main method:

public static void main(String[] args) {
    B b = new B(new Foo<SuperB>());
}

Is this what you're looking for?

Buhake Sindi
  • 87,898
  • 29
  • 167
  • 228
  • Thanks for the suggestion, but this method removes the class hierarchy. I suppose the idea is to put A's method signatures in MarkerInterface? Duplicating all A's code in B doesn't seem ideal to me. – gibberish Jan 07 '11 at 15:06
  • Well, I can't really know how to help you since you've just broadened your scenario. – Buhake Sindi Jan 07 '11 at 15:08
0

Java generics are powerful and well designed; nevertheless we sometimes find them lacking. I don't think there's a good way to do what you want.

The easiest thing to do is to change the declaration of Foo<X> to Foo<X extends A>. If that's not acceptable, you can subclass Foo like this:

class Foo<X> { }

class FooA<X extends A> extends Foo<X> { }

class A {
    public A(FooA<? extends A> foo) { }
}

class B extends A {
    public B(FooA<? super B> foo) {
        super(foo);
    }
}

(Note: if you have trouble following, when you see Foo, think ArrayList.)

This has the obvious disadvantage that you have to use FooA rather than Foo, hindering code reuse.

Dan R.
  • 761
  • 5
  • 21