在Java中,在创建类和接口以及处理继承时,是否有明确的规则来确定何时使用每个访问修饰符,即默认的(包私有)、公共的、受保护的和私有的?


当前回答

注:这只是对公认答案的补充。

这与Java访问修改器有关。

从Java访问修改器:

Java访问修饰符指定哪些类可以访问给定的类及其字段、构造函数和方法。访问修饰符可以为类、其构造函数、字段和方法。Java访问修饰符有时也在日常使用中使用语音作为Java访问说明符,但正确的名称是Java访问修改器。类、字段、构造函数和方法可以具有四种不同的Java访问修饰符:列表项目私有的默认(包)受保护的平民的

从控制对班级成员的访问教程:

访问级别修饰符确定其他类是否可以使用特定字段或调用特定方法。有两个级别访问控制:在顶层public或package private(没有显式修饰符)。在成员级别public、private、protected或package private(没有显式修饰符)。类可以用修饰符public声明,在这种情况下类对任何地方的所有类都可见。如果类没有修饰符(默认值,也称为包专用),它仅可见在其自己的包装内下表显示了每个成员允许的成员访问权限修改器。╔═════════════╦═══════╦═════════╦══════════╦═══════╗║ 修改器║ 班║ 包裹║ 子类║ 世界║╠═════════════╬═══════╬═════════╬══════════╬═══════╣║ 平民的║ Y║ Y║ Y║ Y║║ 受保护的║ Y║ Y║ Y║ N║║ 无修饰符║ Y║ Y║ N║ N║║ 私有的║ Y║ N║ N║ N║╚═════════════╩═══════╩═════════╩══════════╩═══════╝第一个数据列指示类本身是否有权访问由访问级别定义的成员。正如你所看到的,一个班级总是可以访问自己的成员。第二列指示是否类(无论其父母)有权访问该成员。第三列表示在该包外部声明的类的子类是否具有访问该成员。第四列指示是否所有类可以访问该成员。访问级别以两种方式影响您。首先,当您使用来自另一个源,访问级别决定您自己的这些类的哪些成员类可以使用。第二,当你写一门课时,你需要决定类中每个成员变量和每个方法的访问级别应该有。

其他回答

官方教程可能对您有所帮助。


Class Package Subclass
(same pkg)
Subclass
(diff pkg)
World
public + + + + +
protected + + + +
no modifier + + +
private +

+:可访问空白:不可访问

它实际上比简单的网格显示要复杂一些。网格告诉是否允许访问,但访问到底由什么构成?此外,访问级别以复杂的方式与嵌套类和继承交互。

“默认”访问(由缺少关键字指定)也称为包专用。异常:在接口中,没有修饰符表示公共访问;禁止公共以外的修饰语。枚举常量始终是公共的。

总结

是否允许使用此访问说明符访问成员?

成员是私有的:仅当成员与调用代码在同一类中定义时。成员是包专用的:仅当调用代码位于成员的直接封装包内时。成员受保护:相同的包,或者如果成员是在包含调用代码的类的超类中定义的。成员公开:是的。

访问说明符应用于什么

局部变量和形式参数不能采用访问说明符。由于根据范围界定规则,外部无法访问它们,因此它们实际上是私有的。

对于顶级作用域中的类,只允许public和package private。这种设计选择大概是因为受保护和私有在包级别是冗余的(没有包的继承)。

所有访问说明符都可以在类成员(构造函数、方法和静态成员函数、嵌套类)上使用。

相关:Java类可访问性

顺序

访问说明符可以严格排序

public>protected>package private>private

这意味着公共提供的访问最多,而私人提供的访问最少。对私有成员的任何引用对包私有成员也是有效的;对包私有成员的任何引用都对受保护成员有效,依此类推。(将受保护成员的访问权限授予同一包中的其他类被认为是错误的。)

笔记

允许类的方法访问同一类的其他对象的私有成员。更准确地说,类C的方法可以访问C的任何子类的对象上的C的私有成员。Java不支持仅通过类而通过实例限制访问。(与Scala相比,Scala确实支持使用private[this]。)您需要访问构造函数来构造对象。因此,如果所有构造函数都是私有的,那么类只能由类中的代码(通常是静态工厂方法或静态变量初始化器)来构造。对于包私有或受保护的构造函数也是如此。只有私有构造函数也意味着类不能在外部子类化,因为Java需要子类的构造函数隐式或显式调用超类构造函数。(但是,它可以包含一个将其子类化的嵌套类。)

内部类

您还必须考虑嵌套范围,例如内部类。复杂性的一个例子是内部类具有成员,这些成员本身可以接受访问修饰符。因此,您可以拥有一个具有公共成员的私有内部类;可以访问该成员吗?(见下文。)一般规则是查看范围并递归地思考,看看是否可以访问每个级别。

然而,这非常复杂,有关详细信息,请参阅Java语言规范。(是的,过去曾出现过编译器错误。)

要了解这些交互的方式,请考虑以下示例。“泄漏”私有内部类是可能的;这通常是一个警告:

class Test {
    public static void main(final String ... args) {
        System.out.println(Example.leakPrivateClass()); // OK
        Example.leakPrivateClass().secretMethod(); // error
    }
}

class Example {
    private static class NestedClass {
        public void secretMethod() {
            System.out.println("Hello");
        }
    }
    public static NestedClass leakPrivateClass() {
        return new NestedClass();
    }
}

编译器输出:

Test.java:4: secretMethod() in Example.NestedClass is defined in an inaccessible class or interface
        Example.leakPrivateClass().secretMethod(); // error
                                  ^
1 error

一些相关问题:

包私有类内的Java方法可访问性?

Public Protected Default和private是访问修饰符。

它们用于封装,或隐藏和显示类的内容。

类可以是公共的或默认的类成员可以是公共的、受保护的、默认的或私有的。

课堂外无法访问私人课程默认值只能在包中访问。在包以及扩展它的任何类中受到保护。公众对所有人开放。

通常,成员变量被定义为私有的,但成员方法是公共的。

我经常意识到,通过创造真实世界的类比,记住任何语言的基本概念都是可能的。下面是我在Java中理解访问修饰符的类比:

让我们假设你是一个大学的学生,你有一个朋友周末来拜访你。假设校园中央有一座大学创始人的大雕像。

当你把他带到校园时,你和你的朋友首先看到的就是这尊雕像。这意味着任何在校园里行走的人都可以在没有大学许可的情况下观看雕像。这使雕像成为公共的。接下来,你想带你的朋友去你的宿舍,但为此你需要将他登记为访客。这意味着他可以获得进入校园各个建筑的通行证(与你的通行证相同)。这将使他的门禁卡受到保护。你的朋友想登录校园WiFi,但没有任何凭据。他唯一可以上网的方式是你和他分享你的登录信息。(记住,每个上大学的学生都拥有这些登录凭据)。这将使您的登录凭据为NO MODIFIER。最后,你的朋友想看看你在网站上发布的学期进度报告。然而,每个学生都有自己的个人登录来访问校园网站的这一部分。这将使这些凭据成为PRIVATE。

希望这有帮助!

Java中最容易被误解的访问修饰符是受保护的。我们知道它类似于默认修饰符,只有一个例外,子类可以看到它?这里有一个例子,希望能澄清这一困惑:

假设我们有2个类;父亲和儿子,每个人都有自己的包装:包父包;公共课父亲{}-------------------------------------------package-sonpackage;公共课儿子延伸父亲{}让我们向Father添加一个受保护的方法foo()。包父包;公共课父亲{受保护的void foo(){}}方法foo()可以在4种上下文中调用:在位于定义foo()的同一包中的类内(父包):包父包;公共类SomeClass{公共无效方法(父f,子s){f.foo();s.foo();}}在子类内部,在当前实例上通过this或super:package-sonpackage;公共课儿子延伸父亲{public void sonMethod(){this.foo();super.foo();}}在类型为同一类的引用上:包父包;公共课父亲{公共无效父方法(父f){f.foo();//即使foo()是私有的,也有效}}-------------------------------------------package-sonpackage;公共课儿子延伸父亲{公共无效sonMethod(Sons){s.foo();}}在一个类型为父类的引用上,该引用位于定义foo()的包内(父包)[这可以包含在上下文1中]:包父包;公共课儿子延伸父亲{公共无效sonMethod(父f){f.foo();}}以下情况无效。在类型为父类且位于定义foo()的包(父包)外部的引用上:package-sonpackage;公共课儿子延伸父亲{公共无效sonMethod(父f){f.foo();//编译错误}}子类包中的非子类(子类从其父类继承受保护的成员,并使其成为非子类的私有成员):package-sonpackage;公共类SomeClass{public void someMethod(儿子)引发异常{s.foo();//编译错误}}