简体   繁体   中英

Chained calls to an object and inheritance in Java

When declaring a method for chained calls usually it returns this at the end of the method.

So I declare:

public class Foo {

    public Foo setTitle(String title){
        ...
        return this;
    }

}

And:

public class Bar extends Foo{

      /* OTHER STUFF */
}

If you call new Bar().setTitle("Test") it returns a Foo 's reference.

Is possible to declare the method in order to return automatically a Bar 's reference without override the method in Bar for clarity, brevity and maintainability?

Thanks

Is possible to declare the method in order to return automatically a Bar's reference without override the method in Bar for clarity, brevity and maintainability?

No. You could hook up some weird generics - Foo<T extends Foo> or the like - but it wouldn't be very satisfactory.

Basically there's need to be some language support for "this type", where the only valid expressions of that type were null and this . That doesn't exist, so you're left with overriding:

public Bar setTitle(String title) {
    super.setTitle(title);
    return this;
}

Or:

public Bar setTitle(String title) {
    return (Bar) super.setTitle(title);
}

It's just one of those cases where inheritance ends up being a pain :(

I did try with generics...

public class Foo<T extends Foo> {

    public T setTitle(String title){
        .....
        return (T) this;
    }
}

public class Bar extends Foo<Bar>{

    /* OTHER STUFF */
}

Seems to work.

I think its actullay returning Bar Only. Just do the type casting to reference the object as Bar as below:

    Bar bar = (Bar)(new Bar().setTitle("Foo Title"));
    System.out.println(bar.getTitle());//prints Foo Title

Assuming getTitle() method present in Foo returning the title.

If you add another method eg getBarTitle in Bar class:

      public String getBarTitle(){
          return getTitle()+" of Bar";
      }

then

  System.out.println(bar.getBarTitle());//prints Foo Title of Bar

Explanation: When you are calling setTitle on new Bar() , the method is called on Bar Object and this is representing Bar object not Foo , hence it returns Bar onject only with class type as Foo , which is super class. In this process, it doesn't change the original class type, which is bar at all, hence the type casting should serve the purpose for you.

You can use generics with upper bounds:

public class Foo<T extends Foo<T>> {
    public T setTitle() {
        ...
        return (T) this;
    }
}

public class Bar extends Foo<Bar> {
    ....
}

To be precide, it does not return a Foo reference, it returns a Bar reference, you can check by using System.out.println(reference.getClass().getName()).

In the same way when you write,

List l=new ArrayList(); 

(forget about LIst being an interface, it is beside the point)

l is actually a reference to ArrayList even if this information is "hidden", but calling l.someMathod() calls ArrayList methods, not List methods - that's how Object Orientation works!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM