禁止在其包外部直接扩展Java类

时间:2009-04-08 13:17:13

标签: java inheritance api-design

我有一个带

的包
public abstract class Player { /*...*/ }

和这些

public abstract class GamePlayer extends Player { /*...*/ }
public abstract class TournamentPlayer extends Player { /*...*/ }
public abstract class StatelessPlayer extends Player { /*...*/ }

该软件包的用户需要玩家,但为了使用该软件包而不破坏它,我要求他们永远直接扩展播放器。相反,他们应该扩展一个提供的子类。

问题:我应该如何阻止用户直接扩展播放器?

我正在寻找一种明显禁止这种禁令的方法。

5 个答案:

答案 0 :(得分:18)

使Player中的构造函数仅具有包访问权限。然后他们将无法调用构造函数或自行扩展它。如果您还没有Player显式构造函数,请创建一个(否则编译器将创建一个默认的公共无参数构造函数)。

(请注意,我只建议对构造函数执行此操作。类本身可以是公共的,以便客户端仍然可以使用它。)

这是有效的,因为任何构造函数(除java.lang.Object之外)都必须调用超类构造函数(显式或隐式)。如果没有可访问的构造函数,则无法创建子类。

答案 1 :(得分:9)

确保Player的构造函数不公开:

public abstract class Player {
    Player() {
        // initialization goes here
    }
}

然后类可以从同一个包中扩展Player,但不能从包外部扩展。

答案 2 :(得分:0)

嗯......让播放器类非公开?只要省略“public”,那么它将是package-private,即只有同一个包中的类才能扩展它。

但是,没有任何东西可以直接阻止人们将自己的类放在该包中。我相信可以通过将其放入已签名的JAR来阻止它,然后在同一个包中加载未签名(或不同签名)类的任何尝试都将失败。

答案 3 :(得分:0)

我建议

  • 为您希望客户端访问但不创建或子类
  • 的内容创建公共接口
  • 为您希望客户端访问创建或子类
  • 的内容创建公共类
  • 其他任何事情都应该是非公开的

这种方法的问题在于,您最终需要将所有内容都放在一个软件包中,这对于随着库的增长而对组织而言是不利的。

要允许使用带保护的多个包,请查看OSGi。

OSGi允许您限制bundle(jar)允许其他bundle访问哪些包,甚至设置允许额外可见性的“friend”包。

当你真的想保护那些变大的库时,Java的package-as-protection-unit模型还不够......

答案 4 :(得分:-1)

使用默认访问修饰符,也称为“包私有”访问。换句话说,不要指定访问修饰符

abstract class Player { /*...*/ }

documentation here at Sun's website更详细地描述了所有访问修饰符。