java-有没有办法使方法不是抽象的但必须被覆盖?
有什么方法可以强迫子类覆盖超类的非抽象方法?
我需要能够创建父类的实例,但是如果一个类扩展了该类,则它必须给出自己的某些方法的定义。
13个解决方案
37 votes
据我所知,没有直接的编译器强制方法可以做到这一点。
您可以通过不使父类实例化,而提供一种工厂方法来创建具有默认实现的某些(可能的私有)子类的实例,来解决此问题:
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()以获取默认实现。
Joachim Sauer answered 2020-01-08T00:01:21Z
24 votes
正如其他人指出的那样,您不能直接执行此操作。
但是执行此操作的一种方法是使用策略模式,如下所示:
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
}
}
}
Daniel Pryden answered 2020-01-08T00:01:45Z
6 votes
考虑使用此方法创建接口。 类后代将必须实现它。
Ivan Nikitin answered 2020-01-08T00:02:05Z
5 votes
我认为最简单的方法是创建一个从基类继承的抽象类:
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
}
}
s106mo answered 2020-01-08T00:02:25Z
3 votes
不,这就是抽象方法的重点。 您的用例是什么? 也许我们可以根据基本需求来考虑它。
mjaggard answered 2020-01-08T00:02:45Z
3 votes
怎么做:在该方法的默认实现中,使用反射来获取对象的确切类。 如果该类与您的基类不完全匹配,则抛出RuntimeException或等效类。
public class Parent {
public void defaultImpl(){
if(this.getClass() != Parent.class){
throw new RuntimeException();
}
}
}
curioustechizen answered 2020-01-08T00:03:05Z
3 votes
有一个原因是不可能的!
重写方法时,派生类可以简单地调用基类的实现。
那么,强制类重写您的方法有什么意义呢? 我认为没有任何好处。
Mehrdad answered 2020-01-08T00:03:34Z
2 votes
答案是否定的。 您可以使用模板设计模式进行重新设计。 它可能会帮助您。
或者,您可以使子类实现一个接口。 该接口可以由也可以不由超类实现。
Ravi Bhatt answered 2020-01-08T00:03:59Z
1 votes
您始终可以使基类具有引发异常的方法。
从技术上讲,基类已定义了该方法,但是在不重写该方法的情况下它是不可用的。 在这种情况下,我更喜欢运行时异常,因为它们不需要显式的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关键字提供的。
Edwin Buck answered 2020-01-08T00:04:33Z
1 votes
我将镜像其他答案,并说没有编译器强制的方法来强制派生类重写非抽象方法。 使方法抽象化的全部目的是定义具有此签名的方法必须存在,但不能在基本级别上指定,因此必须在派生级别上指定。 如果在基本级别上有一个有效的,不平凡的实现(例如,它不为空,并且不只是抛出异常或显示消息),那么对于调用 从派生类的使用者获取成功的方法。 因此,编译器不必强制重写可以在基本或派生级别上相当成功地运行的方法。
在您希望派生类重写您的工作实现的情况下,很明显,基本实现不能满足派生类的使用者所希望的事情。 基类没有足够的实现,或者实现不正确。 在这些情况下,您必须相信派生自您的类的程序员将知道他在做什么,因此知道该方法需要重写,因为在使用他的新对象的上下文中它不能产生正确的答案。
我可以想到您可以做的一件事。 它将需要一个抽象的基础,并带有一个密封的(对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继承,则不能强制覆盖。
KeithS answered 2020-01-08T00:05:10Z
1 votes
也许这会有所帮助:
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
Rodrigo answered 2020-01-08T00:05:30Z
0 votes
好的,让我们这样学习。 我遵守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 !!!” 屏幕上
Tharindu Rusira answered 2020-01-08T00:06:17Z
0 votes
可能不建议这样做,但是您可以在方法实现中抛出一个异常(例如MethodeMustBeOverRiddenExp)。当然,这是运行时强制,但可能胜于轻巧。
Itay wazana answered 2020-01-08T00:06:37Z