`

protected,你真的理解了吗?

    博客分类:
  • Java
阅读更多

Java中的访问控制修饰符有四个级别,但属protected最复杂。如果问大家,protected修饰符作用,大家会说“在子类与同包中可以访问这个成员”,当然在自己类中也是可的,但你真的理解了吗?不信,先看看下面这些实例,看你是否也是这样想的(其中注释掉的是不能编译的,大家最好把这些代码放在eclipse中再看,不然你会晕的^_^):

package pk1.a;
public class Base {
	protected int i = 1;
	protected void protect() {
		System.out.println("Base::protect");
	}
}

package pk1.a;
import pk1.b.Sub;
public class SubSub extends Sub {
	void g() {
		Sub s = new SubSub();
		//!! s.protect();//规则2.c.i
		System.out.println(s.i);//规则2.c.ii
	}
}

package pk1.b;
import pk1.a.Base;
public class Sub extends Base {
	private void prt() {}
	protected void protect() {
		System.out.println("Base::protect");
	}
	void f() {
		//规则2.a
		this.protect();
		this.i = 2;

		//规则2.b
		Base a2 = new Sub();
		//!! a2.protect();
		//!! System.out.println(a2.i);

		//规则1
		Sub b = new Sub();
		b.protect();
		b.i = 1;
		b.prt();
	}
}

package pk1.b;
public class SubSub extends Sub {
	void g() {
		Sub s = new SubSub();
		s.protect();//规则2.c.i
		//!! System.out.println(s.i);//规则2.c.ii
	}
}

package pk1.c;
import pk1.a.Base;
import pk1.b.Sub;
public class SubSub extends Sub {
	void g() {
		this.protect();//规则2.a

		//规则2.b
		Base b = new SubSub();
		//!! b.protect();
		//!! System.out.println(b.i);

		//规则2.b
		Sub s = new SubSub();
		//!! s.protect();
		//!! System.out.println(s.i);

	}
}

 

package pk2.a;
public class Base {
	protected int i = 1;

	protected void protect() {
		System.out.println("Base::protect");
	}
}

package pk2.a;
import pk2.b.Sub;
public class Other {
	void g() {
		//规则3.a
		Base b = new Sub();
		b.protect();
		System.out.println(b.i);

		//规则3.b.ii
		Sub s = new Sub();
		s.protect();
		System.out.println(s.i);
	}
}

package pk2.b;
import pk2.a.Base;
public class Other {
	void g() {
		//规则3.a
		Base b = new Sub();
		//!! b.protect();
		//!! System.out.println(b.i);

		//规则3.b.ii
		Sub s = new Sub();
		//!! s.protect();
		//!! System.out.println(s.i);
	}
}

package pk2.b;
import pk2.a.Base;
public class Sub extends Base {}

 

package pk3.a;
import pk3.b.Sub;
public class Base {
	protected int i = 1;
	protected void protect() {
		System.out.println("Base::protect");
	}
	
	static protected int i_s = 1;
	static protected void protect_s() {
		System.out.println("Static:Base::protect");
	}
	
	void f() {
		//!! Sub.i_s = 2; //规则3.b.i
		Sub.protect_s();//规则3.b.ii
	}
}

package pk3.a;
import pk3.b.Sub;
public class Other {
	void g() {
		Sub s = new Sub();
		//!! s.protect();//规则3.b.i
		System.out.println(s.i);//规则3.b.ii
	}

	void f() {

		//!! Sub.i_s = 2; //规则3.b.i
		Sub.protect_s();//规则3.b.ii

		Base.i_s = 2;//规则3.a
		Base.protect_s();//规则3.a

	}
}

package pk3.b;
import pk3.a.Base;
public class Other {
	void f() {
		Sub.i_s = 2;//规则3.b.i
		//!! Sub.protect1();//规则3.b.ii
		
		//!! Base.i1 = 2;//规则3.a
		//!! Base.protect1();//规则3.a
	}
}

package pk3.b;
import pk3.a.Base;
public class Sub extends Base {
	protected void protect() {
		System.out.println("Base::protect");
	}
	static protected int i_s = 2;

	void f() {
		
		/*
		 * 在子类中可能通过子类类型或父类类型来来访问父类中protected静态
		 * 成员,而不管子类与父类是否在同一包中,或是子类重新定义了这些成员
		 * 
		 * 注,在父类或子类中访问时后面的规则不再适用
		 */
		System.out.println(Sub.i_s);//2
		Sub.protect_s();
	
		System.out.println(Base.i_s);//1
		Base.protect_s();
	}
}

 

如果你看到这里,想法与程序一致的话,说明你理解了,如果不理解,那看看我的理解吧:

 

定义规则前,我这里约定有三个类,一个是Base类,一个是Base类的子类Sub类,一个是Sub类的子类SubSub类,另一个是Other类且与BaseSubSubSub没有继承关系,并假设Base中有protected方法与属性,都叫YYY吧。

 

在理解protected规则:首先要搞清楚什么叫访问?这里在讲到的访问是有二种的:

一、就是在类中通过“XXX x = new XXX(); x.YYY;”的形式来访问(不妨叫此种形式为“外部访问”吧,此种访问形式除了可以应用到自己与子类中外,还可以应用在其他类中访问,其中XXX表示定义的类型,这里可为BaseSubSubSubYYY为方法或属性);

二、就是this.YYY的形式来访问(不妨叫此种形式为“内部访问”吧,不过这种访问形式只能应用在在自己的类或是子类中)。

 

protected方法与属性可访问的地方有三个:

1.         在自己的类Base中:上面的“XXX x = new XXX(); x.YYY;”与“this.YYY”两种访问形式都可以访问的到自己定义的portected方法或属性;

2.         二是子类SubSubSub中,这要分三种访问方式:

        a.         SubSubSub 中的“this.YYY”内部访问形式:在此种方式形式下,不管是否重写或重新定义过父类Baseprotected方法与属性,子类SubSubSub一定可以访问的。

        b.         SubSubSub 中“Base x = new XXX (); x.YYY;”外部访问形式:此种形式就不一定的能访问的到了,这要看父类Base与子类SubSubSub是否在同一包(注意,此时与是否重写或重新定义过这些protedted方法与属性没有关系);

        c.         SubSub 中“Sub x = new XXX (); x.YYY; 外部访问形式:此种访问形式能否访问关键看Sub是否重写或重新定义过Base的属性与方法:

                      i.              如果重写或重新定义过,则看SubSubSub是否在同包中

                      ii.             如果没有,则看BaseSubSub是否在同包中

3.         在其他类Other中:此时只支持外部访问形式,不过到底是要求OtherBase同包还是要求OtherSub同包,则要依你访问方式而定了:

        a.         如果是通过父类引用“Base x = new XXX (); x.YYY;”形式来访问的,则要求OtherBase同包;

        b.         如果是通过子类引用“Sub x = new Sub (); x.YYY;”形式来访问的,情况又会比较复杂了,此时关键是看子类Sub是否重写或重新定义过父类Base中的protected方法与属性:

                      i.              如果重写或重新定义过了,则要求OtherSub同包即可;

                      ii.             如果没有重写或重新定义过了,则要求OtherBase同包即可;

 

 

另外,写到这里我想到了Object中的clone方法,为什么要求具有克隆能力的类要求实现Cloneable接口与clone方法呢:Object.clone()访问修饰符为protected,如果某个类没有重写此方法,则Object中的clone()方法除被自己与子类能调用方法外,其他不管与这个类在同一包还是不同包都是不可见的,因为未重写,还是属于Object中的方法,又Objectjava.lang包中,与我们定义的包又不在java.lang包中,所以不能访问到(这也与你在在程序里定义了Object o = new Object();你还是不能在当前类中调用o.clone();一样),这也恰好符合上面 3.b.ii 这条规则。所以如果要能被不同包中的非子类克隆,则需重写Object.clone()并设置访问权限为public(如果重写后还是protected,则还是只能被同一包访问)。

 

以上这些就是我对protected限制的一种理解,肯定还有遗漏的地方,希望大家给我指出来,我来完善它。如果对你有帮助,请支持一下!

 

刚刚发现的一个小问题,一并附上《protected,这个错了吗?》

 

非常感谢大家,看了一下大家的理解,我上面的理解确实比较复杂,这正是因为把继承访问与非继承访问混在一起了就复杂了。其实这么理解就最简单了,还是以那句话,protected修饰的成员只允许子类与包访问!只不过子类可访问是指继承访问,即在子类的实例中直接访问继承过来的protected成员,而不是在子类中通过创建父类实例的方式来访问;而包访问就是指通过“XXX x = new XXX(); x.YYY;”的方式来访问,即通过实例的引用来访问,能不能访问就是看访问的代码所在的类是否与类XXX 在同一包中。但包访问要注意一点的是:如果XXX中只是继承了父类中的protected成员,而没有重写(方法)或重新定义(属性)这些成员,则能不能访问就要看当前访问的代码所在的类是否与类XXX的父类在同一包;另外如果类XXX重写与重新定义过这些protected成员,则就直接看访问代码所在的类与类XXX是否在同一包即可。

最后要注意的是静态的受保护成员比较特殊,因为protected static 成员即使被子类重写(严格的讲不叫重写)或重新定义后,还是会被继承下来,即在子类会有两份这样的static protected成员,只是他们的所属域(类)不同而已,所以在子类中可以通过父类的类型来访问所属于父的这些成员而不管子类与否与父类在同一包中,这与非静态的是不一样的。

 

 补充:方法能重写,属性能重写吗

分享到:
评论
14 楼 mercyblitz 2011-01-10  
LZ,你的文章不错,不过简单的问题复杂化了。

对于编译器而言,它是不能区分多态的。因此在编译时,通过申明类型来决定是否可以访问。


这样理解是科学+简单地!

编译时和运行时理解了,就不纠结了!
13 楼 hzwq 2011-01-09  
Java 的protected 和 C#的不同
Java 的protected包含了所有的default特性。
我的理解是 protected只是给与父类不同package的子类一个通过super.xxx()访问父类的方式
12 楼 sswh 2011-01-08  
ximenpiaohua 写道
一个这么简单的问题,被你整的……%&
无聊


+1
11 楼 vividemon 2011-01-08  
我觉得是好文章,今天看那个core java的时候,想到了,没解决。我细读一下
10 楼 ximenpiaohua 2010-05-11  
一个这么简单的问题,被你整的……%&
无聊
9 楼 spyker 2010-05-11  
这个关键字 我觉得都可以去掉...
8 楼 yssas 2010-05-11  
<div class="quote_title">junJZ_2008 写道</div>
<div class="quote_div">
<div class="quote_title">yssas 写道</div>
<div class="quote_div">protected本没有这么复杂,楼主把这个搞复杂了<br>有一个简单的办法——你把所有new换成一个工厂方法,这样:<br>      XXX x=Factory.createXXX();<br>就可以很直观很明显地看出了。<br>ps:示例代码有错,请lz详查……</div>
<br><br>哪儿有错?请指示。</div>
<p><br>是我的结论轻率了,细看之后,发现至少原来认为有错的第一段代码是没有错误的。不过我想总结一个关于字段访问控制的假象算法:</p>
<p> </p>
<p>字段没有动态绑定且基于隐藏机制。访问字段时,自目标对象对象所声明的类型开始,沿继承体系向上,直到相应字段的定义位置,然后检查访问者权限</p>
<p> </p>
<p>对于方法的访问,直接视其声明类型就行了。根据Liskov替换原则,子类不可能降低父类的访问设置,这也就是我提出将new换成工厂方法的原因。</p>
<p> </p>
7 楼 junJZ_2008 2010-05-10  
eroscxl 写道
看完代码。。我发现我理解了。。
看完文字。。我发现我晕了,,,麻烦下次举例的时候来个正常字。。。
XXX YYY 然后我 zzz~ 了

嗯,提的好,不过知道如何修改,还请指示
6 楼 junJZ_2008 2010-05-10  
yssas 写道
protected本没有这么复杂,楼主把这个搞复杂了
有一个简单的办法——你把所有new换成一个工厂方法,这样:
      XXX x=Factory.createXXX();
就可以很直观很明显地看出了。
ps:示例代码有错,请lz详查……


哪儿有错?请指示。
5 楼 yssas 2010-05-10  
protected本没有这么复杂,楼主把这个搞复杂了
有一个简单的办法——你把所有new换成一个工厂方法,这样:
      XXX x=Factory.createXXX();
就可以很直观很明显地看出了。
ps:示例代码有错,请lz详查……
4 楼 eroscxl 2010-05-10  
看完代码。。我发现我理解了。。
看完文字。。我发现我晕了,,,麻烦下次举例的时候来个正常字。。。
XXX YYY 然后我 zzz~ 了
3 楼 ipconfiger 2010-05-10  
折腾,继续折腾
2 楼 whaosoft 2010-05-10  
lz说的不错 至于 "Object.clone()访问修饰符为protected," 我想人家可能就是想叫你把内个方法重写了吧
1 楼 段箭*残箫 2010-05-09  
想不到protected这么复杂,楼主真是细心

相关推荐

    java中protected的权限

    `protected`是Java中四种访问权限之一,它在类的封装和继承中扮演着重要的角色。本篇文章将深入探讨`protected`关键字的含义、用法以及它在实际开发中的应用。 1. `protected`的含义: `protected`是一种中级访问...

    public_protected_private用法详解

    综上所述,理解并合理使用`public`、`protected`和`private`对于编写清晰、安全且易于维护的代码至关重要。掌握这些访问修饰符的用法可以帮助开发者更好地设计类的结构,实现面向对象编程的原则。在实际开发中,应...

    Protected Mode Software Architecture.rar

    通过阅读《Protected Mode Software Architecture》这本书,读者可以全面理解保护模式的原理,学习如何设计和实现高效、安全的软件架构,这对于开发操作系统、驱动程序或者进行系统级编程是必不可少的基础知识。

    Protected Storage PassView(找出电脑账号密码).rar

    而PassView则是一个由 NirSoft 开发的小巧实用工具,它能够帮助用户查看并提取Protected Storage中的密码信息。 Protected Storage PassView的主要功能有以下几点: 1. **密码恢复**:当用户忘记了保存在浏览器、...

    JEDEC JESD260:2021 Replay Protected Monotonic Counter (RPMC) for

    《JEDEC JESD260:2021 Replay Protected Monotonic Counter (RPMC) for Serial Flash Devices》这份文档详细介绍了RPMC(重放保护单调计数器)技术在串行闪存设备中的应用。RPMC是一种重要的安全机制,主要用于防止...

    Protected Management Frames Interoperability Test Plan v1 4.pdf

    《Wi-Fi CERTIFIED Protected Management Frame System Interoperability Test Plan》版本1.4是Wi-Fi Alliance发布的一份关于802.11w协议认证的重要文档。802.11w,也称为Management Frame Protection (MFP),是Wi-...

    基于Java protected的深入理解

    在这个深入理解中,我们将详细探讨`protected`关键字的含义、用法以及其在多态和继承中的行为。 首先,`protected`关键字的基本概念是它比默认(包级私有)权限更开放,但比`public`权限更受限。与`public`不同,`...

    查看本地密码Protected Storage PassView

    描述中的“Protected Storage PassViewHA_PSPV1.63_LRH.rar”指的是该工具的特定版本,即版本号为1.63,由LRH发布的汉化版(HA表示汉化,LRH可能是汉化者的标识)。RAR是一种常见的压缩文件格式,用于打包多个文件或...

    JAVA 访问修饰符 及 protected 几点被人忽略的致命要害

    ### JAVA 访问修饰符及 protected 的几点被人忽略的致命要害 #### 一、概述 在 Java 中,访问控制修饰符用于...希望本文能够帮助您更好地理解和应用 `protected` 访问修饰符,从而写出更加健壮和优雅的 Java 代码。

    Wi-Fi Protected Access 数据加密和数据完整性

    Wi-Fi Protected Access(WPA)是无线网络领域中一种重要的安全标准,旨在提供更好的加密机制和数据完整性,保护用户在无线局域网(WLAN)中的通信安全。本篇文章将深入探讨WPA的工作原理、加密技术和数据完整性机制...

    Wi-Fi Protected Setup Specification 1.0h

    在理解和实施WPS时,还需要参考以下相关文档: - **WPA规范**:定义了Wi-Fi网络的安全框架。 - **IEEE 802.11标准**:规定了无线局域网的技术细节。 - **其他Wi-Fi Alliance文档**:包括认证指南和其他技术建议。 #...

    WPS协议 WiFi_Protected_Setup.pdf

    WPS(Wi-Fi Protected Setup)是一种设计用于简化Wi-Fi设备安全设置流程的标准。它旨在简化WPA(Wi-Fi ...通过深入学习WPS协议的这些知识点,可以更好地理解和应用这一标准,以确保无线网络的便捷接入与安全性。

    用java代码来解析private、public、default、protected的权限问题

    理解这些访问修饰符对于编写健壮且安全的Java代码至关重要。正确使用它们可以帮助我们设计出具有良好封装性和扩展性的类结构。在实际开发中,根据需求选择合适的访问权限,可以有效防止不必要的数据暴露,提高代码的...

    Protected Interoperable File Format (PIFF) 1.1

    知识点: 1. Protected Interoperable File Format(PIFF)的定义和重要性 PIFF(Protected Interoperable File Format...理解这些内容对于开发兼容PIFF的设备或软件、或在遵守专利政策的前提下实现PIFF格式至关重要。

    Java类protected继承链访问控制机制研究.pdf

    通过创建不同包内的类和子类,并观察它们如何访问`protected`成员,可以直观地理解访问控制的规则。例如,可以创建一个父类`A`,其中包含一个`protected`变量`x`,然后在不同的包内创建子类`B`和`C`,观察它们能否...

    易被忽视的protected方法跨包继承问题.pdf

    在这个特定的讨论中,焦点集中在`protected`关键字和默认(default)访问控制修饰符上,特别是在跨包继承的情景下。 `protected`访问修饰符允许子类和同一个包内的类访问其成员。然而,这里有两个关键点经常被忽视...

    protected_ncverilog.rar_DRAM_ddr4_ddr4模型_ncverilog_silkei2

    总的来说,"protected_ncverilog.rar_DRAM_ddr4_ddr4模型_ncverilog_silkei2"提供的资源是DDR4 DRAM设计和验证的一个宝贵工具,利用NCVerilog仿真器,用户可以深入研究DDR4内存系统的功能和行为,为硬件设计和系统级...

Global site tag (gtag.js) - Google Analytics