tags:

views:

266

answers:

2

I'm having a problem understanding Java generics and I've simplified to this example

class A<T extends B> {

    public void fun(T t) {

    }
}

class B {
    A a;

    public void event() {
     a.fun(this);
    }

}

The problem is that this generates a warning because A is defined inside B but A is already using it as a generic type.

My first instinct would be that my design is wrong, but in this case I can't change it. A is like a collection and B is like a node in the collection that users are supposed to override. Certain events can happen in B that require reporting back to the parent A.

But since A is defined generically with B, how do I avoid the compile warning inside B.event()

Thanks

+9  A: 

The problem is that you're using a raw type on this line:

A a;

You need to specify a type for A's type parameter (T).

You could do something like this:

A<B> a;

but then A might as well not be generic at all, if I'm understanding your statement of the problem. You probably want to do something like this:

class A<T> {
  public void fun(T t) {

  }
}

class B<T extends B<T>> {
  A<B<T>> a;
  public void event() {
    a.fun(this);
  }
}

or even this:

class A<T extends B<? extends T>> {
  public void fun(T t) {

  }
}

class B<T extends B<T>> {
  A<? super B<T>> a;
  public void event() {
    a.fun(this);
  }
}

There are a couple of variations in-between these that are possibly useful as well. The latter example is the most generic (but obviously, also the most complicated).

The class A<T extends B<? extends T>> is ensuring that the type parameter to A is a B. Since B is itself generic, and has that cyclic type parameter, you end up needing to say B<? extends T> (simply saying T won't work here).

The class B<T extends B<T>> is as close as you can get to emulating a "self type" in Java. This lets B talk about the (almost) concrete subtype of itself. When subclassing B you'd say something like "class C extends <B<C>>". This is useful because now the type of C.a is actually A<? super B<C>>.

The ? super bit in the latter example is only useful if you plan on connecting a B with an A that isn't for exactly the same type of B. Thinking in concrete terms, suppose you had an A<Shape> and a Circle (which extends Shape which extends B). The super-wildcard lets you use them together. Without it you'd need an A<Circle> rather than an A<Shape> for your Circle.

Laurence Gonsalves
This is correct, and a great example of wildcards.
Dave Jarvis
+10  A: 

Code

public class A<T extends B> {
    public void fun(T t) {
    }
}

public class B {
    A<B> a;

    public void event() {
        a.fun(this);
    }
}

The warning is vanquished.

Reason

Variables of type A should be declared using a specific class type, as suggested by the generic class signature (A<T extends B>).

Resolution

While this resolves the compiler warning, the underlying problem remains. Laurence provides an excellent explanation and solution to the core issue.

Dave Jarvis