用代码详解Java访问控制修饰符
Java访问控制符是一个很基础的内容,网上介绍的文章也很多,但是许多都讲的不清楚,给我造成了很大的困惑,于是我决定自己写一篇博客,并结合代码,针对default与protected这两个比较难理解的访问控制修饰符做一个比较清楚的介绍。
前言
先让我们来看一张图:
这是关于访问权限介绍的一张很经典的图,但是,这张图中的描述有很多令我疑惑的地方。比如,关于default的描述,为什么同包可以,而子类却不行呢?
由于有许多困惑,而网上搜到的博客又大多不能完全解释我的疑惑,所以我决定通过自己编写代码来真正的理解这些访问控制修饰符。
public&private
首先,关于这两个修饰符,我觉得还是很好理解的:
public 无论在哪都可以访问,而 private 则是只能在本类中访问。在这篇博客中就不做过多的阐述了。
default
从表中可以看出,default的访问权限为:当前类及同包可以,但子类和其他包不行。这里的关键在于:这里的子类代表的是位于其他包下的子类! 如果通过字面意思简单的理解为子类,那就会造成许多困扰了。。。
下面,我们通过代码来一探究竟。
首先,我们在pk1下的类A中定义一个变量value,并且不用任何修饰符,即default:
接下来,我们在同一个包下新建一个类A的子类A1并尝试去访问value:
可以到看,是可以访问到的。
然后,同样在pk1下,我们新建一个普通的类Main,并尝试去访问类A的value:
也没有问题,可以访问到。
再然后,我们在另一个包pk2下新建一个类A的子类A2并尝试去访问value:
报错了,访问失败!
最后,我们在包pk2下新建一个普通的类,并尝试去访问value:
同样,也是标红报错,访问失败!
综上,我们在理解default时,其实不必纠结于子类不子类的问题,只要记住,如果使用了default,只有位于同一个包内才有访问权限,而位于其他包中的类,都是没有访问权限的!
protected
这个修饰符我觉得是四个修饰符中最难理解的一个,因为他有许多“奇妙”的表现,让我借助代码来详细剖析。
首先,我简单修改了一下上一部分用到的基类A,将value改为private并且新增一个protected的方法getValue():
接下来,在A1中尝试去访问getValue()方法:
没有问题,访问成功!
然后,在pk1.Main类中尝试去访问getValue()方法:
同样也是没有问题,访问成功!
再然后,奇妙的地方出现了,我们在pk2下A的子类A2中用两种方法尝试去访问getValue()方法:
方法1失败而方法2成功。
最后,在pk2下一个普通的类Main中同样用两种方法尝试去访问getValue()方法:
方法1与方法2都失败了!!都!!!失败了。
由于protected的访问权限比default宽,所以在同一个包下的访问没有问题,这一点并不出乎我们的意料。
奇妙就奇妙在pk2.A2类和pk2.Main类中发生的情况的对比。
在类A2中,我用A的实例去访问getValue(),是不允许的,但是,用A2的实例去访问getValue()(即方法2.直接调用getValue()),是允许的。
在类pk2.Main中,我同样使用了A2中的两种方法,方法1失败了意料之中,但是方法2居然也失败了!这给我造成了很大的困惑,我查阅了很多资料,终于找到了合理的解释:
对于protected修饰符,在同一个包下,其实就等同于default,访问是完全允许的。但是,当在其他包中时,无论什么类,都是不允许通过声明这个protected方法的实例(在本文中,即为A的实例a)来访问这个方法的。而对于不同包下的子类(在本文中,即A2),在没有重写与重载某个protected方法的前提下,只能在本类中访问这个protected方法(因为继承,所以A2其实隐式的继承了这个protected方法),而出了这个类,这个隐式继承来的protected方法又会变得不可见(在本类中,即对应着pk2.Main),所以,pk2.Main中的方法2也就失败了。
那肯定就有人有疑问了,A2不是继承了这个protected方法吗?为什么pk2.Main会没有访问权限呢?不是与A2位于同一个包嘛?这是因为,当protected出了自己所在的包时,它的含义就变为了“仅对子类可见”(这样才体现了 protected嘛),所以,只有在子类中(A2)才有权限访问这个protected方法!
那么我非要在pk2.Main中通过A2来访问getValue()方法可以吗?当然可以!只需要在A2中显式的重写一下这个protected方法就好啦,修改后的代码如下:
方法2成功访问!撒花~~~~