深刻理解 Java 中 protected 修饰符

看似简单的东西能够引出不少问题,学习过程当中不少概念咱们都只是「好像了解」、「貌似是这样」、「应该没问题」, 其实缺少的是仔细思考, 对本身少问了几个「为何」。java

在 Java 中, 访问权限修饰符属于最最基础的知识, protected 修饰符只是其中一个, 若是你要问为何不拿 public、default、private 来深究呢? 那么看完这篇文章你会知道为什么 protected 更值得深刻️思考。bash

在 《Thinking in Java》 中,protected 的名称是「继承访问权限」,这也就是咱们记忆中的 protected:protected 必需要有继承关系才可以访问。 因此你觉得你懂了, 但是你真的理解了这句话吗?学习

先思考几个问题:spa

  1. 同一个包中, 子类对象能访问父类的 protected 方法吗?code

  2. 不一样包下, 在子类中建立该子类对象能访问父类的 protected 方法吗?对象

  3. 不一样包下, 在子类中建立父类对象能访问父类的 protected 方法吗?继承

  4. 不一样包下, 在子类中建立另外一个子类的对象能访问公共父类的 protected 方法吗?get

  5. 父类 protected 方法加上 static 修饰符又会如何呢?编译器

《Thinking in Java》中有一句话:「protected 也提供包访问权限, 也就是说,相同包内的其余类能够访问 protected元素」, 其实就是 protected 修饰符包含了 default 默认修饰符的权限, 因此第 1 个问题你已经知道答案了, 在同一个包中, 普通类或者子类均可以访问基类的 protected 方法。string

父类为非静态 protected 修饰类

package com.protectedaccess.parentpackage;

public class Parent {

    protected String protect = "protect field";

    protected void getMessage(){
        System.out.println("i am parent");
    }
}复制代码

不一样包下,在子类中经过父类引用不能够访问其 protected 方法

不管是建立 Parent 对象仍是经过多态建立 Son1 对象, 只要 Parent 引用, 则不可访问, 编译器会提示错误。

package com.protectedaccess.parentpackage.sonpackage1;

import com.protectedaccess.parentpackage.Parent;

public class Son1 extends Parent{
    public static void main(String[] args) {
        Parent parent1 = new Parent();
        // parent1.getMessage(); 错误

        Parent parent2 = new Son1();
        // parent2.getMessage(); 错误
    }
}复制代码

不一样包下,在子类中经过该子类引用能够访问其 protected 方法

子类中实际上把父类的方法继承下来了, 能够经过该子类对象访问, 也能够在子类方法中直接访问, 还能够经过 super 关键字调用父类中的该方法。

package com.protectedaccess.parentpackage.sonpackage1;

import com.protectedaccess.parentpackage.Parent;

public class Son1 extends Parent{
    public static void main(String[] args) {
        Son1 son1 = new Son1();
        son1.getMessage(); // 输出:i am parent,
    }
    private void message(){
        getMessage();  // 若是子类重写了该方法, 则输出重写方法中的内容
        super.getMessage(); // 输出父类该方法中的内容
    }
}复制代码

不一样包下,在子类中不能经过另外一个子类引用访问共同基类的 protected 方法

package com.protectedaccess.parentpackage.sonpackage2;

import com.protectedaccess.parentpackage.Parent;

public class Son2 extends Parent {

}复制代码

注意是 Son2 是另外一个子类, 在 Son1 中建立 Son2 的对象是没法访问父类的 protected 方法的

package com.protectedaccess.parentpackage.sonpackage1;

import com.protectedaccess.parentpackage.Parent;
import com.protectedaccess.parentpackage.sonpackage2.Son2;

public class Son1 extends Parent{
    public static void main(String[] args) {
        Son2 son2 = new Son2();
        // son2.getMessage(); 错误
    }
}复制代码

父类为静态 protected 修饰类

对于protected的静态变量, 在子类中能够直接访问, 在不一样包的非子类中则不可访问

package com.protectedaccess.parentpackage;

public class Parent {

    protected String protect = "protect field";

    protected static void getMessage(){
        System.out.println("i am parent");
    }
}复制代码

静态方法直接经过类名访问

不管是否同一个包,在子类中都可直接访问

package com.protectedaccess.parentpackage.sonpackage1;

import com.protectedaccess.parentpackage.Parent;

public class Son3 extends Parent{
    public static void main(String[] args) {
        Parent.getMessage(); // 输出: i am parent
    }
}复制代码

在不一样包下,非子类不可访问

package com.protectedaccess.parentpackage.sonpackage1;

import com.protectedaccess.parentpackage.Parent;

public class Son4{
    public static void main(String[] args) {
       // Parent.getMessage(); 错误
    }
}复制代码

看到这里你应该知道有多少种状况了, 针对不一样的状况均可能出现意外的结果, 因此仍是得多实践, 仅仅在书上看一遍 protected 修饰符的做用是没法真正发现它的微妙。

相关文章
相关标签/搜索