在Java中,为什么使受保护成员可以访问同一包的类?


14

从官方文件 ...

修饰符类包子类世界 
公开YYYY 
受保护的YYYN 
没有修饰符YYNN 
私人YNNN 

问题是,我不记得有一个用例,在该用例中,我需要从同一包中的类访问受保护的成员。

执行此操作的原因是什么?

编辑:为澄清起见,我正在寻找一个特定的用例,其中同一包中的子类和类都需要访问受保护的字段或方法。

package some.package;
public class A {
 protected void protectedMethod(){
  // do something
 }
}

package another.package;
public class B extends A{
 public void someMethod(){
  // accessible because B is a subclass of A
  protectedMethod();
 }
} 

package some.package;
public class C {
 public void anotherMethod(){
  // accessible because C is in the same package as A
  protectedMehtod();
 }
}

Answers:


4

寻找一个特定的用例,其中同一包中的子类和类都需要访问受保护的字段或方法...

对我来说,这样的用例不是一般的,而是特定的,它源于我的偏好:

  1. 从尽可能严格的访问修饰符开始,仅在认为有必要时才使用较弱的访问修饰符。
  2. 单元测试是否与测试代码位于同一程序包中。

从上面开始,我可以使用默认的访问修饰符开始为我的对象进行设计(我将从开始,private但这会使单元测试复杂化):

public class Example {
    public static void main(String [] args) {
        new UnitTest().testDoSomething(new Unit1(), new Unit2());
    }

    static class Unit1 {
        void doSomething() {} // default access
    }
    static class Unit2 {
        void doSomething() {} // default access
    }

    static class UnitTest {
        void testDoSomething(Unit1 unit1, Unit2 unit2) {
            unit1.doSomething();
            unit2.doSomething();
        }
    }
}

片段中的Unit1Unit2和的旁注UnitTest是为了简化演示而嵌套在其中Example,但是在实际项目中,我可能会将这些类放在单独的文件中(UnitTest甚至在单独的目录中)。

然后,在必要时,我会将访问控制从默认值减弱为protected

public class ExampleEvolved {
    public static void main(String [] args) {
        new UnitTest().testDoSomething(new Unit1(), new Unit2());
    }

    static class Unit1 {
        protected void doSomething() {} // made protected
    }
    static class Unit2 {
        protected void doSomething() {} // made protected
    }

    static class UnitTest {
        // ---> no changes needed although UnitTest doesn't subclass
        // ...and, hey, if I'd have to subclass... which one of Unit1, Unit2?
        void testDoSomething(Unit1 unit1, Unit2 unit2) {
            unit1.doSomething();
            unit2.doSomething();
        }
    }
}

您会看到,ExampleEvolved由于可以从同一程序包访问受保护的方法,因此即使访问对象不是子类,我也可以保持单元测试代码不变。

所需的更改更少=>更安全的修改;毕竟,我只更改了访问修饰符,并且没有修改方法Unit1.doSomething()Unit2.doSomething()操作,因此自然可以期待单元测试代码无需修改即可继续运行。


5

我说这包括两个部分:

  1. 在许多情况下,默认的“包”访问是有用的,因为类并非总是好的封装单位。各种复合对象,其中某些对象充当其他对象的集合,但这些项目不能公开修改,因为整个集合中存在一些不变性,因此该集合需要对这些项目具有提升的访问权限。C ++有朋友,Java有包访问权限。
  2. 现在,“包”访问范围基本上独立于“子类”(受保护)范围。因此,您将需要仅用于包,仅子类以及包和子类的其他访问说明。“包”范围受到更多限制,因为包中的类集通常是确定的,而子类可能出现在任何地方。因此,为了简单起见,Java仅将包访问包括在受保护的访问中,并且没有用于子类而不是包的额外说明符。尽管您几乎总是应该这样认为protected

如果protected仅是子类,会不会更简单?老实说,很长一段时间以来,我的印象就是这种行为
jramoyo 2013年

@jramoyo:不,因为您仍然需要以某种方式使合并的行为可用,这意味着另一个说明符。
2013年

6
@jramoyo-在C#中,protected仅是类和子类,并且internal是库/包范围的。它还具有protected internal与Java等效的功能protected
Bobson

@Bobson-谢谢,C#实现似乎是一个更好的选择
jramoyo 2013年

5

恕我直言,这是Java中的错误设计决定。

只是推测,但是我认为他们希望访问级别严格地提高:私有-“软件包”-保护-公共。他们不希望有一个层次结构,其中某些字段可用于包,但不能用于子类,某些字段可用于子类,但不能用于包,而另两个字段则适用。

但是,以我的拙见,它们应该采取另一种方式:说保护的仅对类和子类可见,而包对类,子类和包可见。

我经常在一个类中有数据,子类需要该数据,但包的其余部分则不需要。我很难想像情况相反。我遇到过几次罕见的情况,我有一堆相互关联的类需要共享数据,但是这应该使该数据不受束外的影响。好的,可以将它们放在包中,等等。但是我从来没有想过要包共享数据,但是我想将其保留在子类之外。好吧,我可以想象情况会发生。我想如果这个包是一个可以被我一无所知的类扩展的库的一部分,出于同样的原因,我会将类中的数据设为私有。但是,更常见的是只希望对班级及其子级提供数据。

在我和我的孩子之间,我有很多事情要保密,我们不与邻居分享。我和邻居之间几乎没有什么私事,不与我的孩子分享。:-)


0

马上想到的一个很好的例子是实用程序类,该实用程序类在软件包中使用很多,但是您不希望公共访问(从磁盘,场景创建/销毁类等背后的场景图像加载)。 ),而不是把一切[Java的等价物。friend access modifier or idiomC++所有其他类应有尽有]自动可供使用。


1
实用程序类更多地是内部整体而不是其成员内部的类的示例。
Jan Hudec

0

保护/程序包访问修饰符的用例与C ++中的朋友访问修饰符的用例相似。

一种用例是实现Memento模式时

memento对象需要访问对象的内部状态以保留它,以便用作撤消操作的检查点。

由于Java没有“ friend”访问修饰符,因此在同一包中声明类是实现Memento模式的一种可能方法。


1
不,纪念品对象不需要并且不应具有对该对象的任何访问权。该对象将自身序列化为纪念品并再次反序列化。纪念品本身只是一个笨拙的财产袋。双方都不应比其他人更能公开访问。
Jan Hudec

@JanHudec我从字面上说“是-> <<实现Memento模式的可能方法”
图兰斯·科尔多瓦

实现Memento模式的另一种可能方法是将所有内容公开。也就是说,我看不到你的意思。
Thomas Eding

-1

对称?

很少需要这种访问,这就是为什么很少使用默认访问的原因。但是有时框架希望它用于生成的代码,其中包装器类放置在与您的类直接交互的同一包中,出于性能原因将其传递给成员而不是访问器。


1
谢谢,你有例子吗?听起来可以通过“默认”访问器而不是“受保护”来完成
jramoyo13年

-1

Java的封装层次结构定义明确:

类->包->继承

与Java设计师决定的默认程序包相比,“受保护”只是一种较弱的隐私形式。对程序包默认项目的访问仅限于允许访问受保护项目的实体的子集。

从数学和实现的角度来看,让您的实体集可以嵌套访问是非常有意义的。(您不能将程序包访问权限集嵌套在受保护的访问权限集中,因为允许类从其他程序包继承)。

从概念的角度来看,在java.util中使某些内容与该包中的子类的com.example.foo.bar中的某些内容“比”包中的另一个类“更友好”是有意义的。在前一种情况下,这些类可能是由同一作者或至少来自同一组织的编码人员编写的。


1
“只是较弱的形式...”是什么意思?
蚊蚋
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.