以前一直认为自己理解了Java四种权限访问,昨天突然编程时发现protected居然在子类中不能调用,然后越看越迷糊??????
public: Java语言中访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包(package)访问。
private: Java语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”。被其修饰的类、属性以及方法只能被该类的对象访问,其子类不能访问,同包之间不能访问,更不能允许跨包访问。
protect: 介于public 和 default之间的一种访问修饰符,一般称之为“保护形”。被其修饰的类属性以及方法只能被类本身的方法及子类访问,即使子类在不同的包中也可以访问。
default:即不加任何访问修饰符,通常称为“默认访问模式“。该模式下,只允许在同一个包中进行访问。
对于上面这种描述,不能说有错,但是很容易引起人误解。
先陈清一点:对于类的修饰,只能是public或者不写。
下面先看例子:
1 package lesson1209; 2 3 public class Base { 4 5 public int publicInt; 6 protected int protectedInt; 7 int defaultInt; 8 9 void defaultget(){ 10 System.out.println(); 11 } 12 13 protected void protectedget(){ 14 15 } 16 17 } 18 19 20 package lesson1210; 21 22 import lesson1209.Base; 23 24 public class TestNotSub { 25 26 public static void main(String[] args) { 27 Base b = new Base(); 28 b.publicInt = 3; 29 30 TestSub sub = new TestSub(); 31 sub.publicInt = 0; 32 /*在不是一个包的情况之下:子类的引用在子类中可以调用父类的Protected方法或属性, 33 非子类的话只能调用public方法或属性*/ 34 //sub.protectedInt = 3; //不可见 35 //sub.defaultInt = 2; //不可见 36 //sub.protectedget(); //不可见 37 //sub.defaultget(); //不可见 38 } 39 40 } 41 42 package lesson1210; 43 44 import lesson1209.Base; 45 46 public class TestSub extends Base{ 47 48 public static void main(String[] args) { 49 TestSub sub = new TestSub(); 50 sub.protectedInt = 3; //子类可以访问protected,不可以访问default 51 //sub.defaultInt = 2; //不可见 52 sub.protectedget(); 53 //sub.defaultget(); 54 55 Base base = new Base(); 56 base.publicInt = 0; 57 //base.protectedInt = 3; //不可见 这个地方尤其注意了,为什么不可见,理解protected含义 58 //由此可见,只能在子类中子类自己访问,其他的都访问不了。59 60 }
public void protectedkn(){
publicInt = 0; //子类可以直接访问父类中的protected对象
protectedInt = 2;
//defaultInt = 3; //不可见
} 61 62 }
在不是一个包的情况之下: 子类的引用在子类中可以调用父类的Protected方法或属性,非子类的话只能调用public方法或属性。
并且只有子类在子类中才可以调用,其他地方都调用不了。 如果有问题,请指正。
若子类与基类不在同一包中,那么在子类中,子类实例可以访问其从基类继承而来的protected方法,而不能访问基类实例的protected方法。
一般网上的误解或疑惑是:“为什么子类中不能访问另一个包中父类中的protected方法?” 参考博客原贴:https://blog.csdn.net/dawn_after_dark/article/details/74453915
其实这个问题问法是错的,在子类中是可以访问另一个包中父类中的protected方法,能问出这样的问题,多半是在不同包的子类中创建了父类对象,通过父类对象去调用protected方法,结果发现编译不通过,所以才会萌生这样的疑问。
一般我们问这个这个问题呢,其实是没有明白protected权限到底controll了什么,都知道protected修饰的成员变量和方法可以被包外的子类访问到,这里被包外子类访问实质并不是可以在子类中通过创建父类对象来访问这个protected方法, 而是可以通过创建子类对象来访问的。这也可以说是protected权限对包外访问时的一种限制,在包内则可以像public那样可以在任意地方访问。
产生这个问题的主要是我们把在包内访问的方式理解强加到了包外。其实我们又可以转换问题为什么跨包访问某个类的protected方法必须通过继承呢?答案很简单,通过继承呢,子类就可以获得了父类方法的地址信息并把这些信息保存到自己的方法区,这样就可以通过子类对象访问自己的方法区从而间接的访问父类的方法(重写的话,就直接访问子类自己重写后的方法)。
Testsub确实继承了Base,但只是通过继承产生了自己能访问的方法表包括父类的保护区域(实例方法),并无权限访问父类对象的方法表中保护区域,就是只能通过Testsub自己的对象去访问自己的方法表中保护区域来调用已继承的方法,Testsub是无权限查看Base方法表中保护区域信息,更别说用通过Base对象调用了。这里也就很好的解释了为什么继承的子类看不到private方法,和为什么包外无法访问父类的default方法,因为编译器规定不能继承过来,所以子类的方法表不存在这些修饰符修饰的方法,更别谈调用了。
类B继承了类A,包括保护型方法区域,所以能通过B对象来调用这个区域访问该方法。在类B是无法查看对象A的保护型方法区域,是因为类B并没有继承对象A的保护型方法区域,类B只是继承了类A的保护型方法区域。(这个地方需要好好理解)
总结:
1. 子类可以通过继承获得不同包父类的protected权限成员变量和成员方法,在子类中可以直接访问
2. 在子类中可以通过子类的对象访问父类的protected成员变量和方法
3. 在子类中反而不能通过父类的对象访问父类的protected成员变量和方法
4. 在子类中不能通过其他子类的对象访问父类的protected成员变量和方法
5. 在与子类同包的其他类中不能通过子类的对象访问父类的protected成员变量和方法
参考原文:https://blog.csdn.net/blacktal/article/details/81198579
这儿还有一篇文章写得也是很清楚,并且例子非常简单清晰,你看后会耳目一新:
https://www.cnblogs.com/liuleicode/p/4946248.html