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

禁止Java类在其包外直接扩展,java,inheritance,api-design,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 { /*...*/ } 软

我有一个包裹,上面有

public abstract class Player { /*...*/ }
这些呢

public abstract class GamePlayer extends Player { /*...*/ }
public abstract class TournamentPlayer extends Player { /*...*/ }
public abstract class StatelessPlayer extends Player { /*...*/ }
软件包的用户需要玩家,但为了使用软件包而不破坏它,我要求他们永远不要直接扩展播放器。相反,它们应该扩展提供的一个子类

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


我正在寻找一种方法,使这项禁令的目的显而易见。

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

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

更详细地描述了所有访问修饰符。

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

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


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

请确保Player的构造函数不是公共的:

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

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

嗯。。。使玩家类非公开?只需省略“public”,那么它将是包私有的,即只有同一包中的类才能扩展它

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

我建议

  • 为您希望客户端访问但不创建或子类的内容创建公共接口
  • 为您希望客户端访问和创建的对象或子类创建公共类
  • 其他任何东西都应该是非公开的
这种方法的问题在于,最终需要将所有内容都放在一个包中,随着库的增长,这对组织不利

要允许使用多个具有保护功能的软件包,请查看OSGi

OSGi允许您限制一个bundle(jar)允许其他bundle访问的包,甚至可以设置允许额外可见性的“朋友”bundle


当您真的想要保护变得很大的库时,Java的包作为保护单元模型是不够的…

,但是客户端甚至可以看到这个类吗?很抱歉,我手头没有javac来检查我自己。不,他们不会-这就是为什么它应该是非公共的构造函数。另一种可能是公共接口,结合包私有抽象基类…呃,Jon Skeet是正确的,我下意识地回答说,在没有意识到该课程仍然需要公开的情况下。Alnitak的建议也很好。我相信这会阻止在包外使用,而不仅仅是继承。关于隐式公共默认构造函数的注释+1