有没有办法让一个方法不是抽象的但必须被覆盖?

时间:2011-10-20 07:21:34

标签: java inheritance override abstract-class abstract-methods

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

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

13 个答案:

答案 0 :(得分: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()来获取默认实现。

答案 1 :(得分:24)

正如其他人所指出的,你不能直接这样做。

但实现此目的的一种方法是使用策略模式,如下所示:

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

答案 2 :(得分:6)

考虑使用此方法创建接口。类后代必须实现它。

答案 3 :(得分: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
    }
}

答案 4 :(得分:3)

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

答案 5 :(得分:3)

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

public class Parent {

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

}

答案 6 :(得分:3)

原因是不可能的!

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

那么迫使班级覆盖你的方法有什么意义呢?我认为没有任何好处。

答案 7 :(得分:2)

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

或者,您可以使子类实现接口。该接口可能由超类实现,也可能不实现。

答案 8 :(得分: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关键字提供的。

答案 9 :(得分:1)

我将镜像其他答案并说没有编译器强制方法来强制派生类覆盖非抽象方法。制作方法摘要的重点是定义具有此签名的方法必须存在,但不能在基本级别指定,因此必须在派生级别指定。如果在基本级别存在一个工作的,非平凡的实现(因为它不是空的并且不仅仅抛出异常或显示消息),那么这对于调用来说并不是绝对必要的。来自派生类的使用者的方法成功。因此,编译器不必强制覆盖可以在基本或派生级别上非常成功运行的方法。

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

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

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继承,则不能强制覆盖。

答案 10 :(得分: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

答案 11 :(得分: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 !!!”在屏幕上

答案 12 :(得分:0)

可能不建议这样做,但是您可以在方法实现中抛出一个异常(类似于MethodeMustBeOverRiddenExp)。 当然,这是运行时强制,但可能胜于营养。