有没有办法创建一个不是抽象但必须重写的方法?

发布于 2024-12-10 22:45:03 字数 79 浏览 0 评论 0原文

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

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

Is there any way of forcing child classes to override a non-abstract method of super class?

I need to be able to create instances of parent class, but if a class extends this class, it must give its own definition of some methods.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

零時差 2024-12-17 22:45:03

据我所知,没有直接的编译器强制方法可以做到这一点。

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

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()来获取默认实现。

There is no direct compiler-enforced way to do this, as far as I know.

You could work around it by not making the parent class instantiable, but instead providing a factory method that creates an instance of some (possible private) subclass that has the default implementation:

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

You can't write new Base() now, but you can do Base.create() to get the default implementation.

软的没边 2024-12-17 22:45:03

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

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

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

As others have pointed out, you can't do this directly.

But one way to do this is to use the Strategy pattern, like so:

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
        }
    }
}
杀お生予夺 2024-12-17 22:45:03

考虑使用此方法创建一个接口。阶级后代将不得不实施它。

Consider making an interface with this method. Class descendants will have to implement it.

山色无中 2024-12-17 22:45:03

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


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

I think the easiest way is to create an abstract class that inherits from the base class:


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
    }
}
生死何惧 2024-12-17 22:45:03

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

public class Parent {

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

}

How about this: inside the default implementation of the method, use reflection to get the exact Class of the object. If the Class does not match your base class exactly, throw a RuntimeException or equivalent.

public class Parent {

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

}
我是有多爱你 2024-12-17 22:45:03

这是不可能的原因

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

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

There's a reason it's not possible!

The derived class could simply call the base class's implementation when overriding the method.

So what's the point of forcing the class to override your method? I don't think there's any benefit.

嘿看小鸭子会跑 2024-12-17 22:45:03

不,这就是抽象方法的全部意义。您的用例是什么?或许我们可以根据底层需求来思考。

No, that's the whole point of an abstract method. What is your use case? Perhaps we can think about it based on the underlying need.

可爱暴击 2024-12-17 22:45:03

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

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

Answer would be a no. You can redesign using template design pattern. It may help you.

Alternatively, you can make your child classes implement an interface. The interface may or may not be implemented by the super class.

素手挽清风 2024-12-17 22:45:03

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

从技术上讲,基类已经定义了该方法,但如果不重写该方法,它就无法使用。在这种情况下,我更喜欢运行时异常,因为它们不需要显式的 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关键字所提供的。

You can always make the base class have a method that throws an exception.

Technically the base class has defined the method, but it is not usable without overriding the method. In such a case, I prefer a runtime exception as they don't require an explicit throws statement. An example follows

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

}

The downside is that this doesn't prevent creation of Base objects; however, anyone attempting to use one of the "must be overridden" methods will soon find that they should have overridden the class.

While this solution meets the description of the request well, your application would probably benefit from not requiring a solution like this one. It's much better to avoid runtime crashes with compiler checks, which is what the abstract keyword provides.

陌伤ぢ 2024-12-17 22:45:03

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

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

我能想到你可以做的一件事。它将需要一个抽象基础,以及一个密封的(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 继承,则无法强制覆盖。

I will mirror the other answers and say that there is no compiler-enforced way to force derived classes to override a non-abstract method. The whole point of making a method abstract is to define that a method with this signature must exist, but cannot be specified at the base level and therefore must be specified at a derived level. If there is a working, non-trivial implementation (as in it's not empty and doesn't just throw an exception or show a message) of a method at the base level, then this isn't strictly necessary in order for a call to the method from a consumer of the derived class to succeed. So, the compiler doesn't have to enforce overriding a method that can run quite successfully on either the base or derived levels.

In situations where you would want a derived class to override your working implementation, it should be pretty obvious that the base implementation doesn't do what the derived class's consumers will want; the base class either doesn't have enough implementation, or the wrong one. In those cases, you have to trust that a programmer deriving from your class will know what he is doing and thus know that the method needs to be overridden because it does not produce the right answer in the context of using his new object.

I can think of one thing you could do. It would require an abstract base, with a sealed (final for the Javaheads) "default" implementation. That way, there is a basic implementation of the method that is readily available to use as if it were a "base" class, but in order to define a different class for a new scenario, you must go back to the abstract class, and are thus forced to reimplement the method. This method could be the only abstract thing on the class, thus still allowing you to make use of basic implementations of other methods:

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() { ... }
}

However, this has two drawbacks. First, because you do not have access to DefaultClass's implementation through inheritance, you cannot extend DefaultClass's implementation, meaning that to do what DefaultClass does, plus a little more, you must rewrite the code from DefaultClass, violating DRY. Second, this only works for one level of inheritance, because you cannot force overriding if you allow inheritance from DerivedClass.

花伊自在美 2024-12-17 22:45:03

也许这有帮助:

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

maybe this helps:

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
热鲨 2024-12-17 22:45:03

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

使父类方法抽象并不是必须的,
在面向对象编程中,您使用多态性的概念。您可以通过两种或多种不同的方式使用相同的方法。
这称为方法重写。

让我们举个例子。

    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 !!!”在屏幕上

ok, let's learn it this way. I adhere to java style guidelines and use java syntax. So it is assumed that multiple inheritance and C++ templates are unavailable.

making the parent class method abstract is not a must,
in OOP you use the concept of polymorphism. you can use the same method in two or more different ways.
This is called method overriding.

let's take an example.

    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(); 
        }
    }

this will print "meowww !!!" on the screen.

but this doesn't imply that the method makeSound must be overridden in the child class.

If you need the child class to be forced to override the methods, you better implement an interface by the class.

      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(); 
        }
      }

this will also print "meowwww !!!" on the screen

颜漓半夏 2024-12-17 22:45:03

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

It may not be recommended, but you can throw an exeption( something like MethodeMustBeOverRiddenExp) in your methode implementation.
Of course it is RunTime forcing but may be better than nuthing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文