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
In C++ when you use a template the compiler will emit the template code again after replacing the generic parameter in it with the type you used. This is more powerful in several ways but can lead to bloated executables.
A C++ template gets reproduced and re-compiled entirely whenever a template is instantiated with a new class. The main difference is that Java generics are encapsulated. The errors are flagged when they occur and not later when the corresponding classes are used/instantiated.
Template Method is a behavioral design pattern that allows you to defines a skeleton of an algorithm in a base class and let subclasses override the steps without changing the overall algorithm's structure.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With