【问题标题】:Inherited method returned reference type继承方法返回的引用类型
【发布时间】:2013-10-15 22:05:12
【问题描述】:

我面临this question 中描述的问题,但希望找到一个没有所有强制转换和@SuppressWarning 注释的解决方案(如果可能)。

更好的解决方案是基于以下引用的解决方案:

  • 删除@SuppressWarning
  • 移除演员表

此处介绍的解决方案将根据标准评分为 2 分。赏金会以最高分或“最优雅”的解决方案来解决,如果有超过 2 分的解决方案。

【问题讨论】:

标签: java generics inheritance


【解决方案1】:

没有演员表,没有@SuppressWarning,只有几行:

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;
    }
}

【讨论】:

  • 这被选为最佳答案,因为它完全避免了强制转换,没有 @SuppresWarnings 并且据我说是最优雅的,因为它还避免了方法覆盖(你必须“覆盖的参考" 看起来更干净并且需要更少的代码;它也对用户隐藏,你完全覆盖了任何东西)。将在 23 小时内奖励赏金。
  • @pnt 这与您引用的问题中接受的答案基本相同。为什么你不喜欢它并在这里接受它?
  • @FrancoisBourgeois 实际上,这不是同一个解决方案。在另一种解决方案中,在抽象类中使用return (T) this;,编译器在编译时无法知道强制转换是否安全(即使可以,也只有开发人员知道),因此需要@SuppressWarning 注释。在我的解决方案中,无需转换,因为 that 直接在子类中设置。而这个no-cast解决方案正是这里所要求的。
  • @pnt 为什么你认为这个答案比下面来自 Rohit 的答案更好?想要使用这个抽象类的人需要知道他必须在构造函数中分配that = this。但是,如果他不这样做,那么您不会收到任何警告,但是您的代码将在运行时失败。使用下面 Rohit 的回答,您需要重写该方法并返回正确的实例,这样会更好且不易出错。
【解决方案2】:

一种方法是在Parent 类中定义一个抽象方法getThis(),并让所有Child 类覆盖它,返回this 引用。这是一种在类层次结构中恢复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();
    }
}

根据要求,没有 Casting@SuppressWarnings。几天前我从Angelika Langer - Java Generics FAQs 学到了这个技巧。

参考:

【讨论】:

  • 您可能想要声明Parent&lt;T extends Parent&lt;T&gt;&gt;。否则你可以做extends Parent&lt;String&gt;,方法链接将在String getThis()结束。
【解决方案3】:

一种解决方案是覆盖子类中的方法并将返回类型更改为更具体的类型,即。子类型。这需要铸造。不要使用典型的(Child) 演员表,而是使用Class#cast(Object) 方法

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;
    }
}

演员表隐藏在标准方法中。来自Class的来源。

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

【讨论】:

  • 不是真正的解决方案,因为它不会删除演员表(只是包装和隐藏它们)并且不能解决引用问题中的原始问题。是的,当然您可以重写该方法以返回更具体的类型,但重点是重新使用它,而不必在每个子项中重写它。
  • @pnt 所陈述的问题是我想在不使用额外接口和额外方法的情况下实现它,并且在没有类转换、辅助参数等的情况下使用它。 事情你不能。提出的解决方案都有额外的方法和/或额外的参数。要么覆盖有问题的方法,要么在父级中引入另一个方法并覆盖它。在泛型方案中,还需要引入类型参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-26
  • 1970-01-01
  • 2020-11-20
  • 2014-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多