zoukankan      html  css  js  c++  java
  • 详解Java中的访问控制修饰符(public, protected, default, private)

    Java中的访问控制修饰符已经困惑笔者多时,其中较复杂的情况一直不能理解透彻。今天下定决心,系统、全面地研究Java中的访问控制修饰符的所有方面,并整理成这篇文章,希望有同样疑惑的读者读完后能有所收获。如果文章中出现错误,欢迎评论指出,共同交流~

    说在前面:这篇文章只研究Java中访问控制修饰符声明类的变量/方法的情况。

    先抛出结论:

    * 成员变量/方法的访问权限 

    ①:子类可以继承,但是不能访问父类的成员变量/方法(一般来说,可以访问就可以继承)。

    ②:有继承关系说明访问对象所在的类是父类。

    1. 让我们来看一下Java中访问控制修饰符的定义。

    Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。

    访问的形式有以下四种:

    · 某个类的成员变量访问某个类的成员变量

    · 某个类的成员变量访问某个类的成员方法

    · 某个类的成员方法访问某个类的成员变量

    · 某个类的成员方法访问某个类的成员方法

    ps:以下代码均以第三种形式为例,其他形式基本一致。

    根据访问对象的不同,访问的方式又可划分为两大类:

    · 访问对象在同一个类,此时可以通过[成员变量/方法的名字]直接访问。

    class A {
        int a = 10;
    
        void printA() {
            System.out.println(a);
        }
    }
    

    printA()要访问a,因为它们在同一个类,所以可以通过a直接访问。

    · 访问对象在不同类(假设访问对象在类B),此时可以通过声明、初始化B的一个对象,通过[对象名.成员变量/方法的名字]进行访问。

    ps:这种情况仅限于成员方法访问成员变量/方法。

    class A {
        void printB() {
            B ob = new B();
            System.out.println(ob.b);
        }
    }
    
    class B {
        int b = 10;
    }
    

    A中的printB()要访问B中的b,因为它们不在同一个类,所以可以在printB()中声明、初始化B的一个对象ob,通过ob.b进行访问。

    此外,当访问对象为静态变量/方法时,可以通过[访问对象所在类的类名.成员变量/方法的名字]进行访问。

    class A {
        static int a = 10;
    
        int doubleA = A.a * 2;
    
        void printB() {
            System.out.println(B.b);
        }
    }
    
    class B {
        static int b = 10;
    }
    

    doubleA要访问a,由于a为静态变量,因此可以通过A.a进行访问。

    A中的printB()要访问B中的b,由于b为静态变量,因此可以通过B.b进行访问。

    2.结论中提到了包,我们来看一下Java中包的定义和作用。

    为了更好地组织类,Java提供了包机制,用于区别类名的命名空间。

    包的作用

    • 1 把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。
    • 2 如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。
    • 3 包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。

    Java使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口、枚举(enumerations)和注释(annotation)等。

    关于包的使用方法,请参考Java教程 包(package),在此不详细赘述。

    值得注意的是,import关键字引入的是class文件,而非java文件。

    3.结论中还提到了继承,我们来看一下Java中继承的定义。

    继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。继承可以理解为一个对象从另一个对象获取属性的过程。

    关于继承的细节,请参照Java教程 继承,在此不详细赘述。

    需要理解的是,子类继承父类的成员变量/方法时,是先访问再继承。因此上面访问权限的规则同样适用于继承。

    在同一个包里,如果父类的某个成员变量/方法可以被访问,则该成员变量/方法可以被继承。即如果在子类成员方法中,声明、初始化父类的一个对象后,可以通过[对象名.成员变量/方法a]访问a,则声明、初始化子类的一个对象后,也一定可以通过[对象名.成员变量/方法a]访问a。

    class A extends B {
      void printB() {
        B ob = new B();
        System.out.println(ob.b);
        A ob2 = new A();
        System.out.println(ob2.b);
      }
    }
    
    class B {
        int b = 10;
    }
    

    A继承B,因此A继承B的成员变量b。由于A在printB()中,声明、初始化B的一个对象ob后,可以通过ob.b访问b,则声明、初始化A的一个对象ob2后,可能通过ob2.b访问b。(可以访问则可以继承)。

    然而,在不同包里,子类继承父类时,子类只能访问父类的public型成员变量/方法,却能继承父类的protected和public型成员变量/方法。(请看下面的例子)

    值得注意的是,子类继承父类的成员变量/方法,并不意味着这些成员变量/方法存在于子类,因此不能通过[成员变量/方法的名字]直接访问。可以理解为继承而来的成员变量/方法进入了子类的异次元(雾)。

    当然,如果继承而来的成员变量/方法被重写,这些成员变量/方法就存在于子类了,此时可以通过[成员变量/方法的名字]直接访问。

    此处不讨论多态的情况,请参照Java教程 多态

     回到结论,让我们来一层层地验证Java中的访问控制修饰符。

    /* Stark.java */
    
    package winter.is.coming;
    
    public class Stark {
        private boolean ned;
        boolean robb;
        protected boolean sansa;
        public boolean arya;
    
        void howIsNed() {
            System.out.println(ned);
        }
    }
    
    class Snow {
        void whoseBastard() {
            Stark stark = new Stark();
            // System.out.println(stark.ned); 不可访问
            System.out.println(stark.robb);
        }
    }
    
    /* Greyjoy.java */
    
    import winter.is.coming.Stark;
    
    public class Greyjoy extends Stark {
        void betray() {
    
            Stark stark = new Stark();
            // System.out.println(stark.robb); 不可访问
            // System.out.println(stark.sansa); 不可访问
    
            Greyjoy greyjoy = new Greyjoy();
            // System.out.println(greyjoy.robb); 不可访问
            System.out.println(greyjoy.sansa);
    
        }
    }
    
    /* Bolton.java */
    
    import winter.is.coming.Stark;
    
    public class Bolton {
        void flay() {
            Stark stark = new Stark();
            System.out.println(stark.arya);
        }
    }
    

    ① 自己包自己类 -- private可访问

    Stark中的howIsNed()可以访问Stark中private型的ned。

    ② 自己包别的类 -- default可访问

    Snow中的whoseBastard()可以访问Stark中default型的robb,不可以访问Stark中private型的ned。

    ③ 别的包别的类有继承关系 -- protected可继承,不可访问

    Greyjoy中的betray()可以继承Stark中protected型的sansa,不可以访问Stark中protected型的sansa,也不可以继承和访问Stark中default型的robb。

    ④ 别的包别的类无继承关系 -- public可访问

    Bolton中的flay()可以访问Stark中public型的arya。

    转载于:https://www.cnblogs.com/sunyubin/p/9683860.html

  • 相关阅读:
    Android视频播放软解与硬解的区别
    Android ViewPager嵌套ViewPager滑动冲突处理方法
    2.2 Consumer API官网剖析(博主推荐)
    2.1 Producer API官网剖析(博主推荐)
    2. APIS官网剖析(博主推荐)
    1.5 Upgrading From Previous Versions官网剖析(博主推荐)
    1.4 Ecosystem官网剖析(博主推荐)
    1.3 Quick Start中 Step 8: Use Kafka Streams to process data官网剖析(博主推荐)
    1.3 Quick Start中 Step 7: Use Kafka Connect to import/export data官网剖析(博主推荐)
    1.3 Quick Start中 Step 6: Setting up a multi-broker cluster官网剖析(博主推荐)
  • 原文地址:https://www.cnblogs.com/twodog/p/12135907.html
Copyright © 2011-2022 走看看