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


当前回答

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

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

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

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

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

其他回答

公共-可从应用程序中的任何位置访问。默认-可从包访问。protected-可从其他包中的包和子类访问。也private-只能从其类访问。

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

私有的

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

包专用

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

受保护的

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

平民的

每个人都能看到。

出版

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

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

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

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

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

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

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

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

对于初学者来说,考虑这个例子可能会有所帮助;

考虑到我在foo包中开发了MyClass,它有一个很棒的方法,名为print,您有兴趣调用它(它可能是一个方法或属性)

package foo;  // I am in foo 
public class MyClass {
     private void print() { //This is private
        System.out.println("I can print!");
    }
}

您已经开发了YourClass的bar包,您有兴趣使用MyClass#print

package bar; \\You are not in same package as me 
import foo.MyClass;    
public class YourClass {
    void test() {
        MyClass myClass = new MyClass();
        myClass.print();
    }
}

您的代码未编译,并且出现错误。方法print()对于类型MyClass未定义

你来找我:

你:我想用你的方法,但它是私人的。你能公开吗?我:不,我不想让别人使用你:我是你的朋友,至少让我不要让别人使用它。我:好的,我将删除私有关键字。我的访问修饰符将是默认的或私有的包。因为你们是我的朋友,你们必须和我在同一个包裹里。所以你们必须来到我的包裹里。我的意思是确切的包,甚至不是子包。

然后MyClass将

package foo;    
public class MyClass {    
    void print() { //No access modifier means default or package-private 
        System.out.println("I can print!");
    }   
}

YourClass将是:

package foo;//You come to my package
public class YourClass {
    void test() {
        MyClass myClass = new MyClass();
        myClass.print();
    }
}

不考虑这个:你又来找我了

你:我的老板告诉我我不能改变我的包(在实际世界中,你不能改变你的包以使用其他类方法)我:还有另一种方法,如果你扩展我,我使print()受到保护,那么无论你是否更改包,你都可以使用它。(因此,子类将始终允许您访问我的方法)。

这是我的班级

package foo;
protected class MyClass { // it is now protected
     protected void print() {
        System.out.println("I can print!");
    }   
}

这是YourClass

package bar; // You are on your own package
import foo.MyClass;
public class YourClass extends MyClass {
    void  test() {
        //You initiate yourself! But as you extend me you can call my print()
        YourClass yourClass = new YourClass(); 
        yourClass.print();
    }
}

您可能已经注意到,通过使一个方法受到保护,所有其他类都可以通过扩展它来使用它,您无法轻松控制如何使用它。这在java17中通过引入密封和许可词来解决。因此,您可以定义哪些类可以扩展您。类似于公共密封类MyClass允许YourClass参见Java17中的密封类是什么?有关详细信息

此页很好地描述了受保护的默认访问修饰符(&D)

....受保护:受保护的访问修饰符有点棘手,可以说是默认访问修饰符的超集。就同一包中的访问而言,受保护的成员与默认成员相同。不同的是,受保护的成员也可以访问声明成员的类的子类,这些子类位于父类所在的包之外。

但是,这些受保护的成员“只能通过继承在包外部访问”。即,您可以直接访问某个类的子类中的受保护成员,就像该成员存在于子类本身中一样。但是,通过使用父类的引用,该受保护成员在包外部的子类中将无法访问。....

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

仅对类可见(私有)。

对世界(公众)可见。

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

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

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(){
    }

}