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


当前回答

当你想到访问修饰符时,你可以这样想(适用于变量和方法):

public-->可从任何位置访问private-->只能在声明它的同一类中访问

现在,当涉及到默认和受保护时,就会出现混乱

默认-->不存在访问修饰符关键字。这意味着它严格在类的包中可用。在该包之外,任何地方都无法访问。

protected-->略低于默认值,并且除了相同的包类之外,它可以由声明的包之外的子类访问。

其他回答

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

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

总结

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

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

访问说明符应用于什么

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

对于顶级作用域中的类,只允许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方法可访问性?

(注意:我不是一个Java程序员,我是一个Perl程序员。Perl没有正式的保护措施,这也许就是为什么我如此理解这个问题的原因:)

私有的

就像你想的那样,只有声明它的类才能看到它。

包专用

它只能由声明它的包看到和使用。这是Java中的默认设置(有些人认为这是错误的)。

受保护的

包Private+可以由子类或包成员看到。

平民的

每个人都能看到。

出版

在我控制的代码之外可见。(虽然不是Java语法,但这对本次讨论很重要)。

C++定义了一个称为“朋友”的附加级别,你对它了解得越少越好。

你什么时候应该用什么?整个想法是封装以隐藏信息。您希望尽可能地向用户隐藏某些操作的细节。为什么?因为这样你以后就可以更改它们,而不会破坏任何人的代码。这使您可以优化、重构、重新设计和修复错误,而不用担心有人在使用您刚刚大修过的代码。

因此,经验法则是让事物尽可能地可见。从私密开始,只在需要时增加更多的可见性。只公开用户需要知道的信息,你公开的每一个细节都限制了你重新设计系统的能力。

如果您希望用户能够自定义行为,而不是将内部公开以便他们可以覆盖它们,那么通常最好将这些内容插入到对象中并将接口公开。这样他们就可以简单地插入一个新对象。例如,如果您正在编写一个CD播放器,并希望“go find info about this CD”位可定制,而不是将这些方法公开,那么您应该将所有这些功能放入其对象中,并仅将对象getter/setter公开。通过这种方式,吝啬于暴露自己的内心会鼓励良好的组合和关注的分离

我只坚持“私人”和“公共”。许多OO语言都有这一点。“受保护”可能很方便,但这是一个骗局。一旦一个接口超过了私有,它就超出了你的控制范围,你必须去查看其他人的代码才能找到用途。

这就是“发布”的概念所在。更改接口(重构它)需要找到使用它的所有代码并进行更改。如果接口是私有的,那么没问题。如果它受到保护,你必须找到所有的子类。如果它是公开的,你必须找到使用你的代码的所有代码。有时这是可能的,例如,如果您正在编写仅供内部使用的公司代码,那么接口是否公开无关紧要。您可以从公司存储库中获取所有代码。但是,如果一个接口被“发布”,如果有代码在您的控制之外使用它,那么您将被罚款。您必须支持该接口,否则可能会破坏代码。即使是受保护的接口也可以被认为是已发布的(这就是为什么我不关心受保护的)。

许多语言发现公共/受保护/私有的等级性质过于局限,不符合现实。为此,有一种特质类的概念,但这是另一种表现。

简而言之

公共:随处可见。protected:可由同一包的类和驻留在任何包中的子类访问。默认(未指定修饰符):可由同一包的类访问。private:只能在同一类中访问。

包装可见。默认值。不需要修改器。

仅对类可见(私有)。

对世界(公众)可见。

对包和所有子类可见(受保护)。

变量和方法可以在不调用任何修饰符的情况下声明。默认示例:

String name = "john";

public int age(){
    return age;
}

私有访问修饰符-私有:

声明为私有的方法、变量和构造函数只能在声明的类本身内访问。私有访问修饰符是限制性最强的访问级别。类和接口不能是私有的。

如果类中存在公共getter方法,则可以在类外部访问声明为私有的变量。

使用私有修饰符是对象封装自身并向外界隐藏数据的主要方式。

示例:

Public class Details{

    private String name;

    public void setName(String n){
        this.name = n;
    }

    public String getName(){
        return this.name;
    }
}

公共访问修饰符-Public:

声明为公共的类、方法、构造函数、接口等可以从任何其他类访问。因此,在公共类中声明的字段、方法和块可以从属于Java世界的任何类访问。

但是,如果我们试图访问的公共类位于不同的包中,那么仍然需要导入公共类。

由于类继承,类的所有公共方法和变量都由其子类继承。

例子:

public void cal(){

}

受保护的访问修饰符-受保护的:

在超类中声明为受保护的变量、方法和构造函数只能由另一个包中的子类或受保护成员类的包中的任何类访问。

受保护的访问修饰符不能应用于类和接口。方法、字段可以声明为受保护,但接口中的方法和字段不能声明为受。

受保护的访问使子类有机会使用helper方法或变量,同时防止非相关类尝试使用它。

class Van{

    protected boolean speed(){

    }
}

class Car{
    boolean speed(){
    }

}
____________________________________________________________________
                | highest precedence <---------> lowest precedence
*———————————————+———————————————+———————————+———————————————+———————
 \ xCanBeSeenBy | this          | any class | this subclass | any
  \__________   | class         | in same   | in another    | class
             \  | nonsubbed     | package   | package       |    
Modifier of x \ |               |           |               |       
————————————————*———————————————+———————————+———————————————+———————
public          |       ✔       |     ✔     |       ✔       |   ✔  
————————————————+———————————————+———————————+———————————————+———————
protected       |       ✔       |     ✔     |       ✔       |   ✘   
————————————————+———————————————+———————————+———————————————+———————
package-private |               |           |               |
(no modifier)   |       ✔       |     ✔     |       ✘       |   ✘   
————————————————+———————————————+———————————+———————————————+———————
private         |       ✔       |     ✘     |       ✘       |   ✘    
____________________________________________________________________