zoukankan      html  css  js  c++  java
  • Java中protected语义解释

    在一权威的java教材中提到“protected" 修饰的方法和属性对于包外的子类是可见的,其实这个表达有些不够严密,导致很多人产生歧义。经过论坛讨论和大量的程序测试,对“protected"语义的探究逐渐明晰。现总结如下:  (1)除了在(2)中表述的有关继承方面的区别之外,在某个类中定义的protected 方法和属性(注意是定义的,不是继承而来的,对于继承而来的情况在(2)中有表述)和默认权限方法和属性是一样的。比如,某类的protected 方法和属性在包外是不能通过该类对象进行访问的(你能在包外访问一个类的默认权限的方法和属性吗?当然不能),这就是为什么在某对象所在的包的以外的任何 地方,你不可以通过该类的对象引用来调用它的protected 方法和属性,哪怕是在该类的子类中也不可以这样做。在该类包外的子类中能“看到“的只是子类自己继承来的protected 方法和属性,它是不能“看到“它的父类对象的protected方法和属性的。 (2)protected 修饰的方法和属性和默认权限方法和属性的区别在于:在包外的子类可以继承protected 方法和属性,而且被继承的protected 方法和属性,在子类中仍然是protected(如果方法没有被override),但是要注意的是,我这里说它们仍然是protected,是从它们可 以由该子类的包外的子类继续继承的递归性角度来说的,实际上它们的可见范围和该子类中新定义的protected 方法和属性是有区别的 。不同之处在于在该子类中新定义的protected 方法和属性对该子类所在的包是可见的。而从父类中继承的protected 方法和属性在该子类所在的包中仅仅对该子类是可见的,同时另外它们还享有被继承前的可见范围(即被被继承前的可见范围仍然保持。这让人想起oop中的一个 原则,方法和属性被继承后,其可见的范围只能扩大,不能缩小)。比如某类中定义某个protected方法,那么在该类所在的包中是可以访问该类的包外的 子类的通过继承得到的该protected方法的(尽管该子类是在包外)。同时不可以在该类(代号A)的包外定义的某个类B中调用类A的子类SA的继承该 类得到的该protected 方法(类B可以是A子类也可以不是A子类,类SA可以是在任何一个包中,但是B和SA是不同的两个类)。 (3)对于构造函数,protected修饰词带给它的语义本质上和带给其他方法的是一样的。但因为构造函数相 比一般的方法有特别之处,所以protected语义在具体体现上也会有些不同。比如构造函数不存在继承的问题,但是构造函数有一个隐含或显式 super()调用的问题。如果您对protected语义有了本质的认识,您一定能想到,你在包外的任何地方你都不能用new的方式直接调用某类的 protected构造函数,但是在该类的包外的子类的构造函数中,是可以隐含地调用前者的protected构造函数的,也可以显式的通过 super()调用(这个不难理解,就像他的其他protected方法可以用super.的方式来调用一样)。另外提醒下,构造函数从来都不是继承得来 的,构造函数的可见性和父类的构造函数的可见性没有什么必然联系。 (4)综述之,protected的确切语义是:protected修饰的方法或变量将会被任何位置的子类继承,但是永远只能被最早定义他的父类所在的包的类所见(除了该类以及其子类能看到本身的该protected方法或变量之外。)

    代码:

    package com.protecteds.test;

    import com.protecteds.test2.Duck1;

    public class Bird {
    protected int nFeathers;

    public void name(){
    Duck1 d=new Duck1();
    d.nFeathers=0;
    }
    }

    1.

    package com.protecteds.test2;

    import com.protecteds.test.Bird;

    public class Duck1 extends Bird{
    public void setn(int duck1n){
    //在子类中直接访问父类中的protected变量
    nFeathers=duck1n;
    }
    }


    2.

    package com.protecteds.test2;

    import com.protecteds.test.Bird;

    public class Duck2 extends Bird{

      public void construct(int newduck2){
    Duck2 d2 = new Duck2();
    //在子类中通过子类的对象访问父类中的protected变量
    d2.nFeathers=newduck2;
    }
    }

    3.

    package com.protecteds.test2;

    import com.protecteds.test.Bird;

    public class Duck3 extends Bird {

     public void construct(int newduck3) {
    Bird b = new Bird();
    // 子类中用父类对象反而不能访问父类中的protected变量
    //b.nFeathers = newduck3;
    }
    }

    4.

    package com.protecteds.test2;

    import com.protecteds.test.Bird;

    public class Duck4 extends Bird{

      public void construct(int newduck4){
    Duck1 d1 = new Duck1();
    //子类中用另外一个子类的对象也不能访问父类中的protected变量
    //d1.nFeathers=newduck4;
    }
    }

    5.

    package com.protecteds.test2;

    import com.protecteds.test.Bird;

    public class Duck5 extends Duck2{

      public void construct(int f){
    Duck2 d1 = new Duck2();
    //不同包继承来之后就算protected也只有自己可以访问

        //d1.nFeathers=f;
    }
    }

  • 相关阅读:
    【2021 ECUG Con】聚势而来,与你相约花开时
    为 Nginx 添加 HTTP 基本认证(HTTP Basic Authentication)
    centos6 yum 源失效 404
    [nsis]安装包反编译
    Web安全测试学习笔记-DVWA-盲注(使用sqlmap)
    Shellcodeloader免杀过火绒
    C#创建快捷方式-转载自ConExpress
    C#运行新线程,也可打开网页
    C#判断指定文件是否存在-转载mmgx(仅为方便找一下)
    C# 文件夹创建方法
  • 原文地址:https://www.cnblogs.com/danghuijian/p/4400196.html
Copyright © 2011-2022 走看看