当前位置: 首页 > 知识库问答 >
问题:

防止子类添加方法

邵逸明
2023-03-14

这似乎是一件奇怪的事情,但是在Java中有没有办法阻止子类添加新方法(包括构造函数),同时仍然允许子类重写方法?

实际情况是,我们有一个带有一些抽象方法和构造函数的抽象类

abstract class A {
  abstract A doX();
  abstract boolean isY();
  public A(String s){ ... };
}

我们希望这个类的所有具体子类只重写这些方法和构造函数。

这是关于在我们的代码中强制使用某种风格,即阻止其他人在代码中添加内容。我们可以告诉他们不要这样做,但这很少奏效,所以我们想知道是否有一种程序化的方式来实现这一点。

显然,这个类不能是final。效率不是最重要的——更干净的代码更重要。

更新-动态方法

正如答案中所指出的那样,静态地实现这一点是不可能的,因为防止创建子类的唯一方法是使用final,这是行不通的。但我可以使用动态方法,所以我目前的解决方案是将这个方面添加到项目中(该项目已经使用了AspectJ)。

   public aspect WatchA{
      before() : execute(* A.*()) || execute(* A.*(..)) {
         String methodCalled = joinPoint.getSignature().getName();
         Class<?> c = Class.forName(args[0])
         Method[] allMethods = c.getDeclaredMethods();
         boolean found = false;
         for(Method m : allMethods)
           found |= m.getName().equals(methodCalled);
         if(!found) 
           throw new RuntimeException("Do not add method "+methodCalled+" to A");
      }
   }

如果他们使用这些新方法,这将导致他们的测试失败。


共有3个答案

端木令雪
2023-03-14

没有这种办法。为什么要强制执行这种编码风格?

如果你真的必须执行这样的风格,你可以创建一个“规则执行器”,它检查你的类路径,并将抽象父类的方法与其子类进行比较。

薄欣怿
2023-03-14

如果你真的不想这么做。。一种方法是通过编程在抽象类构造函数中检查类中定义的方法是否是允许的方法。

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public abstract class Base {

    private static final Set<String> allowedMethodNames = new HashSet<>(Arrays.asList("doThis", "wait", "wait", "wait", "equals", "toString", "hashCode", "getClass", "notify", "notifyAll"));

    public Base() {
        Set<String> allMethods = new HashSet<>();
        for (Method aMethod : getClass().getMethods()) {
            allMethods.add(aMethod.getName());
        }
        if (!allowedMethodNames.equals(allMethods)) {
            allMethods.removeAll(allowedMethodNames);
            throw new IllegalStateException("Following methods not allowed <" + allMethods + ">");
        }
    }

    public abstract void doThis();
}

public class Disallowed extends Base {

    @Override
    public void doThis() {
        System.out.println("dooooooo");
    }

    public void doSomethingElse() {
        System.out.println("not allowed");
    }

    public static void main(String[] args) {
            new Allowed().doThis();
        new Disallowed();
    }

}

public class Allowed extends Base {

    @Override
    public void doThis() {
        System.out.println("doing this");
    }


}

当有人试图创建“不允许”的实例时,它将失败。但是“新的”是允许的()。doThis()会很好用的。

一种更优雅的方法是引入自定义注释处理器,并在编译期间进行相同的检查。

况浩邈
2023-03-14

你不能那样做。只有当类是final时,才能确保不能创建任何子类。

还可以将方法设置为final(即使是在抽象类中),这样就禁止重写它们。

最好的办法是创建一个接口,其中包含所有你希望可见的方法,并强制你的应用编程接口的所有用户通过这个接口访问对象。这样,即使实现添加了自己的东西,这些东西也不可见。

一种解决方案是实现一个工厂来返回具体的类;为了“增加安全性”,您可以将所有实现与此工厂放在同一个包中,并使构造函数包成为本地的(但这通常是不实际的):

public final class MyFactory
{
    // ....
    public MyInterface getConcrete()
    {
        return new MyInterfaceImpl();
    }
    // etc etc -- getStones(), getTar(), getFeathers() and so on
}

请注意,构建器也可以用于此目的。

 类似资料:
  • 我有一个主类。应用程序中有许多子类是从类扩展而来的。base类公开公共方法,如下所示: 应用程序将在子实例上调用以获得一个检查器实例。每个子类都可以有自定义的基本检查器和验证检查器。他们可以使用和方法实现它,但是他们不能覆盖基类的,因为它包含处理逻辑。 在这里使用关键字合适吗?

  • 要发布一个插件,我必须更改代码以使用Wordpress HTTP API。 因此,我翻译了我的代码。 之前。 之后 但是对于函数wpremotepost我有这个问题。 当JSON数据发送到远程主机时,数据内部带有反斜杠。 示例: 怎么啦? 我在翻译原点代码时有错吗? 我需要一些帮助来发送没有这些转义字符的JSON数据。 多谢了。

  • 我使用Spring Boot框架构建了一个REST接口。然后,我使用Swagger版本2.9.2来生成文档。从下面的照片可以看到,Swagger自动检测了很多模型。 所以,我的问题是:我怎么告诉Swagger该曝光哪些模特? 下面是我的控制器的Swagger配置和代码片段。 控制器:

  • 在本节中,我们将学习如何保护交付方法。使用XArp或静态ARP表等工具来防止中间人攻击,避免不知道的网络。另一个预防措施是确保在下载更新时使用HTTP。这将降低下载虚假更新的风险。 我们将学习另一个有用的工具,即WinMD5。当程序的签名或校验和以任何方式被修改时,该程序将提醒我们,这表明该文件不是原始文件。为了检查,我们将下载并运行WinMD5,我们可以在其中比较文件的签名和校验和。如果签名和校

  • 问题内容: 有没有办法用javascript / jquery防止图像加载?我正在从带有图像的html列表构建幻灯片。因此,我想收集所有src数据,然后阻止加载图像。因此,稍后当用户真正需要图像时,我便会加载它。 我在Google上找到了一些延迟加载脚本,但找不到阻止图像加载的方式。 提前致谢。 Edit1: 从答案看来,不可能使用javascript来防止图像加载。 这是一个执行延迟加载的脚本。

  • 这很奇怪返回一个:https://static.javadoc.io/tech.tablesaw/tablesaw-core/0.32.6/tece/tablesaw/api/table.html#join-java.lang.String...- 我认为,是一个,所以也许Groovy正在使用它自己的join方法。 真正奇怪的是,如果我将Tablesaw版本从切换到,即使也在该版本中实现了 知道如