Java中的public,protected,package-private和private之间有什么区别?


3171

在Java中,有没有关于何时使用每个访问修饰符,即默认(包专用),明确的规则publicprotected并且private,同时使classinterface和处理继承?


161
private隐藏包中的其他类。public暴露给包外部的类。protectedpublic仅限于子类的版本。
Museful

87
@Tennenrishin-否;与C ++相反,在Java中protected,该方法也可以从整个程序包访问。Java可见性模型中的这种愚蠢行为打破了的目标protected
Nicolas Barbulesco

35
@Nicolas无论有没有,都可以从整个程序包中访问它protected。作为访问修饰符,唯一protected要做的就是公开包外部的子类。
Museful 2014年

15
@tennenrishin-好吧,这就是尼古拉斯所说的...而您现在就重复一遍。您最初说的是protected(我引用)“是仅限于子类的公共版本”,您自己承认这是不正确的,因为protected也允许通过整个包进行访问(因此,它不限制对子类的访问。 )
luis.espinal 2014年

10
我也同意Nicolas的观点,因为Java中的受保护访问模式是愚蠢的。发生的事情是Java混合了水平(格)和垂直访问限制限定符。默认范围是水平/晶格限制,其中晶格为包装。公共是另一个横向限制,其中格子是整个世界。私有和(C ++)保护是垂直的。如果我们拥有跨切访问权限,那将是更好的选择,例如,protected-package在极少数情况下,我们实际上需要它,而protected使其等同于Protected的C ++版本。
luis.espinal 2014年

Answers:


5636

官方教程可能对您有用。

______________________________________________________________
| │类别│包装│子类│子类│世界|
| │││(相同pkg)│(diff pkg)│|
|──────────┼┼──────┼──────┼ ──┼────────|
|公共│+│+│+│+│+ | 
|──────────┼┼──────┼──────┼ ──┼────────|
|受保护的│+│+│+│+│| 
|──────────┼┼──────┼──────┼ ──┼────────|
|无修饰符│+│+│+││| 
|──────────┼┼──────┼──────┼ ──┼────────|
|私人│+││││|
| ___________ | _______ | _________ | __________ | __________ | ________ |
 +:可访问空白:不可访问

5
上表是不正确的,因为private在同一源文件中,任何类/静态方法都可以看到/使用成员。
宫本宇佐(Usagi Miyamoto)

5
受保护的成员只能从相同程序包的子类访问,而不能从不同程序包的子类访问。上表中应进行更正
尼克斯,

2
世界在您的项目之内。我应该进一步解释。库在您的项目中,如果您要创建库,它们也会公开这些公共类和方法。因此,仅在您的项目中说有点不对。“所有使用它的东西”都是更好的描述。
adprocas '18年

3
例如,如果我有MyClass并且正在做,AnotherClass extends MyClass我将可以从内部访问所有受保护的方法和公共方法和属性AnotherClass。如果我MyClass myClass = new MyClass();AnotherClass某个地方(例如构造函数)进行操作,则只有在其他程序包中,我才可以访问公共方法。请注意,如果执行= new MyClass() { @Override protected void protectedMethod() { //some logic } };此操作,则似乎可以访问受保护的方法,但是这种方法与扩展方法相同,但是可以内联。
adprocas '18年

3
不幸的是,这个答案过于简单了。现实情况要复杂一些,尤其是当您考虑时protected(实际上这是一个很难完全理解的访问修饰符-大多数认为自己知道protected真正含义的人)。而且,正如Bohemian所指出的那样,它并不能回答问题-它没有说明何时使用每个访问修饰符。在我看来,这个回答是不是糟糕,足以downvote,但接近。但是超过4000票?这怎么发生的?
达伍德·本·卡里姆

483

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

私人的

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

包私人

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

受保护的

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

上市

每个人都可以看到。

已发表

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

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

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

因此,经验法则是使事物仅在其必须可见的地方可见。从私有开始,仅根据需要添加更多可见性。仅公开用户必须知道的绝对必要信息,公开的每个细节都会限制您重新设计系统的能力。

如果您希望用户能够自定义行为,而不是公开内部结构以便他们可以覆盖它们,则将这些胆量推入一个对象并将该接口公开是一个更好的主意。这样,他们可以简单地插入新对象。例如,如果您正在编写CD播放器,并且希望对“可以查找有关此CD的信息”进行自定义,而不是公开这些方法,则可以将所有功能放到其自己的对象中,而仅将您的对象获取/设置者公开。这样一来,小胆地暴露胆量就可以促进良好的构图和关注点分离

就我个人而言,我只坚持“私有”和“公开”。许多OO语言就是这样。“受保护”可以派上用场,但这确实是个骗子。一旦接口不只是私有的,它就不在您的控制范围之内,您必须去寻找其他人的代码来寻找用途。

这就是“发布”思想的来源。更改接口(重构接口)要求您找到使用该接口的所有代码,并且也要对其进行更改。如果接口是私有的,那就没问题了。如果受保护,则必须查找所有子类。如果是公开的,则必须查找使用您的代码的所有代码。有时这是可能的,例如,如果您正在处理仅供内部使用的公司代码,则接口是否公开无关紧要。您可以从公司存储库中获取所有代码。但是,如果某个接口是“已发布”的,则如果控件之外有使用该接口的代码,那么您将被束之高阁。您必须支持该接口,否则可能会破坏代码。甚至可以将受保护的接口视为已发布(这就是为什么我不这样做)

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


26
朋友->“越少了解它越好” --->它具有选择性的可见性,这仍然优于包的隐私性。在C ++中,它有其用途,因为并非所有函数都可以是成员函数,并且与朋友相比,公开发布更好。当然,存在被邪恶的人滥用的危险。
塞巴斯蒂安·马赫

30
还应该注意的是,C ++中的“保护”具有不同的含义-受保护的方法实际上是私有的,但仍可以从继承类中调用。(与Java相反,Java可以在同一程序包中的任何类调用它。)
Rhys van der Waerden

9
@RhysvanderWaerden C#在这方面与C ++相同。我发现Java不允许声明一个子类可访问的成员而不是整个包可以访问的成员,这很奇怪。这对我来说有点倒挂-包比子类的范围更广!
康拉德莫拉斯基

15
@KonradMorawski IMHO包的作用域比子类小。如果您尚未将您的类声明为final,则用户应该可以对其进行子类化-因此受Java保护是您已发布接口的一部分。OTOH,软件包是由单个组织隐式开发的:例如com.mycompany.mypackage。如果您的代码在我的程序包中声明了自己,则隐式声明自己是我的组织的一部分,因此我们应该进行沟通。因此,与子类(扩展我的对象的人员)相比,程序包发布给较小的对象/更容易获得受众(我公司的人员),因此算作可见度较低的对象。
同名的2014年

2
friend对于定义类之间的特殊关系很有用。在正确使用的情况下,它可以在许多情况下提供出色的封装效果。例如,特权工厂类可以使用它将内部依赖项注入到构造的类型中。它的名称很不好,因为不关心正确维护设计良好的对象模型的人可能会滥用它来减轻工作量。
丹尼斯2014年

434

这是表格的更好版本,其中还包括模块列。

Java访问修饰符

说明

  • 一个私有成员(i)是唯一的,因为它宣布同一个类中访问。

  • 没有访问修饰符j)的成员只能在同一包中的类内访问。

  • 一个受保护的成员(k)是在同一个包中的所有类中访问其他包中的子类中。

  • 一个公共成员(l)是所有类都可以访问(除非它驻留在一个模块不出口的话,在声明的包)。


选择哪个修饰符?

访问修饰符是一种工具,可帮助您防止意外破坏封装(*)。问问自己,您是否希望成员成为类,包,类层次结构的内部成员或根本不是内部成员,然后相应地选择访问级别。

例子:

  • 一个字段long internalCounter可能是私有的,因为它是可变的和实现细节。
  • 仅应在工厂类(在同一包中)实例化的类应具有受包限制的构造函数,因为不可能直接从包外部调用它。
  • void beforeRender()应该保护在渲染前即被用作子类中的钩子的内部方法。
  • void saveGame(File dst)从GUI代码调用的方法应该是公共的。

(*)什么是封装?


11
只是说:很多人在区分红色/绿色方面有问题。使用红色/绿色(或黄色/橙色/ ...)着色方案的
桌子

1
@GhostCat,我不同意。我认为,红/绿直观地对齐与“工程” /“不工作”对许多人来说,即它比许多替代品更好。
aioobe

8
colourblindawareness.org/colour-blindness / ... ... 8%的色盲男性大致可分为1%氘代鹿角,1%角tan,1%角tan和5%异黄。因为我是那5%的那50%之一,所以请放心:红色/绿色很烂。
GhostCat

6
@GhostCat好..那是我所期望的人口比例更大的部分。我在此色盲模拟器中上传了图像,并测试了所有不同的模式。即使在单色/无色症模式下,色差也是合理的。您能看到区别还是模拟器关闭了?(我仍然认为红色/绿色对于有色人种非常直观。)
aioobe

3
我可以看到其中的区别,但是我也可以通过一半的色盲测试,而这是我们在德国必须取得的驾驶执照;-) ...但是我认为这样的模拟器“足够好”。
GhostCat

206
____________________________________________________________________
                | 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         |              |          |              |       
____________________________________________________________________

1
值得一说-“受保护的修饰符使对象可在其他程序包中使用,而默认/无修饰符将限制对同一程序包的访问”
vanguard69

2
@ vanguard69,protected修饰符使标记的事物(类,方法或字段)可用于某些其他程序包中的某个其他类,除非该其他类是声明该protected标记的事物的类的子类。
阿卜杜勒

“非卧床”?“这个子类在另一个包中”?嗯 我以为我知道Java。
sehe

@AlexanderFarber您是否针对特定的浏览器配置进行了优化?这是我现在的铬,这是Firefox的
sehe

嗯,让我们还原一下我的更改
亚历山大·法伯

165

简单的规则。首先将所有内容声明为私有。然后,随着需求的增长和设计的需要,向公众发展。

公开成员时,请问自己是公开代表选择还是抽象选择。第一个是您要避免的事情,因为它将对实际表示而不是其可观察的行为引入过多的依赖。

作为一般规则,我尝试通过子类化来避免覆盖方法的实现。弄乱逻辑太容易了。如果打算覆盖抽象的受保护方法,请声明它。

另外,在覆盖时使用@Override批注,以防止重构时发生破坏。


3
@RuchirBaronia,“世界” =应用程序中的所有代码,无论它在哪里。
Andrejs

116

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

“默认”访问权限(由缺少关键字指定)也称为package-private。例外:在接口中,没有修饰符表示公共访问;禁止使用除public之外的修饰符。枚举常量始终是公共的。

摘要

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

  • 成员是private:仅当在与调用代码相同的类中定义成员时。
  • 成员是包私有的:仅当调用代码在成员的直接封装中。
  • 成员是protected:相同的包,或者如果成员在包含调用代码的类的超类中定义。
  • 成员是public:是的。

什么是访问说明符

局部变量和形式参数不能使用访问说明符。由于根据作用域规则,它们本质上是外部无法访问的,因此它们实际上是私有的。

对于顶级范围的类,仅public允许使用package-private。这种设计的选择大概是因为protectedprivate将在封装级冗余(没有包装的继承)。

所有访问说明符都可用于类成员(构造函数,方法和静态成员函数,嵌套类)。

相关:Java类可访问性

订购

访问说明符可以严格订购

公共>受保护>包私有>私有

表示public访问最多,private最少。对于包私有成员,任何对私有成员的引用都有效。对包专用成员的任何引用在受保护成员上均有效,依此类推。(在同一软件包中将受保护的成员授予其他类的访问权限被认为是错误的。)

笔记

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

内部班

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

但是,这非常复杂,有关详细信息,请查阅Java Language Specification。(是的,过去有编译器错误。)

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

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

一些相关的问题:


1
“禁止使用非公共的修饰符” —从Java 9开始,情况不再如此:接口也可以具有私有方法。
MC Emperor

96

根据经验:

  • private:类范围。
  • default(或package-private):包范围。
  • protected:(package scope + child与包类似,但我们可以从不同的包中继承它)。protected修饰符始终保持“父子”关系。
  • public:无处不在。

结果,如果我们将访问权限分为三个权限:

  • (D)irect(从同一类内部的方法调用,或通过“ this”语法调用)。
  • (R)引用(使用对类的引用或通过“点”语法调用方法)。
  • (I)继承(通过子类化)。

那么我们有这个简单的表:

+—-———————————————+————————————+———————————+
|                 |    Same    | Different |
|                 |   Package  | Packages  |
+—————————————————+————————————+———————————+
| private         |   D        |           |
+—————————————————+————————————+———————————+
| package-private |            |           |
| (no modifier)   |   D R I    |           |
+—————————————————+————————————+———————————+
| protected       |   D R I    |       I   |
+—————————————————+————————————+———————————+
| public          |   D R I    |    R  I   |
+—————————————————+————————————+———————————+

54

在很短的时间内

  • public:可从任何地方访问。
  • protected:可由同一包的类和任何包中的子类访问。
  • 默认值(未指定修饰符):同一包的类可以访问。
  • private:只能在同一个类中访问。

48

Java中最容易理解的访问修饰符是protected。我们知道它类似于默认修饰符,但有一个例外,子类可以看到它。但是如何?这是一个示例,希望可以澄清这种混淆:

  • 假设我们有2个班级;FatherSon,每个都有自己的包:

    package fatherpackage;
    
    public class Father
    {
    
    }
    
    -------------------------------------------
    
    package sonpackage;
    
    public class Son extends Father
    {
    
    }
  • 让我们添加一个受保护的方法foo()Father

    package fatherpackage;
    
    public class Father
    {
        protected void foo(){}
    }
  • 该方法foo()可以在4个上下文中调用:

    1. foo()定义了(fatherpackage)的同一包中的类内:

      package fatherpackage;
      
      public class SomeClass
      {
          public void someMethod(Father f, Son s)
          {
              f.foo();
              s.foo();
          }
      }
    2. 在子类内部,通过this或在当前实例上super

      package sonpackage;
      
      public class Son extends Father
      {
          public void sonMethod()
          {
              this.foo();
              super.foo();
          }
      }
    3. 在类型相同的引用上:

      package fatherpackage;
      
      public class Father
      {
          public void fatherMethod(Father f)
          {
              f.foo(); // valid even if foo() is private
          }
      }
      
      -------------------------------------------
      
      package sonpackage;
      
      public class Son extends Father
      {
          public void sonMethod(Son s)
          {
              s.foo();
          }
      }
    4. 对于类型为父类且位于定义()的程序包内部的引用,[可将其包含在上下文编号11中。1]:foo()fatherpackage

      package fatherpackage;
      
      public class Son extends Father
      {
          public void sonMethod(Father f)
          {
              f.foo();
          }
      }
  • 以下情况无效。

    1. 在类型为父类且位于定义()的包外部的引用上:foo()fatherpackage

      package sonpackage;
      
      public class Son extends Father
      {
          public void sonMethod(Father f)
          {
              f.foo(); // compilation error
          }
      }
    2. 子类的包内的非子类(子类从其父类继承受保护的成员,并使它们对非子类私有):

      package sonpackage;
      
      public class SomeClass
      {
          public void someMethod(Son s) throws Exception
          {
              s.foo(); // compilation error
          }
      }

Object#clone()protected成员的一个例子。
Eng.Fouad

super.foo()与第一个无效情况有f.foo()什么区别?
cst1992

1
@ cst1992令人困惑,但请参见Java语言规范6.6.2:“可以从仅由负责该对象实现的代码声明该对象的包外部访问该对象的受保护成员或构造函数”。对于super.foo(),引用“ super”是“直接负责实现”,而引用“ f”则不是。为什么?因为您可以100%地确定“ super”是“父亲”类型,而不是“ f”类型;在运行时,它可能是父亲的其他一些子类型。请参阅docs.oracle.com/javase/specs/jls/se9/html/…–
skomisa

1
读懂的人的回答令人耳目一新protected。不幸的是,此页面上定义的所有其他答案protected都使它有点错误。
达伍德·伊本·卡里姆

30

私人的

  • 方法,变量和构造函数

声明为私有的方法,变量和构造函数只能在声明的类本身内访问。

  • 类和接口

专用访问修饰符是最严格的访问级别。类和接口不能是私有的。

注意

如果类中存在公共获取方法,则可以在类外部访问声明为私有的变量。在超类中声明为受保护的变量,方法和构造函数只能由其他包中的子类或受保护成员的类的包中的任何类访问。


受保护的

  • 类和接口

受保护的访问修饰符不能应用于类和接口。

方法,字段可以声明为受保护,但是接口中的方法和字段不能声明为受保护。

注意

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


上市

可以从任何其他类访问已声明为公共的类,方法,构造函数,接口等。

因此,可以从属于Java Universe的任何类中访问在公共类内声明的字段,方法,块。

  • 不同包装

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

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


默认-无关键字:

默认访问修饰符意味着我们不会为类,字段,方法等明确声明访问修饰符。

  • 在同一包装内

在没有任何访问控制修饰符的情况下声明的变量或方法可用于同一包中的任何其他类。接口中的字段隐式为public static final,而接口中的方法默认为public。

注意

我们无法覆盖静态字段。如果您尝试覆盖它,则不会显示任何错误,但是除了我们无法正常工作之外,其他所有内容均不起作用。

相关答案

参考链接

http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html http://www.tutorialspoint.com/java/java_access_modifiers.htm


21

可以在已经提供的链接中找到区别,但是通常使用哪个链接归结为“最低知识原则”。只允许所需的可见度最小。


20

私人:仅限上课者

默认值(无修饰符):限制访问类和包

受保护的:限制访问类,包和子类(包的内部和外部)

Public:可访问类,包(所有)和子类...简而言之,无处不在。


17

访问修饰符可以在多个级别限制访问。

公共:基本上,您可以从任何类(无论是否在同一程序包中)中进行访问而变得如此简单。

要访问您是否在同一包中,可以直接访问,但是如果您在另一个包中,则可以创建该类的对象。

默认值:可以从同一类软件包中的任何一种软件包中访问它。

要访问,您可以创建该类的对象。但是您不能在包外部访问此变量。

受保护:您可以访问同一程序包中的变量以及任何其他程序包中的子类。所以基本上它是默认+继承行为。

要访问基类中定义的受保护字段,您可以创建子类的对象。

私人的: 可以在同一班访问。

在非静态方法中,由于引用(在构造函数中),您可以直接访问,但是在静态方法中,您需要创建类的对象。


16

Java中的访问修饰符。

Java访问修饰符用于提供Java中的访问控制。

1.默认值:

仅可访问同一包中的类。

例如,

// Saved in file A.java
package pack;

class A{
  void msg(){System.out.println("Hello");}
}

// Saved in file B.java
package mypack;
import pack.*;

class B{
  public static void main(String args[]){
   A obj = new A(); // Compile Time Error
   obj.msg(); // Compile Time Error
  }
}

这种访问比公共和受保护的限制更严格,但比私有的限制较少。

2.公开

可以从任何地方访问。(全球访问)

例如,

// Saved in file A.java

package pack;
public class A{
  public void msg(){System.out.println("Hello");}
}

// Saved in file B.java

package mypack;
import pack.*;

class B{
  public static void main(String args[]){
    A obj = new A();
    obj.msg();
  }
}

输出:你好

3.私人的

仅在同一个类内可访问。

如果您尝试访问另一类上的一个类的私有成员,则会引发编译错误。例如,

class A{
  private int data = 40;
  private void msg(){System.out.println("Hello java");}
}

public class Simple{
  public static void main(String args[]){
    A obj = new A();
    System.out.println(obj.data); // Compile Time Error
    obj.msg(); // Compile Time Error
  }
}

4.受保护

仅可访问同一包中的类以及子类

例如,

// Saved in file A.java
package pack;
public class A{
  protected void msg(){System.out.println("Hello");}
}

// Saved in file B.java
package mypack;
import pack.*;

class B extends A{
  public static void main(String args[]){
    B obj = new B();
    obj.msg();
  }
}

输出:你好

在此处输入图片说明



14

对包装可见。默认值。不需要修饰符。

仅对班级可见(私人)。

对世界(公共)可见。

对包和所有子类(protected)可见。

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

String name = "john";

public int age(){
    return age;
}

专用访问修饰符-专用:

声明为私有的方法,变量和构造函数只能在声明的类本身内访问。专用访问修饰符是最严格的访问级别。类和接口不能是私有的。

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

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

例子:

Public class Details{

    private String name;

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

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

公共访问修饰符-公共:

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

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

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

例:

public void cal(){

}

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

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

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

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

class Van{

    protected boolean speed(){

    }
}

class Car{
    boolean speed(){
    }

}

12

该页面很好地描述了受保护的默认访问修饰符

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

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


只需添加以下内容:“一旦孩子访问了父类的受保护成员,它就会成为子类的私有成员(或者更确切地说,可以由子类的子类继承的特殊私有成员)。”
阿南德(Anand)2012年

9

David的答案提供了每个访问修饰符的含义。至于何时使用它们,我建议公开所有类以及每个类的供外部使用的方法(其API),以及其他所有私有的东西。

随着时间的流逝,您将逐渐了解何时将某些类设置为私有包,何时声明受保护的某些方法可在子类中使用。


6

注意:这只是已接受答案的补充

这与Java Access修饰符有关

Java访问修饰符

Java访问修饰符指定哪些类可以访问给定的类及其字段,构造函数和方法。可以为类,其构造函数,字段和方法分别指定访问修饰符。Java访问修饰符有时在日常用语中也称为Java访问修饰符,但正确的名称是Java访问修饰符。类,字段,构造函数和方法可以具有四个不同的Java访问修饰符之一:

  • 项目清单
  • 私人的
  • 默认(包)
  • 受保护的
  • 上市

控制访问到类成员教程:

访问级别修饰符确定其他类是否可以使用特定字段或调用特定方法。访问控制分为两个级别:

  • 在顶层-公共或程序包私有(无显式修饰符)。
  • 在成员级别-公共,私有,受保护或整包私有(无显式修饰符)。

可以使用修饰符public声明一个类,在这种情况下,该类对于所有地方的所有类都是可见的。如果一个类没有修饰符(默认值,也称为package-private),则仅在其自己的包中可见

下表显示了对每个修饰符允许的成员的访问。

╔═════════════╦═══════╦═════════╦══════════╦═══════╗
 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     
╚═════════════╩═══════╩═════════╩══════════╩═══════╝

第一个数据列指示类本身是否有权访问由访问级别定义的成员。如您所见,类始终有权访问其自己的成员。第二列指示与该类在同一个包中的类(无论其亲本)是否有权访问该成员。第三列指示在此包外部声明的类的子类是否有权访问该成员。第四列指示是否所有类都有权访问该成员。

访问级别以两种方式影响您。首先,当您使用其他来源的类(例如Java平台中的类)时,访问级别确定您自己的类可以使用那些类的哪些成员。其次,编写类时,需要确定类中每个成员变量和每个方法应具有的访问级别。


1
补充内容究竟是什么?为什么不对现有帖子进行编辑?
sehe

补充是访问修饰符。为什么不编辑?为了历史原因,保持接受的答案不变,并给出我的答案。
ישואוהבאותך

5

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

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

  1. 类可以是公共的或默认的
  2. 类成员可以是公共的,受保护的,默认的或私有的。

在类之外无法访问Private只能在包中访问Default。在包以及任何扩展它的类中受保护。公众向所有人开放。

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


Default不是访问修饰符,其他两个则拼错了。
user207421 '16

5

我常常意识到,通过创建现实世界的类比,记住任何一种语言的基本概念都可以实现。这是我理解Java中的访问修饰符的类比:

假设您是一所大学的学生,并且有一个朋友将在周末拜访您。假设在校园中间有一个很大的大学创始人雕像。

  • 当您将他带到校园时,您和您的朋友首先看到的是这座雕像。这意味着在校园里散步的任何人都可以在未经大学许可的情况下看雕像。这使得雕像成为PUBLIC

  • 接下来,您想带您的朋友去您的宿舍,但是为此您需要将他注册为访客。这意味着他获得了通行证(与您的通行证相同),可以进入校园内的各种建筑物。这将使他的访问卡被保护

  • 您的朋友想登录校园WiFi,但没有任何凭据。他上线的唯一方法是与他共享登录信息。(请记住,每个上大学的学生都拥有这些登录凭据)。这将使您的登录凭据为NO MODIFIER

  • 最后,您的朋友想阅读您发布在网站上的学期进度报告。但是,每个学生都有自己的个人登录名以访问校园网站的此部分。这将使这些凭据成为PRIVATE

希望这可以帮助!


4

当您想到访问修饰符时,只需以这种方式考虑一下(适用于变量方法):

public->从任何地方
private均可访问->仅在声明它的同一类中可访问

现在产生了困惑,当谈到defaultprotected

default->没有访问修饰符关键字。这意味着它只能在该类的包中使用。在该软件包之外的任何地方都无法访问它。

protected-> default与相同的包类相比,它的严格程度略低,并且可以由声明的之外的子类访问。


4

Java访问会修改您可以使用的

在此处输入图片说明

访问修饰符可以适用于classfield[关于]method。尝试访问,子类化或覆盖它。

  • 访问fieldmethod通过class
  • 遗产。后继class(子类)访问修饰符可以是任何。后继method(覆盖)访问修饰符应该相同或展开

顶级类(第一级作用域)可以是publicdefaultNested class[关于]可以有任何一个

package 不适用于包层次结构

快速访问修饰符


2

这全都与封装有关(或者正如Joe Phillips所说的,最起码的知识)。

首先从限制性最高的(私有)开始,然后再看看是否需要限制性较小的修饰符。

我们所有人都使用方法和成员修饰符,例如private,public ...,但是开发人员很少做的一件事是使用包来逻辑地组织代码。

例如:您可以将敏感的安全方法放在“安全”包中。然后放置一个公共类,该类可以访问此程序包中的某些与安全性相关的代码,但将其他安全性类程序包保持私有。因此,其他开发人员将只能从此程序包外部使用公共可用的类(除非他们更改了修饰符)。这不是安全功能,但将指导使用。

Outside world -> Package (SecurityEntryClass ---> Package private classes)

另一件事是,彼此之间非常依赖的类可能最终会在同一包中,并且如果依赖关系太强,最终可能会被重构或合并。

相反,如果您将所有内容都设置为public,则不清楚应该访问或不应该访问什么,这可能会导致编写大量的javadoc(无法通过编译器强制执行任何操作……)。


2

可变数据类型的私有保护的公共完善类比

以下框图解释如何的数据成员基类继承派生的类的接入方式是私人

在此处输入图片说明

注意:使用私有访问说明符声明数据成员称为数据隐藏。

来源:访问说明–私有,公共和受保护


1
问题是关于Java而不是C ++。
Benoit19年

1
@Benoit但是我发布的内容,特别的图片,对于java和c ++来说是不一样的?此规则也不适用于Java?谢谢
leonidaa

2
在C ++中,只有3个修饰符,而在Java中有4个。
贝努瓦

1
这个比喻很好,但是缺少默认的访问说明符,
mss

1
OP提出了一个问题:“ Java中的public,protected,package-private和private之间有什么区别?”
JL_SO

2

我的两分钱:)

私人的:

class->顶级类不能为私有。内部类可以是私有的,可以从同一类访问。

实例变量->仅在类中可访问。无法在课程外访问。

包私有:

class->顶级类可以是包私有的。只能从同一软件包访问它。不是来自子包,不是来自外部包。

实例变量->可从同一包访问。不是来自子包,不是来自外部包。

受保护的:

class->顶级类不能被保护。

实例变量->仅可在同一包或子包中访问。扩展类时只能在包外部访问。

上市:

类->可从包/子包/另一个包访问

实例变量->可从包/子包/另一个包访问

这是详细的答案

https://github.com/junto06/java-4-beginners/blob/master/basics/access-modifier.md


1
  • 上市

    如果一个类成员被公开声明,那么可以从任何地方访问它

  • 受保护的

    如果使用关键字protected声明了类成员,则可以从相同的类成员,相同的包中的外部类成员以及继承的类成员访问它。如果一个类成员受到保护,那么除非从外部打包的类继承,即不能扩展另一个打包的超类,否则不能从外部的打包类访问它。但是受保护的类成员始终可用于相同的包类,无论继承还是不继承相同的包类都没有关系

  • 默认

    在Java中,默认不是访问修饰符关键字。如果声明的类成员没有任何访问修饰符关键字,则在这种情况下,它将被视为默认成员。默认的类成员始终可用于相同的包类成员。但是,即使外部类是不同于受保护成员的子类,外部包类成员也无法访问默认类成员

  • 私人的

    如果使用关键字protected声明了类成员,则在这种情况下,仅对相同的类成员可用


-1

Java中的访问说明:Java中有4个访问说明,即访问顺序递增的私有,程序包私有(默认),受保护和公共。

私有的:当您正在开发某个类时,如果您不想让该类的成员暴露于此类之外,则应将其声明为私有。私有成员只能在定义了私有成员的类(即封闭类)中访问。私有成员可以在'this'引用以及包含这些成员的类的其他实例上访问,但只能在此类的定义内。

Package-private(默认):此访问说明符将提供私有访问说明符指定的访问权限,除了以下所述的访问权限。

当您开发某个包并因此开发其中的某个类(例如Class1)时,可以使用默认(无需明确提及)访问说明符,以将类中的成员公开给您(相同)包中的其他类。在这些其他类(在同一包中)中,您可以在Class1的实例上访问这些默认成员。您也可以访问Class1的子类中的这些默认成员,例如Class2(在此引用上或在Class1的实例上或在Class2的实例上)。

基本上,在同一个包中,您可以直接在类的实例上或在子类的“ this”引用上访问默认成员。

protected:除了以下描述的访问之外,此访问说明还将提供由程序包专用访问说明指定的访问。

当您开发某个包并因此开发其中的某个类(例如Class1)时,如果您不希望在包外部访问该成员(例如,在Consumer的包中),则应对Class1中的数据成员使用受保护的访问说明符。您的程序包,即通常使用API​​的客户端),但您希望例外,并且仅当客户端编写扩展Class1的类Class2时才允许访问此成员。因此,通常,在派生类(即Class2)中的“ this”引用上以及在Class2的显式实例上都可以访问受保护的成员。

请注意:

  1. 如果试图在Class1的显式实例上访问它,则将无法访问Class2中继承的Class1的受保护成员,尽管它是在Class1中继承的。
  2. 当您在扩展Class2的相同/不同包中编写另一个类Class3时,可以在此引用以及Class3的显式实例上访问Class1的受保护成员。这对于任何扩展的层次结构都是正确的,即在该引用或扩展类的实例上仍可访问受保护的成员。请注意,在Class3中,如果您创建Class2的实例,则尽管它是继承的,但您将无法从Class1访问受保护的成员。

因此,最重要的是,只有在其他包中的某个类扩展了包含该受保护成员的类的扩展类,并且可以在扩展对象的定义内的“ this”引用或扩展类的显式实例上访问受保护成员时,才可以在其他包中访问受保护成员。类。

public:除了以下描述的访问之外,此访问说明还将提供受保护的访问说明所指定的访问。

当您正在开发某个包并因此在其中开发某个类(例如Class1)时,如果您希望该成员在其他包的某个类中创建的Class1实例的其他包中可访问,则应该对Class1中的数据成员使用公共访问说明符包。基本上,当您打算将数据成员无条件公开给世界时,应使用此访问说明符。

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.