从clone()谈protected

看到Object的clone()是protected的,然后看到《java2认证考试指南》上描述:一个对象只能请求其他对象的克隆,后者的类与被克隆对象属于同一类,或是被克隆对象的子类。

example:   C-->B-->A <--D

C对象能克隆B或A对象;B对象能克隆A对象;D对象能克隆A对象

B对象不能克隆D对象

 

我是读了很久没有理解,最后读了一些程序才发现这样理解:主要是visibility问题。因为是protected的,那么在子类不重载,则自动继承。子类和父类在不同package时,子类实例可以调用它自己的protected foo(), 但在子类的code中调用父类实例的protected foo(),则看不见。 //子类中用父类对象反而不能访问父类中的protected变量  

之所以没能理解,原因居然是国内的很多Java书籍在介绍访问权限时,一般都这样描述:

 

  public protected default private
同类 T T T T
同包 T T T  
子类(不同包) T T    
无继承关系不同包的类 T      

所以我们想当然的认为,B继承A,在不同包,那么在B的code中用A的实例a调用a.clone()是可以的,但是,事实上:不行(但b.clone显然可以)

这里给出《java in a nutshell》中的一段话:【让我理解了真正的protected-你不能在B中调用A的protected方法,你可以调用自己继承于A的那个protected方法】
protected access requires a little more elaboration. Suppose class A declares a protected field x and is extended by a class B, which is defined in a different package (this last point is important). Class B inherits the protected field x, and its code can access that field in the current instance of B or in any other instances of B that the code can refer to. This does not mean, however, that the code of class B can start reading the protected fields of arbitrary instances of A! If an object is an instance of A but is not an instance of B, its fields are obviously not inherited by B, and the code of class B cannot read them.
如果一个对象o是Object实例,但不是B的实例,在B的code中不能看到o.clone,就因为它是protected字段或方法(因此需要public)
因此上面表格第三行显然没有细化protected,它说可以访问应该是指可以使用super.funProtected()或自己实例的funProtected()

代码如下:

package test;

public class Tree{
    protected int age;
    
    void sayTree(){
        Maple mm=new Maple();
        mm.clone();//compile ok, mm is instance of Maple, also instance of Tree
    }
}

class Maple extends Tree{
    public void sayMaple(){
        Maple m=new Maple();
        m.age=0;
        
        Tree t=new Tree();
        t.age=0; //ok, same pack can access protected field
        
        m.clone();//compile ok, can access Maple's protected fun
        t.clone();//error, t is instance of Tree, but not instance of Maple!-----------见上文黑色粗体字
    }
}


package test.a;

import test.*;
class Pine extends Tree{
    public void say(){
        Pine p=new Pine();
        p.age=0;
        p.clone();
        
        Tree t=new Tree();
        t.age=0;                  // invisible
        t.clone();                // invisible
    }
}

 

posted @ 2015-10-15 17:03  jack-xu  阅读(421)  评论(0编辑  收藏  举报