Overriding chained method
Let's have a class A
with a method useful for chaining:
class A {
A foo() {
// do stuff
return this;
}
}
Now you can do a.foo().foo().foo()
(think: builder pattern). Let class B extend it:
class B extends A {
}
B b;
The call now b.foo()
returns a valid type B
, but declared A
. Therefore, I cannot write:
B other = b.foo();
I would need to write:
B other = (B) b.foo();
Or override foo()
in B:
class B extends A {
@Override
B foo() {
super.foo();
return this;
}
}
Is there a good way to do this?
source to share
I did it by implementing an additional generic method as(type)
for the superclass. It helps to make casting for a fluent interface more enjoyable.
class A {
public A foo() {
return this;
}
@SuppressWarnings("unchecked")
public <T extends A> T as(Class<T> clazz) {
return (T) this;
}
}
class B extends A {}
So you can write a.foo().as(B.class).methodOfB(..)
. And you don't need to override foo () in all subclasses.
source to share
Sorry, but you haven't already provided the best way:
B other = (B) b.foo();
This will be the solution for any developer who uses A
and B
.
Rewriting is for you so other developers can just write B other = b.foo();
But there is no other way for the compiler to know that
-
B
is kindA
-
B
compatible, so you won't be using any information when instantiatingA
, but put it inB
The latter is the reason you need to explicitly specify. Example:
int myInt = 2;
short myShort = (short) myInt; // correct
although this works, the compiler requires you to be explicit because in many cases (when myInt
large) you lose precision / information when you click on short
.
If this works:
short myShort = myInt; // wrong
Then the compiler will make its own guess. But only the developer can know that if myInt
it ever matters, more than short
that can persist.
source to share
You can declare class A
to have the general type of your implementation class, or you foo()
can return this dynamic type:
class A<T extends A<T>> {
@SuppressWarnings("unchecked")
T foo() {
// do stuff
return (T) this;
}
}
class B extends A<B> {
B bar() {
// do other stuff
return this;
}
}
After that, the following is valid:
B b = new B();
b.foo().bar();
source to share
I think a good way to do this is to keep the reference as a type A
, as this is the least specific class that has the functionality you need:
A other = b.foo();
You should only use type B if B contains some required functionality:
B another = (B)A;
another.somethingElse();
This is the same logic that does:
List<String> myList = new ArrayList<>();
more desirable than:
ArrayList<String> myList = new ArrayList<>();
source to share