Java基础知识详解: protected修饰符

@author: Tobin
Java初学者,试图用最简单的大白话让自己搞懂一些知识点。

修饰符modifiers介绍

学习Java不可避免地接触到一些基本的修饰符。
修饰符决定了类成员的访问权限,是否能够被其它类所访问。

  • private: 只能被基类访问
  • 无修饰符: 被基类,子类和同package的类访问
  • protected: 在无修饰符的基础上,加了与基类不同包,但是是子类的访问权限,这个访问权限只在子类访问自身的实例时才有,超类的实例还是不能访问的
  • public: 全都可以访问

下面这个很好地展现了权限的逐层增加。

protected修饰符详解

《Java编程思想》对protected的介绍是:被protected修饰的成员对于本包和其子类可见。看了上面的图,我们知道子类可见的意思是不同包的子类也是可见的。总结一下就是:

  • 基类的protected成员是包内可见的
  • 当不在同一个包,但是是其子类也是可以访问protected的成员的。但是有个前提,就是子类只能访问其继承来的protected成员,如果是在子类中初始化一个超类的实例,这个实例是无法访问protected的成员的。
    概念比较抽象,用形象的语言来说。
    包就相当于一个家族。不同包有可能有继承的分支,也有可能毫无关系。类内的成员就相当于资源。
  • private: 私有资源,只能自己使用
  • default: 家族,我自己,我子孙可以用
  • protected: 我可以开放,但是只给自己家族的但是嫁到或者入赘其它家族的后代使用
  • public: 谁都可以用,水资源

参考几个例子,分析下。
(1)示例1

//示例一
package p1;
public class Father1 {
    protected void f() {} // 父类Father1中的protected方法
}

package p1;
public class Son1 extends Father1 {}

package p11;
public class Son11 extends Father1{}

package p1;
public class Test1 {
    public static void main(String[] args) {
        Son1 son1 = new Son1();
        son1.f(); // Compile OK ----(1)
        son1.clone(); // Compile Error ----(2)

        Son11 son = new Son11();    
        son11.f(); // Compile OK ----(3)
        son11.clone(); // Compile Error ----(4)
    }
}
  • f方法是超类Father1的,son1和son11虽然是定义不同的包,但是它们的都是Father1的子类,所以都可以访问f方法。此外Test1也在p1包里,所以1和3编译通过。
  • son1和son11的clone()方法都是来自于Father1,但是和f的区别在于,Father的clone()还来自于java.lang.Object,Test1也是Object的子类,这只是说明它可以访问自己继承的clone()方法,即使其它分支继承了相同的方法,它也是不可以访问的。想象一下,家族给其它分支都分配一些资源,即使是相同的,我也不该有权限去访问其它分支的资源。

(2)示例2

//示例二
package p2;
class MyObject2 {
    protected Object clone() throws CloneNotSupportedException{
       return super.clone();
    }
}

package p22;
public class Test2 extends MyObject2 {
    public static void main(String args[]) {
       MyObject2 obj = new MyObject2();
       obj.clone(); // Compile Error ----(1)

       Test2 tobj = new Test2();
       tobj.clone(); // Complie OK ----(2)
    }
}
  • Test2继承了MyObject2,clone()方法来源于MyObject2,Test2可以建立自身实例,然后访问clone()方法,2通过
  • 但是作为子类,Test2建立超类实例,直接去访问超类的protected方法是不可以的
  • 想一下,家族已经给我分支资源了,我还要直接向家族拿资源,不该有这个权限
    (3)示例3
//示例三
package p3;
class MyObject3 extends Test3 {
}

package p33;
public class Test3 {
  public static void main(String args[]) {
    MyObject3 obj = new MyObject3();
    obj.clone(); // Compile OK ------(1)
  }
}
  • MyObject3继承Test3,两个不在一个包内。Test3作为超类,建立了子类的一个实例,访问子类继承的来自于它的方法,当然它的clone()方法,也是继承自java.lang.Object,这个不管,继承自我的,我是有权限访问的
  • 想象一下,家族给分支资源了,家族是有权限直接访问我给出的资源的

(4)示例4

//示例四
package p4;
class MyObject4 extends Test4 {
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
}

package p44;
public class Test4 {
  public static void main(String args[]) {
    MyObject4 obj = new MyObject4();
    obj.clone(); // Compile Error -----(1)
  }
}
  • 和示例3的区别在于,此时的clone()方法是子类自身的方法了,来源于MyObject4本身,作为超类是没有权限访问子类的protected成员的
  • 想象一下,分支建立自己的受保护资源,家族没有权限直接访问的
    (5)示例5
//示例五
package p5;

class MyObject5 {
    protected Object clone() throws CloneNotSupportedException{
       return super.clone();
    }
}
public class Test5 {
    public static void main(String[] args) throws CloneNotSupportedException {
       MyObject5 obj = new MyObject5();
       obj.clone(); // Compile OK ----(1)
    }
}
  • 现在属于同一个包,Test5可以直接访问Myobject5的protected成员
  • 想象一下,同一个家族的资源共享
    (6)示例6
//示例六
package p6;

class MyObject6 extends Test6{}
public class Test6 {
  public static void main(String[] args) {
    MyObject6 obj = new MyObject6();
    obj.clone(); // Compile OK -------(1)
  }
}
  • 即使不在同一个包,1也成立。此处在同一个包,且clone()方法来自于Test6
  • 同一个家族的资源共享
    (7)示例7
//示例七
package p7;

class MyObject7 extends Test7 {
    public static void main(String[] args) {
        Test7 test = new Test7();
        test.clone(); // Compile Error ----- (1)
  }
}

public class Test7 {}
  • 超类Test7的方法来自于java.lang.Object,只有java.lang这个包和对应继承了这个clone()方法的Test7才能访问。说白了,方法还是一个方法,但是被不同的子类继承了,就不再是同样的方法了。
  • 看起来是一个家族的,实际上资源是超类从其它家族得到的。其它家族对该资源做了限制,所以不能整个家族都能使用。其次,子类只能访问自身实例的protected资源,没有权限访问超类实例的protected资源。两个条件都不满足。

其它修饰符

static
final
abstract
见我Java基础知识系列的其它文章。

总结

protected成员,在相同package下,对其它类开放,不同package下,对继承了该类的子类开放(有条件)。其它包的子类没有权限直接创建超类的实例,然后访问超类的protected成员。除了认清楚protected属性,更重要的是要辨别来源,来源决定package是哪个,这是决定访问权限的基础。

参考文章
https://blog.csdn.net/ciawow/article/details/8262609。
https://blog.csdn.net/justloveyou_/article/details/61672133

posted @ 2019-10-19 22:22  我的小叮当  阅读(7989)  评论(0编辑  收藏  举报