protected 域(或方法)微妙的规则
protected
域(或方法)对本包内的所有类可见(当然包括子类),那么,子类可以获得访超类受保护域(或方法)的权利,但是,若子类和超类不在同一个包下,就不能访问超类对象的这个受保护域(或方法)。也就是说,不在一个包下,子类中不能通过一个父类对象的引用来获得父类受保护的域(或方法),测试如下。
package protect2;public class P{ protected int a; public P(){} public P(int a){ this.a = a; } protected void fun(){ System.out.println("父类protected方法"); }}
package protect2;public class ProtectedTest { public String s; public ProtectedTest(String s) { this.s = s; } P ap = new P(10); void foo() { ap.fun(); System.out.println("ap.a " + ap.a); } public static void main(String[] args) { ProtectedTest test = new ProtectedTest("abcdef"); test.foo(); System.out.println(test.s); }}
package protect;import protect2.P;class C extends P{ public int b; public C(int a,int b){ super(a); this.b = b; } public void afun(){ P pp = new P(10); System.out.println("C.a= " + a); System.out.println("P.a= " + pp.a);//ERROR:The field P.a is not visible pp.fun(); //ERROR:The method fun() from the type P is not visible }
浅拷贝与深拷贝
Object类对自己的具体子类的域一无所知,Object
类的clone
方法只是将各个域进行拷贝。数值或基本类型不会出现问题,但是,如果在对象中包含了引用对象,这些对象的内容没有被自我复制,拷贝的结果也即是原始对象和拷贝对象引用着同一个引用对象(一般地,动词“引用”可理解为“管理”,就是指向同一内存)。
浅拷贝满足:
x.clone() != x
为true
,x.clone().getClass() == x.getClass()
为true
,((x.clone().field1 ) == (x. field1))&& … &&((x.clone().fieldN )==(x. fieldN))
也为true
。
如果原始对象与浅拷贝对象共同引用(管理、指向)的引用对象是不可变的,将不会产生任何问题,如,引用对象是String类对象;或引用对象在其生命周期不会发生变化,具体来说,管理它的类中没有更改它的方法,也没有返回对它引用的方法(分享其管理权的方法)。
如果原始对象管理的引用对象是可变的,就必须需重新定义clone
方法,来实现深层次的拷贝。要对涉及的每一个类,判断以下两点:
- 默认的clone方法是否满足需求。
- 默认的clone方法是否能通过调用可变引用对象的clone方法得到解决。
对涉及的每一个类,深拷贝要满足:
x.clone() != x
为true
,x.clone().getClass() == x.getClass()
为true
,x.clone().equals(x)
也为true
,当然。
Object
类中的clone
方法被声明为protected
,防止出现文章开头所提到的,子类和超类不在同一个包下的情况,要声明clone
为public
,来实现深拷贝:
import java.util.Date;public class EqualsT { public static void main(String[] args) throws CloneNotSupportedException { Date hireDay = new Date(); Employee e1 = new Employee("Tommy", 10, "9998", hireDay); Employee e2 = new Employee("Tommy", 10, "9998", hireDay); System.out.println(e1.equals(e2)); System.out.println(e1 == e2); Employee e3 = (Employee) e1.clone(); System.out.println(e1.equals(e3)); }}//Cloneable为标记接口,接口内没有方法。class Employee implements Cloneable { String name; int age; String salary; Date hireDay; public Employee(String name, int age, String salary, Date hireDay) { super(); this.name = name; this.age = age; this.salary = salary; this.hireDay = hireDay; } @Override public boolean equals(Object otherObject) { if (this == otherObject) return true; if (otherObject == null) return false; if (!(otherObject instanceof Employee)) return false; Employee other = (Employee) otherObject; return name.equals(other.name) && age == other.age && salary.equals(other.salary) && hireDay.equals(other.hireDay); } @Override protected Object clone() throws CloneNotSupportedException { // call Object.clone() Employee cloned = (Employee) super.clone(); // call mutable fields cloned.hireDay = (Date) hireDay.clone(); return cloned; }}Output:truefalsetrue
// JDK中Date类的克隆方法public Object clone() { Date d = null; try { d = (Date)super.clone(); if (cdate != null) { d.cdate = (BaseCalendar.Date) cdate.clone(); } } catch (CloneNotSupportedException e) {} // Won't happen return d; }
——@guoyangde http://www.cnblogs.com/LittleTreasureBox/p/8904016.html