Reputation: 140447
No, this question is not about the difference between ? and T; it is about how I turn a < ? > argument into a named < T >. Consider this example code:
import java.io.Serializable;
class A<T extends Serializable> {
<S extends Serializable> void bar(S arg) { }
void bar2(T arg) { }
}
public class B {
A<? extends Serializable> myA = null;
<T extends Serializable> void foo(T arg) {
myA.bar(arg);
myA.bar2(arg);
}
}
My problem is the fact that the above doesn't compile; the call to bar2() gives me
The method bar2(capture#2-of ? extends Serializable) in the type
A<capture#2-of ? extends Serializable> is not applicable for the arguments (T)
I guess the "reason" for that is that myA is a < ? extends Serializable >; but the T in B.foo ... is well, a named T; and not the wildcard ?.
One way to "fix" this would be to make < T extends Serializable > a type parameter for class B ... but that basically conflicts with my other usage of that class. Meaning: I ended up writing down B and its member myA like this - exactly because I don't want to parameterize the B class. So, I started with only the bar2() method; and then added bar() later on ... but that doesn't really help either.
So - is there a way to for my class B to use A.bar2() as "intended" in my example code?
EDIT: and just to be precise - the bar() method doesn't help me; as the "S" there ... isn't compatible with the "T" that I am really using in my A class.
Upvotes: 1
Views: 439
Reputation: 15212
@JBNizet already explains why this can't be done. This answer aims to explain the possible options you have (one of them being rightly pointed out by in your question but that's not the only option).
Make B take a type parameter
class B<T extends Serializable> {
A<T> myA = null;
void foo(T arg) {
myA.bar(arg);
myA.bar2(arg);
}
}
Make B extend from A (If B passes the is-a test for A)
class B extends A<String> {
public void foo(String arg) {
bar2(arg);
bar(1);
}
}
The difference between the two options is that in 1) both bar
and bar2
need to be passed the same type where as in 2) bar
and bar2
can be passed different types since bar2
is bound by the type parameter declared for A
where as bar
is bound by the type parameter declared for the method.
Upvotes: 1
Reputation: 691725
You're in a dead end.
A<? extends Serializable> myA = ...;
So myA
is a A
of something unknown. It could be a A<String>
, or a A<Integer>
or a A<Banana>
. You just don't know. Let's say it's a A<Banana>
.
<T extends Serializable> void foo(T arg) {
So foo()
accepts any serializable: String, Integer, Banana, Apple, anything. Let's say it's called with an Integer
as argument.
myA.bar2(arg);
So, based on the assumptions above, that would call bar2()
with an Integer as argument, although myA
is a A<Banana>
. That can't be accepted by the compiler: it's clearly not type-safe. B
must be made generic.
Upvotes: 2