简体   繁体   中英

Inherited method returned reference type

I'm facing the problem described in this question but would like to find a solution (if possible) without all the casts and @SuppressWarning annotations.

A better solution would be one that builds upon the referenced one by:

  • removing @SuppressWarning
  • removing casts

Solutions presented here will be graded with 2 points based on the criteria. Bounty goes to solution with most points or the "most elegant" one if there is more than one with 2 points.

No cast, no @SuppressWarning, few lines only:

public abstract class SuperClass<T extends SuperClass<T>> {
    protected T that;
    public T chain() {
        return that;
    }
}

public class SubClass1 extends SuperClass<SubClass1> {
    public SubClass1() {
        that = this;
    }
}

public class SubClass2 extends SuperClass<SubClass2> {
    public SubClass2() {
        that = this;
    }
}

One approach is to define an abstract method getThis() in Parent class, and make all the Child classes override it, returning the this reference. This is a way to recover the type of this object in a class hierarchy.

The code would look like this:

abstract class Parent<T extends Parent<T>> {

    protected abstract T getThis();

    public T example() {
        System.out.println(this.getClass().getCanonicalName());
        return getThis();          
    }
}

class ChildA extends Parent<ChildA> {

    @Override
    protected ChildA getThis() {
        return this;
    }

    public ChildA childAMethod() {
        System.out.println(this.getClass().getCanonicalName());
        return this;
    }
}

class ChildB extends Parent<ChildB> {

    @Override
    protected ChildB getThis() {
        return this;
    }

    public ChildB childBMethod() {
        return this;
    }
}


public class Main {

    public static void main(String[] args) throws NoSuchMethodException {
        ChildA childA = new ChildA();
        ChildB childB = new ChildB();

        childA.example().childAMethod().example();
        childB.example().childBMethod().example();
    }
}

As per requirement, there is no Casting and no @SuppressWarnings . I learnt this trick few days back from Angelika Langer - Java Generics FAQs .

Reference:

One solution is to override the method in the child class and change the return type to a more specific one, ie. the child type. This requires casting. Instead of using the typical (Child) cast, use the Class#cast(Object) method

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

public class Child extends Parent {
    public Child example() {
        return Child.class.cast(super.example());
    }

    public Child method() {
        return this;
    }
}

The cast is hidden within the standard method. From the source of Class .

public T cast(Object obj) {
    if (obj != null && !isInstance(obj))
        throw new ClassCastException(cannotCastMsg(obj));
    return (T) obj;
}

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