38

Is there any elegant way to make Java method located within parent class return object of child class, when this method is called from child class object?

I want to implement this without using additional interfaces and extra methods, and to use this without class casts, auxiliary arguments and so on.

Update:

Sorry that I was not so clear.

I want to implement method chaining, but I have problems with methods of parent class: I lose access to child class methods, when i call parent class methods... I suppose that I'v presented the core of my idea.

So the methods should return this object of this.getClass() class.

7 Answers 7

78

If you're just looking for method chaining against a defined subclass, then the following should work:

public class Parent<T> { public T example() { System.out.println(this.getClass().getCanonicalName()); return (T)this; } } 

which could be abstract if you like, then some child objects that specify the generic return type (this means that you can't access childBMethod from ChildA):

public class ChildA extends Parent<ChildA> { public ChildA childAMethod() { System.out.println(this.getClass().getCanonicalName()); return this; } } public class ChildB extends Parent<ChildB> { public ChildB childBMethod() { return this; } } 

and then you use it like this

public class Main { public static void main(String[] args) { ChildA childA = new ChildA(); ChildB childB = new ChildB(); childA.example().childAMethod().example(); childB.example().childBMethod().example(); } } 

the output will be

org.example.inheritance.ChildA org.example.inheritance.ChildA org.example.inheritance.ChildA org.example.inheritance.ChildB org.example.inheritance.ChildB 
Sign up to request clarification or add additional context in comments.

6 Comments

Thank you so much. This is the exact what I want.
perfect. But I need to add @SuppressWarnings("unchecked") to example().
This works for OP, but unfortunately for me (and OP in this question), it doesn't work if you also want to make GrandChild extend ChildA. =(
Should be Parent<T extends Parent<T>>, no?
I'm using this implementation but the IDE warns about Unchecked cast: 'mypackage.MyClass<T> to T'. Maybe after all this years there is another way?
|
8

What are you trying to achieve ? It sounds like a bad idea. A parent class should not know anything about its children. It seems awfully close to breaking the Liskov Substitution Principle. My feeling is that your use case would be better serve by changing the general design, but hard to say without more informations.

Sorry to sound a bit pedantic, but I get a bit scared when I read such question.

2 Comments

My use case is the following: I have classes that describe the functionality of a UI screen. Then I perform multiple actions on the screen using the following syntax: currentScreen.actionA().actionB().actionC(); But then what if an action is common for all screens and therefore I want to implement it in a parent class? In this case I want the method in the parent class return with the child object, so that I can continue calling actions on the child screen as if all actions were implemented as methods of the child class.
It doesn't violate the Liskov Substitution Principle. It's just a quirk of Java syntax to avoid explicit casts and compiler warnings.
3

Simply to demonstrate:

public Animal myMethod(){ if(this isinstanceof Animal){ return new Animal(); } else{ return this.getClass().newInstance(); } } 

3 Comments

This method would have to be changed again and again as subclasses are added, changed and removed. Still, a solution nonetheless.
@BoltClock, Was just demonstrating, I have resolved your problem in this update.
how to define new Animal(TigerData) return Tiger instance and new Animal(LionData) return Lion Instance. thank you
2

You can call this.getClass() to get the runtime class.

However, this is not necessarily the class that called the method (it could be even further down the hierarchy).

And you would need to use reflection to create new instances, which is tricky, because you do not know what kind of constructors the child class has.

return this.getClass().newInstance(); // sometimes works 

2 Comments

That sounds like: A parent can produce a child through reflection but it's not guaranteed to be his. :)
It is going to be a subclass of the current class, because this always is. It could be an indirect subclass, though.
1

I know exactly what you mean, in Perl there is the $class variable which means if you call some factory method on a subclass, even if it is not overridden in the subclass, if it instanciates any instances of $class an instance of the subclass will be created.

Smalltalk, Objective-C, many other languages have a similar facility.

Alas, there is no such equivalent facility in Java.

2 Comments

In Perl there's no such thing as a generic built-in $class variable at all. It can be computed by retrieving the first argument to a class method (e.g. MyClass->mySub() call passes "MyClass" as a first parameter) or by taking a ref() of an object (which is a first argument of an method called on an object, e.g. $myclass_object->mySub() call passes $myclass_object as a first parameter and ref($myclass_object) returns "MyClass"). Please know what you're talking about.
But, as you say, the first argument to a class method is always the name of the class the method was applied on. This means you can write methods which then do $class->newInstance() which will create instances of subclasses if the method is called on a subclass. Useful for factory methods, template method pattern in construction, and so on. In Java, static MyObj newInstance() { .. } will always produce a MyObj even if you call MySubObj.newInstance() and there is no way around that like there is e.g. in Perl.
1

If you are using Kotlin, you can create an extension function

abstract class SuperClass class SubClass: SuperClass() fun <T : SuperClass> T.doSomething(): T { // do something return this } val subClass = SubClass().doSomething() 

Comments

0
public class Parent { public Parent myMethod(){ return this; } } public class Child extends Parent {} 

And invoke it like

 Parent c = (new Child()).myMethod(); System.out.println(c.getClass()); 

Is this solution is correct? If it is, then, how is it different from the #1 solution?

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.