【Java】访问修饰符(Access Modifier)

Posted by 西维蜀黍 on 2019-03-29, Last Modified on 2021-10-02

访问修饰符(Access Modifier)

**访问控制修饰符(Access Modifier)**用来定义类、类的方法或者类的成员变量。

我们通过下面的例子来说明:

public class className {
   // ...
}
private boolean myFlag;
static final double weeks = 9.5;
protected static final int BOXWIDTH = 42;
public static void main(String[] arguments) {
   // 方法体
}

Java中有三种访问修饰符,分别是public、protected和private,不带任何修饰符则称之为default。

Java的访问权限控制只存在于编译阶段,而编译生成的字节码文件事实上没有留下任何痕迹,只是在编译的时候进行访问权限的检查。

因此,通过反射的手段,可以访问任何包下任何类的成员,例如,访问类的私有成员也是没问题的。

public

被public修饰的类、类的方法或者类的成员变量,它具有最大的被访问权限。

protected

被protected修饰的类的方法或者类的成员变量, 对同一包内的类,或者其所有的子类内部可见。

分析1

这里说,被protected修饰的类的方法或者类的成员变量,对所有的子类内部可见,是指在子类中的构造函数、成员方法中,能够访问到这些被protected修饰的类的方法或者类的成员变量。

然而,通过这个子类的实例对象,是无法访问到这个被protected修饰的类的方法或者类的成员变量的。

分析2

被protected修饰的类的方法或者类的成员变量, 对所有的子类内部可见。这意味着,无论这些子类是否与父类处于同一个包,这些被protected修饰的类的方法或者类的成员变量,在子类内部都可见。

看下面的例子:

package com.p1;
public class A {
    protected void method1() {
    }
}

package com.p2;
public class B extends A {
    public B() {
      	// 正确
        this.method1();
      
      	// 正确
      	super.method1();
    }
}

package sw.test;
public class Test {
    public static void main(String[] args) {
        A b = new B();
        // b.method1();  错误
      
      	A a = new A();
      	// a.method1();  错误
    }
}

修饰对象:变量、方法。

注意:不能修饰类(外部类)、接口及接口的成员变量和成员方法

默认访问修饰符-不使用任何关键字

使用默认访问修饰符(即不使用任何关键字)声明的类、类的成员变量或成员方法,对同一个包内的类是可见的。

private

对于被private修饰的类的方法或者类的成员变量,它们的访问范围仅限于类的内部,是一种封装的体现。

例如,大多数的成员变量都是修饰符为private的,因为它们不希望被任何外部的类访问。

声明为private(私有访问类型)的变量只能通过类中公共的 getter 方法被外部类访问。

public class Logger {
   private String format;
   public String getFormat() {
      return this.format;
   }
   public void setFormat(String format) {
      this.format = format;
   }
}

注意,外部类和接口不能声明为 private。而内部类天然地需要用private来修饰。

private与final

用private来修饰final方法是没有意义的。

因为声明为final方法的目的,就是不允许子类覆盖这个final方法,然而加上private后,这个方法对于子类而言不具有可见性,谈何覆盖。

private与abstract

用private来修饰abstract方法是错误的,

abstract方法要求在子类中具体来实现它。然而加上private后,这个abstract方法对于子类而言不具有可见性,谈何实现(覆盖)。

private修饰构造函数

使用private修饰构造函数后,将不能在其他类中通过new的方式来实例化一个这个类的对象。

因此,使用private修饰构造函数,能够有效控制对象的创建行为,这在有些设计模式中是非常重要的。

总结

类内部 本包 子类 外部包
public
protected ×
default × ×
private × × ×

接口的访问修饰符

接口的访问修饰符只有public和默认(default)。

接口里的成员变量默认都隐式声明为 public static final,而接口里的方法默认情况下访问权限为 public

接口中的所有方法都是抽象方法,不会有任何实现,而它的具体实现在实现这个接口的具体类中完成。而且,这个接口中的方法是不可更改的。同样的,接口中的变量也是不可更改的。所以,要声明为final。

类的访问修饰符

类的访问修饰符只包括public和默认。类不能被protected和private修饰。

类的默认访问修饰符

当不使用访问修饰符修饰一个类时,这个类只能被同一个包中的类所访问。

比如,有类A:

package com.p1;

class A {
    protected void method1() {
    }
}

位于另一个包的类B就无法访问到类A了:

public类

一个.java文件中只能有一个public类,并且该文件的文件名,要和这个public类的类名一致。而在这个.java文件中定义的其他的类只能类的默认访问修饰符(default)修饰。

成员变量和成员方法的访问修饰符

private

如果一个类的方法或者变量被private修饰,那么这个类的方法或者变量只能在该类本身中被访问,在类外以及其他类中都不能显示地进行访问。

protected

如果一个类的方法或者变量被protected修饰,对于同一个包中的类,这个类的方法或变量是可以被访问的。

对于不同包的类,只有继承于该类的类,才可以访问到该类的方法或者变量。

public

被public修饰的方法或者变量,在任何地方都是可见的。

访问控制和继承

请注意以下方法继承的规则:

  • 父类中声明为 public 的方法,在子类中重写后也必须为 public。
  • 父类中声明为 protected 的方法,在子类中重写后,要么声明为 protected,要么声明为 public,不能声明为 private。
  • 父类中声明为 private 的方法,不能够被继承。

Reference