为什么Java中没有子类可见性修饰符?


74

在不止一次的情况下,我发现自己希望获得Java中无法实现的可变可见性。我希望某些成员在他们自己的班级和任何子班级中可见,但对于包的其余部分或世界其他地方不可见。换句话说,我想要这样:

Modifier        Class     Package   Subclass  World
sub-class       Y         N         Y         N

但是,Java的设计师只给了我这个

Modifier        Class     Package   Subclass  World
public          Y         Y         Y         Y
protected       Y         Y         Y         N
no modifier     Y         Y         N         N
private         Y         N         N         N

我想要这样的典型情况是在创建抽象类时。有时我发现抽象的父母需要访问某些成员,但是具体的孩子也需要访问。我可以通过成为成员来给他们这种访问权限protected,但这在我真的不想要的时候打开了对包其余部分的访问权限。

为了完全清楚,我知道这样的修改是不是可以在Java中。我的问题是为什么Java中不包含这样的修饰符?在我看来,这比protected默认值或默认值更自然。仅仅是因为它的原因不够重要,还是与我未曾考虑过的可能的副作用更相关?


1
作为这种限制的解决方法,您可以将变量设为私有,然后使用静态内部类来实现此目的。
杰夫·福斯特

1
也许是因为人们通常创建的子类与父类生活在不同的包中?一个典型的例子是扩展第三方库以提供我们自己的实现。
2011年

1
@adarshr:这是存在子类修饰符的确切原因。如果所有子类都与超类位于同一包中,则与被保护没有什么不同。
aioobe 2011年

5
碰巧的是Java 1.0有了private protected。我相信实施方式有问题。下降到1.1。
汤姆·哈特芬

4
由于与@Michael相同的原因,我也错过了这种可见性。将我的类放在单独的程序包中(抽象超类和具体子类)只是为了限制可见性,这感觉有点“不必要”。还进行了一些骇人听闻的解决方案,例如使超类具体化,将其作为子类中的私有成员变量添加,实现某些接口等,这使代码比应有的变得更加复杂。私有保护通过在继承时实现封装,将复杂性降到最低,确实会使事情变得更好。
罗伯特

Answers:


19

我想他们希望通过具有非线性访问层次结构来避免增加的复杂性。

您应该控制您的包,因此不要在其中调用这些受保护的方法。

(顺便说一下,protected与并不太相同sub-class and package,因为非静态受保护的方法(如果不在同一包中)不能在声明类的任意对象上调用,而只能在代码所在的子类的对象上调用(您可以在上看到它Object.clone(),只能由正在克隆其对象的类调用。)


我不理解您在括号中的评论。受保护的子类可见性+封装可见性。你什么意思?
ewernli 2013年

1
@ewernliprotected少一些。尽管每个类都继承自Object(即clone(),在任何地方都应该可见),但是您不能调用anyObject.clone()任意对象。
圣保罗Ebermann

1
以类似的方式,任何类的实例都可以访问private同一类的另一个实例的成员。您会认为,因为一个成员是private,所以只有该实例才可以访问它,但是正如@PaŭloEbermann所说,您已经可以完全控制该类了。如果要访问private另一个实例的成员,那是因为是用这种方式设计的。同样,如果您正在开发一个程序包,并且访问protected另一个类的成员,那是因为是开发该程序包的那个,其他人没有访问权限。
Michael Plautz 2013年

旧评论/要评论的问题,但是有人可以澄清以下语句:“您应该控制您的软件包”?如果我有一个第三方库,那么我总是可以创建一个具有相同层次结构的包,并在需要时访问受保护的成员。不是这样吗
Mubin

@Mubin是这种情况,是的(如果没有安全管理器来限制哪个类加载器可以在包中创建类)。但是您也可以创建第三方库的修改版本,并通过公开私有成员来实现。或使用反射。所有这些访问修饰符都不是完全防水的。
圣保罗Ebermann

9

与被包装的子类型相比,包装在同一包装中只是一种更紧密的关系。

为什么?

通常,您可以控制你正在开发包的所有源代码(*) ,那么你至少有可能避免作出错误的电话。

控制,扩展你的类的所有代码。(任何人都可以扩展您的课程。)这意味着包私有访问扮演着更重要的角色。


*)但是,嘿,我从那里开始任何源文件,package com.yourpackage;因此您不控制软件包中的所有代码!好吧,是的,但是a)确实不应该这样做,并且b)可以通过密封包装来避免。


我无法决定我认为哪种关系更紧密。我的直觉是,一个子类型是一个更紧密的关系(也许这就是我认为这种修饰符比受保护和默认有意义的部分原因)。但是,某些使用我创建的JAR库的随机编码器可以对我的一个类进行子类化,而我可能知道我的包中发生了什么。嗯...
Michael McGowan

是的 准确地说,我也是这样。如果密封包裹,您甚至可以在最后一句话中“很可能”击中。
aioobe 2011年

我很难想象您不希望使用密封包装的情况。
corsiKa 2011年

3

您应该将您的类放入自己的包中,并将该成员(实例变量或方法)标记为受保护。这样,除子类外,其他任何类都不能访问您作为受保护市场成员。如果您极希望只让子类访问该受保护的成员,则最终在一个包中只有一个类。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.