有没有办法做出一个不抽象但必须重写的方法?
有没有办法迫使孩子类重写超类的非抽象方法?
我需要能够创build父类的实例,但是如果一个类扩展了这个类,它必须给它自己的一些方法的定义。
就我所知,没有直接的编译器强制的方式来做到这一点。
您可以通过不使父类可实例化来解决这个问题,而是提供一个工厂方法来创build一些具有默认实现的(可能的私有)子类的实例:
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()
以获取默认实现。
正如其他人指出的那样,你不能直接这样做。
但是做到这一点的一个方法是使用战略模式 ,就像这样:
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 } } }
考虑用这个方法做一个接口。 阶级后裔将不得不执行它。
我认为最简单的方法是创build一个从基类inheritance的抽象类:
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 } }
不,这是一个抽象方法的全部。 你的用例是什么? 也许我们可以根据潜在的需求来思考它。
怎么样:在方法的默认实现里面,使用reflection来获取对象的确切类。 如果该类与您的基类完全不匹配,请抛出RuntimeException或等价物。
public class Parent { public void defaultImpl(){ if(this.getClass() != Parent.class){ throw new RuntimeException(); } } }
有一个原因是不可能的!
重写方法时,派生类可以简单地调用基类的实现。
那么迫使class级重写你的方法有什么意义呢? 我不认为有任何好处。
答案将是一个没有。 您可以使用模板devise模式进行重新devise。 它可以帮助你。
或者,你可以让你的子类实现一个接口。 接口可能会或可能不会被超类实现。
你总是可以让基类有一个抛出exception的方法。
从技术上讲,基类已经定义了这个方法,但是如果不覆盖这个方法,它是不可用的。 在这种情况下,我更喜欢运行时exception,因为它们不需要显式的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 ... } }
缺点是这并不妨碍创buildBase
对象; 然而,任何试图使用“必须重写”的方法之一很快就会发现他们应该重写这个类。
虽然此解决scheme很好地满足了请求的描述,但您的应用程序可能会从不需要像这样的解决scheme中受益。 用编译器检查来避免运行时崩溃要好得多,这是abstract关键字提供的。
我将镜像其他答案,并说没有编译器强制的方式来强制派生类来重写一个非抽象的方法。 做一个抽象方法的要点是要定义具有这个签名的方法必须存在,但不能在基本级别指定,因此必须在派生级别指定。 如果在基本级别上有一个工作的,不重要的实现(因为它不是空的,不会抛出exception或显示消息),那么这对于调用从派生类的消费者的方法成功。 因此,编译器不必强制重写可以在基本级别或派生级别上成功运行的方法。
在你想要一个派生类重写你的工作实现的情况下,应该很明显的是,基本的实现不会做派生类的用户需要的东西; 基类要么没有足够的实现,要么是错误的。 在这种情况下,你必须相信从你的类派生出来的程序员会知道他在做什么,从而知道这个方法需要被覆盖,因为它在使用他的新对象的上下文中没有产生正确的答案。
我可以想到你可以做的一件事。 这将需要一个抽象的基础,与密封(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() { ... } }
但是,这有两个缺点。 首先,因为你没有通过inheritance来访问DefaultClass的实现,所以你不能扩展DefaultClass的实现,这意味着要做什么DefaultClass,再加上一点点,你必须重写DefaultClass的代码,违反DRY。 其次,这只适用于一个级别的inheritance,因为如果允许inheritanceDerivedClass,则不能强制覆盖。
也许这有助于:
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
好吧,让我们这样学习吧。 我坚持java风格的指导方针,并使用java语法。 所以假设多inheritance和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(); } }
这也将打印“喵!!!” 屏幕上