Reputation: 19450
I have a parameterized type A<T extends B>
, and another C<T2 extends A>
.
Is it possible to (statically) reference T
subclass from inside C
without having to add T
as a second type parameter for C
? The objective is to add a method to C
with return type T
.
What I'd like to write:
class A<T extends B> {
}
class C<T2 extends A<T>> {
T myMethod() {
}
}
Upvotes: 1
Views: 118
Reputation: 546
The section 4.4 of the spec says
A type variable is introduced by the declaration of a type parameter of
a generic class, interface, method, or constructor.
The occurrence of T
on the right of the extends
is a type variable, not a type parameter. It needs to be a parameter in scope if you want to use it as a variable.
You can add T
as a parameter like this:
class A<T extends B> {
...
}
class C<T, T2 extends A<T>> {
T myMethod() {
...
}
}
but this is what your question is trying to avoid. An alternative is to make C
an inner class:
class A<T extends B> {
class C<T2 extends A<T>> {
T myMethod() {
...
}
}
...
}
Upvotes: 0
Reputation: 6127
I think the answer is yes, you can, indirectly.
I think you can't do it directly, due to type erasure. As others have mentioned you would have to add another parameter, or type parameter, or nested class.
You can do it indirectly using a combination of a generics function, help from the caller of the class, and help from the base class:
class B
{
}
class B2 extends B // B2 is Just an example of a concrete type T
{
}
class A<T extends B> {
T t;
T getT()
{
return t;
}
}
class C<T2 extends A<?>> {
T2 t2;
T2 getT2()
{
return t2;
}
<X> X getValWithInnerType(A<? extends X> x)
{
return x.getT();
}
}
public class Example {
public static void main(String[] args) {
C<A<B2>> c1 = new C<>();
B2 inner = c1.getValWithInnerType(c1.getT2());
}
}
If you are willing to get the type you want , but not necessarily directly from the C class, you can also do something simpler using composition:
class B
{
}
class B2 extends B
{
}
class A<T extends B> {
T t;
T getT()
{
return t;
}
}
class C<T2 extends A<?>> {
T2 t2;
T2 getT2()
{
return t2;
}
}
public class Example {
public static void main(String[] args) {
C<A<B2>> c1 = new C<>();
B2 inner = c1.getT2().getT();
}
}
Finally , if it's not that crucial to get the exact deriving type T, you can just have a function returning type B:
class B
{
}
class B2 extends B
{
}
class A<T extends B> {
T t;
T getT()
{
return t;
}
}
class C<T2 extends A<? extends B>> {
T2 t2;
B getT2()
{
return t2.getT();
}
}
Upvotes: 0
Reputation: 20520
As things stand, you've used A
as a raw type in your definition of C
:
C<T2 extends A>
That's a bad idea, and you can't expect to get information about the type parameters in this context because you haven't specified any. There is no T
to find.
In your definition of A
, the type T
is just a parameter. Until you use a specific A
with a particular class as a parameter, T
doesn't refer to anything. When you define C
, you have to say what flavour of A
you're extending, or, in other words, specify a real type.
What you're doing is a bit like asking what the value of x
is in f(x) = x+1
. Until you invoke f
with some particular argument, x
is just a label.
Upvotes: 2