So I don't know if this is possible I've tried searching it but maybe my search terms are off. Basically I'm wondering, is there a way to create a generic function/method in a super class that returns the downcast object.
class A {
public <downcasted type (in this example B if called from a B instance)> test() {
return this;
}
}
class B extends A { }
B b = new B().test()
basically having "test()" return the B instance as type B even know the function/method is declared purely in the parent class?
I know I can cast the variable, tho having many functions some of which may return Lists of the class type, etc become troublesome. I also realize I could @override the function in B and do a "return (B)this.super()" thing, but again wrapping many functions is tedious and makes makes updating the base classes code more painful.
I also know you can do
"class A<T extends A>"
and then define B as
"class B extends A<B>"
but then if you want to make a "C" that extends "B" it breaks.
So is this type of behavior possible? If so, what is it called and how do I implement it?
An example as to where this behavior could be useful would be any base data structures you want to make extendable like an N-Ary Tree that you extend into oct/quad tree structure and/or an extended class that adds a "Name" and "Attributes" or something for a xml-like node.
Edit: This seems to work(as far as the linter is concerned), it's a bit more work to implement the base methods but it's got the desired end result as far as I can tell. That said when I attempt to run it, it gives me a "cannot find symbol: class type" error. :S
static class D extends auto {
final Class type = getClass();
@SuppressWarnings("unchecked")
public <T extends type> T test() {
return (T)type.cast(this);
}
}
static class E extends D { }
static class F extends E { }
static {
D d = new D().test();
E e = new E().test();
F f = new F().test();
}
There is a simpler way, which seems to work:
class Alpha {
@SuppressWarnings("unchecked")
<T extends Alpha> T test() {
return (T) this;
}
}
class B extends A { }
However, that does not support method chaining.
You need test()
to return a subtype of A
, rather than A
itself. In order to do this, the signature of the A
class could be this:
class A<T extends A<?>> {
@SuppressWarnings("unchecked")
public T test() {
return (T) this;
}
}
If you create a class B
extending A
, you will need B.test()
to return an instance of B
, without needing to override test()
returning a specific type. You could then do something like this:
class B<T extends B<?>> extends A<T> { }
Now T
is a subclass of B
, and because test()
's return type is T
, it will return a B
instance. Further subclassing can be done in the same way:
class C<T extends C<?>> extends B<T> { }
And statements like this will work:
C<?> c = new C<>().test();