55

有没有办法强制子类覆盖超类的非抽象方法?

我需要能够创建父类的实例,但是如果一个类扩展了这个类,它必须给出它自己的一些方法的定义。

4

13 回答 13

37

据我所知,没有直接的编译器强制执行此操作的方法。

您可以通过不使父类可实例化来解决它,而是提供一个工厂方法来创建具有默认实现的某些(可能是私有的)子类的实例:

public abstract class Base {
  public static Base create() {
    return new DefaultBase();
  }

  public abstract void frobnicate();

  static class DefaultBase extends Base {
    public void frobnicate() {
      // default frobnication implementation
    }
  }
}

你现在不能new Base(),但你可以做得到Base.create()默认的实现。

于 2011-10-20T07:25:16.957 回答
24

正如其他人指出的那样,您不能直接执行此操作。

但一种方法是使用Strategy 模式,如下所示:

public class Base {
    private final Strategy impl;

    // Public factory method uses DefaultStrategy
    // You could also use a public constructor here, but then subclasses would
    // be able to use that public constructor instead of the protected one
    public static Base newInstance() {
        return new Base(new DefaultStrategy());
    }

    // Subclasses must provide a Strategy implementation
    protected Base(Strategy impl) {
        this.impl = impl;
    }

    // Method is final: subclasses can "override" by providing a different
    // implementation of the Strategy interface
    public final void foo() {
        impl.foo();
    }

    // A subclass must provide an object that implements this interface
    public interface Strategy {
        void foo();
    }

    // This implementation is private, so subclasses cannot access it
    // It could also be made protected if you prefer
    private static DefaultStrategy implements Strategy {
        @Override
        public void foo() {
            // Default foo() implementation goes here
        }
    }
}
于 2011-10-20T20:42:02.240 回答
6

考虑用这个方法做一个接口。类后代将不得不实现它。

于 2011-10-20T07:26:33.417 回答
5

我认为最简单的方法是创建一个继承自基类的抽象类:


public class Base {
    public void foo() {
        // original method
    }
}

abstract class BaseToInheritFrom extends Base {
    @Override
    public abstract void foo();
}

class RealBaseImpl extends BaseToInheritFrom {
    @Override
    public void foo() {
        // real impl
    }
}
于 2012-02-04T16:20:55.850 回答
3

不,这就是抽象方法的全部意义所在。你的用例是什么?也许我们可以根据潜在的需求来考虑它。

于 2011-10-20T07:25:05.147 回答
3

怎么样:在方法的默认实现中,使用反射来获取对象的确切类。如果 Class 与您的基类不完全匹配,则抛出 RuntimeException 或等效项。

public class Parent {

    public void defaultImpl(){
        if(this.getClass() != Parent.class){
            throw new RuntimeException();
        }
    }

}
于 2011-10-20T07:31:54.573 回答
3

不可能是有原因的!

派生类在重写方法时可以简单地调用基类的实现。

那么强制类覆盖你的方法有什么意义呢?我不认为有任何好处。

于 2011-10-20T17:50:27.787 回答
2

答案是否定的。您可以使用模板设计模式重新设计。它可能会帮助你。

或者,您可以让您的子类实现一个接口。接口可能由超类实现,也可能不实现。

于 2011-10-20T07:27:58.967 回答
1

您始终可以使基类具有引发异常的方法。

从技术上讲,基类已经定义了方法,但如果不覆盖该方法,它就无法使用。在这种情况下,我更喜欢运行时异常,因为它们不需要显式的 throws 语句。下面是一个例子

public class Parent {

  public void doStuff() {
    throw new RuntimeException("doStuff() must be overridden");
  }

}

public class Child extends Parent {

  @Override
  public void doStuff() {
    ... all is well here ...
  }

}

缺点是这不会阻止Base对象的创建。但是,任何尝试使用“必须重写”方法之一的人很快就会发现他们应该重写该类。

虽然此解决方案很好地满足了请求的描述,但您的应用程序可能会因不需要这样的解决方案而受益。最好通过编译器检查来避免运行时崩溃,这是 abstract 关键字提供的。

于 2011-10-20T07:39:09.713 回答
1

我将反映其他答案,并说没有编译器强制的方法来强制派生类覆盖非抽象方法。使方法抽象的全部意义在于定义具有此签名的方法必须存在,但不能在基本级别指定,因此必须在派生级别指定。如果在基本级别有一个有效的、非平凡的实现(因为它不是空的并且不只是抛出异常或显示消息),那么这对于调用该方法从派生类的消费者中获得成功。因此,编译器不必强制重写可以在基础级别或派生级别上非常成功地运行的方法。

在您希望派生类覆盖您的工作实现的情况下,很明显,基本实现不会做派生类的消费者想要的。基类要么没有足够的实现,要么是错误的。在这些情况下,您必须相信从您的类派生的程序员会知道他在做什么,因此知道该方法需要被覆盖,因为在使用他的新对象的上下文中它不会产生正确的答案。

我能想到你可以做的一件事。它需要一个抽象基础,以及一个密封的(Javahead 的最终版本)“默认”实现。这样,该方法的基本实现就可以像“基”类一样使用,但是为了为新场景定义不同的类,您必须回到抽象类,并且因此被迫重新实现该方法。该方法可能是该类中唯一的抽象事物,因此仍然允许您使用其他方法的基本实现:

public abstract class BaseClass
{
   public abstract void MethodYouMustAlwaysOverride();

   public virtual void MethodWithBasicImplementation() { ... }
}

public final class DefaultClass:BaseClass
{
   public override void MethodYouMustAlwaysOverride() { ... }

   //the base implementation of MethodWithBasicImplementation 
   //doesn't have to be overridden
}

...

public class DerivedClass:BaseClass
{
   //Because DefaultClass is final, we must go back to BaseClass,
   //which means we must reimplement the abstract method
   public override void MethodYouMustAlwaysOverride() { ... }

   //again, we can still use MethodWithBasicImplementation, 
   //or we can extend/override it
   public override void MethodWithBasicImplementation() { ... }
}

然而,这有两个缺点。首先,因为你不能通过继承访问 DefaultClass 的实现,所以你不能扩展 DefaultClass 的实现,这意味着要做 DefaultClass 所做的,再加上一点,你必须从 DefaultClass 重写代码,违反了 DRY。其次,这只适用于一级继承,因为如果您允许从 DerivedClass 继承,则不能强制覆盖。

于 2011-10-20T14:31:10.193 回答
1

也许这有帮助:

class SuperClass {

    void doStuff(){

        if(!this.getClass().equals(SuperClass.class)){

            throw new RuntimeException("Child class must implement doStuff Method");
        }else{
            //ok
            //default implementation
        }
    }
}

class Child extends SuperClass{

    @Override
    void doStuff() {
        //ok
    }
}

class Child2 extends SuperClass{

}


 new SuperClass().doStuff(); //ok
 new Child().doStuff();         //ok
 new Child2().doStuff();        //error
于 2011-10-20T16:02:41.947 回答
0

好的,让我们这样学习。我遵守 java 风格准则并使用 java 语法。所以假设多重继承和C++模板不可用。

使父类方法抽象不是必须的,在 OOP 中您使用多态的概念。您可以以两种或多种不同的方式使用相同的方法。这称为方法覆盖。

让我们举个例子。

    public class Animal{
       public void makeSound(){
          System.out.println("Animal doesn't know how to make sound");
       }

    }

    public class PussyCat extends Animal{
        public void makeSound(){

           System.out.println("meowwww !!!");
        }

        public static void main(String args[]){
           PussyCat aCat=new PussyCat();
           aCat.makeSound(); 
        }
    }

这将打印“meowww !!!” 屏幕上。

但这并不意味着必须在子类中重写方法 makeSound。

如果需要强制子类重写方法,最好通过类实现接口。

      public Interface audible{
         public void makeSound();

      }

      public class pussyCat implements audible{
          // now you must implement the body of makeSound method here
          public void makeSound(){
            System.out.println("meowwww !!!"); 
          }

          public static void main(String args[]){
           PussyCat aCat=new PussyCat();
           aCat.makeSound(); 
        }
      }

这也将打印“meowwww !!!” 屏幕上

于 2011-10-20T09:20:41.333 回答
0

可能不建议这样做,但您可以在方法实现中抛出异常(类似 MethodeMustBeOverRiddenExp)。当然,这是强制运行时,但可能比什么都好。

于 2018-07-31T19:01:11.313 回答