一、阐述问题
我在用clone()进行对象的复制时,我们知道,调用的是Object类里面的clone()方法进行的,但是clone()是protected修饰的,而当我用已有的对protected的认识去代码时,发现事实并不是我认为的那样。
二、问题代码
1.这是父类(clones)的代码,位于test2包中
package test2;
public class clones {
protected void cloned() {
System.out.println("cloned");
}
}
2.这是子类(Student、teacher)的代码,位于test1包内
package test1;
import test2.clones; //这里记得导入
public class Student extends clones
{
private String name;
private String age;
public Student(String n,String a)
{
this.name=n;
this.age=a;
}
public static void main(String[] args)
{
Student s=new Student("lzc", "13");
s.cloned(); //访问成功
teacher t=new teacher();
t.cloned(); //访问失败
}
}
class teacher extends clones{
public void c() {
}
}
以上的父类与子类位于不同的包内,两个子类(Student、teacher)位于同一个包中,我们在Student类里面去实例化两个子类对象并且尝试调用父类的protected修饰的cloned()方法。结果是Student的对象可以调用成功,而teacher的对象则调用失败。
三、原因分析
1、protected的访问规则是:同一个包中的所有类以及不同包中的子类可以访问。我们刚才的问题就是出在 “不同包中的子类可以访问” ;我们要注意了,这句话是有限制的,比如:我在Student类的方法里面,那我只能Student s=new Student(“lzc”,“13”); 这个对象s才能访问父类clones里面的cloned()。也就是你在哪个子类里面,你的实例化对象必须就是对应这个子类的,别的是不行的。
2、有一句话是专门来描述这种情况的:“ 对于protected的成员或方法,要分子类和超类是否在同一个包中。与基类不在同一个包中的子类,只能访问自身从基类继承而来的受保护成员,而不能访问基类实例本身的受保护成员 ” 。老实的讲,我看不懂这句话,很多博文里面都有这句话,他们也没有详细讲讲这句话啥意思,比如什么是 “基类实例本身的受保护成员 ” 。我觉得对这句话的理解可以是我前面第一点所理解的那样的。
四、使用clone()过程中,出现如上所描述的问题
1.我先把我是如何调用clone()的代码给出来,大家要耐住性子,我的代码的都是很短的,名字也都是取的特别容易短。
package test1;
public class Student{
/*
* Student与teacher都是Object类的子类,它们与Object不在同一个包里面,当我们想在Student里面
* 实例化对象,并且用这个对象调用父类的protected修饰的clone()时,只有Student类的对象调用成功了,
* 这和我们在上面举出的那个例子不是一样的吗。
*/
public static void main(String[] args)
{
teacher t=new teacher("lzc", "13");
teacher copy=null;
copy=(teacher)t.clone(); //这里报错了:The method clone() from the type Object is not visible。意思是teacher类的对象t不可访问Object类里面的clone()
Student s=new Student();
Student copy2=null;
copy2=(Student) s.clone(); //编译成功
}
}
class teacher {
private String name;
private String age;
public teacher(String n,String a)
{
this.name=n;
this.age=a;
}
}
我们来回顾一下我在第二大点所举出的问题代码,以此来对比是否相同
1、首先是位于test2包的父类:clones
package test2;
public class clones {
protected void cloned() {
System.out.println("cloned");
}
}
2、然后是位于test1包的两个子类:Student、teacher
package test1;
import test2.clones; //这里记得导入
public class Student extends clones{
private String name;
private String age;
public Student(String n,String a)
{
this.name=n;
this.age=a;
}
public static void main(String[] args)
{
Student s=new Student("lzc", "13");
s.cloned(); //访问成功
teacher t=new teacher();
t.cloned(); //访问失败
}
}
class teacher extends clones{
public void c() {
}
}
3、大家仔细看看代码,然后再琢磨一下这句话:“ 对于protected修饰的成员或方法,要分子类和父类是否在同一个包中。与父类不在同一个包中的子类,只能访问自身从父类继承而来的受保护成员,而不能访问父类实例本身的受保护成员 ” 。其实这句话就是想说:要在所在类里面写与该类相同类型的实例化语句,获取所在类的对象。用这个对象去调用父类的protected方法才是可行的。
五、那么正确的clone()调用方法该是怎么样的?
我直接给出代码,在代码里面总结,请耐住性子,别着急,多看几遍。
package test1;
/*
* clone的实现格式:
* 1.在A类中实现Cloneable接口并重写clone();
* 2.在B类中实例化A的类对象,并且对A类对象进行复制;
*/
class Body implements Cloneable
{
public Head head;
public int a;
public Body() {}
public Body(Head head,int a) {this.head = head;this.a=a;}
@Override
protected Object clone() throws CloneNotSupportedException {
//这里是深克隆,深克隆、浅克隆的区别后续文章会介绍。
Body newbody=(Body)super.clone(); //执行了这句话(Body)super.clone()以后,body对象的副本在堆内存里面已经复制好一个份了,然后再把它的地址发布给外部引用变量
newbody.head=(Head)head.clone(); //将引用变量的对象复制一份,返回新复制的对象的地址。
return super.clone();
}
}
class Student
{
public void main(Strings[] args)
{
Body b=new Body(new Head(),3);
Body copy=b.clone(); //调用Body里面重写的方法。
}
}
六、总结:
总结就是:看清楚你在哪个类里面,那么你实例化语句的对应类型也要是对应的这个类。比如在Student类里面,那么就是Student s=new Student(“lzc”,“18”); 还有看完这篇文章的同学,如果有疑问或者不同观点,大家评论区见哦~