通过超类返回与类名相同的数据类型?

时间:2017-07-19 12:51:26

标签: java oop

我有一个abstract class,它有一个abstract方法。我希望这个方法return 与覆盖方法的类相同的数据类型,而不必转换create的结果或必须在上面创建新的方法声明每个子类。我希望所有这些都可以从父类中无声地声明。

我希望该方法返回一个对象,其数据类型与调用它的类相同。

编辑:我删除了印刷品,因为人们对我的要求感到困惑

abstract class A
{
   public abstract ... create();
}

class B extends A
{
   @override
   public ... create()
   {
      return new B...;
   }
}

class C extends A
{
   @override
   public ... create()
   {
      return new C...;
   }
}

这样

B x1 = new B();
B x2 = x1.create();
// Since create was called on a B object
// a B object is returned, NOT AN "A" object

C y1 = new C();
C y2 = y1.create();
// create makes a C object this time,
// because it's called on a C object

// Problem: create() returns A object, even when
// called from class B or C.
// I want create() to return a B object if called from a B object.

这会是一个好方法吗?感谢。

5 个答案:

答案 0 :(得分:5)

我不再认为这是正确的答案。它是一个答案,但过于复杂。请参阅my other answer

没有" self"输入Java的泛型。你能做的最好就是使用自我约束的泛型:

abstract class A<T extends A<T>>
{
   public abstract T create();
}

然后,在您的子类中:

class B extends A<B>
{
   @override
   public B create()
   {
      return new B...;
   }
}

答案 1 :(得分:1)

实际上,有一种比使用my other answer更简单的方法:只需在子类中使用协变返回类型:

abstract class A {
  public abstract A create();
}

class B extends A {
  @Override public B create() {
    return new B...
  }
}

如果你正在处理A的实例,这会更令人愉快,因为你不必使它成为通用的(或者是颤抖的,原始的)。

它也提供了返回“自我”类型的保证,即根本不保证。

答案 2 :(得分:0)

我必须质疑设计方法。

我要去

abstract class A {
    abstract Supplier<? extends A> create();
}

class B extends A {
    public Supplier<B> create() {
        return B::new;
    }
}

(和C相应)。 然后,有

A b = new B();
A anotherB = b.create().get(); // will create a B
A c = new C();
A anotherC = c.create().get(); // will create a C

答案 3 :(得分:0)

您不需要将create方法摘要化。如果所有子类都有一个无参构造函数,那么你可以写一下(在类A中)

public A create() {
    try {
        return getClass().newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
        return null;
    }
}

这将检查您调用方法的对象的类;并使用其无参数构造函数创建同一类的新对象。

<强>更新

OP的评论表明他们不想投出返回的值。如果这是一项要求,则可以通过更改方法签名来避免转换,如下所示。

public <T extends A> T create() {
    try {
        return getClass().newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
        return null;
    }
}

答案 4 :(得分:0)

this.getClass()获取类对象,或this.getClass().getSimpleName()获取类名的字符串