浅克隆:需要类实现Cloneable,并重写clone()方法
一般在重写clone()方法时,将返回值类型强转为自己类,避免每次克隆之后需要强转
- public class Test {
- public static void main(String[] args) throws CloneNotSupportedException {
- A a1=new A();
- A a2 = a1.clone();
-
- //克隆之后 a1和a2是两个不同对象 内容相同
- System.out.println(a1==a2);//false
- //true 注意这里也是true 如果a1和a2是new出来的 这里肯定是false
- System.out.println(a1.getC()==a2.getC());//true
- //注意 这里并非常量池里取,而是指向同一个对象 再把对象放入常量池
- System.out.println(a1.getE()==a2.getE());//true
- System.out.println(a1);//A{a=1, b=2, c='3', d=D{name='1'}, e='4'}
- System.out.println(a2);//A{a=1, b=2, c='3', d=D{name='1'}, e='4'}
- System.out.println("--------------------------------------");
-
- //浅克隆之后,对String类型和8种基本类型(包装类)的改变不会影响另外一个对象的属性内容
- a1.setA(5);
- a1.setB(6);
- a1.setC("7");
- a1.setE("8");
- System.out.println(a1);//A{a=5, b=6, c='7', d=D{name='1'}, e='8'}
- System.out.println(a2);//A{a=1, b=2, c='3', d=D{name='1'}, e='4'}
- System.out.println("--------------------------------------");
-
- //但是浅克隆对自定义类型的成员变量的改变,会影响另外一个对象 说明自定义对象在a1和a2中的引用地址指向了同一个对象
- a1.getD().setName("改了");
- System.out.println(a1);//A{a=5, b=6, c='7', d=D{name='改了'}, e='8'}
- System.out.println(a2);//A{a=1, b=2, c='3', d=D{name='改了'}, e='4'}
- a2.getD().setName("又改了");
- System.out.println(a1);//A{a=5, b=6, c='7', d=D{name='又改了'}, e='8'}
- System.out.println(a2);//A{a=1, b=2, c='3', d=D{name='又改了'}, e='4'}
-
- }
-
- }
- class A implements Cloneable{
- int a=1;
- Integer b=2;
- String c=new String("3");
- D d=new D();
- String e="4";
-
- @Override
- public String toString() {
- return "A{" +
- "a=" + a +
- ", b=" + b +
- ", c='" + c + '\'' +
- ", d=" + d +
- ", e='" + e + '\'' +
- '}';
- }
- public D getD() {
- return d;
- }
- public void setD(D d) {
- this.d = d;
- }
- public String getE() {
- return e;
- }
- public void setE(String e) {
- this.e = e;
- }
- public int getA() {
- return a;
- }
- public void setA(int a) {
- this.a = a;
- }
- public Integer getB() {
- return b;
- }
- public void setB(Integer b) {
- this.b = b;
- }
- public String getC() {
- return c;
- }
- public void setC(String c) {
- this.c = c;
- }
- @Override
- protected A clone() throws CloneNotSupportedException {
- return (A)super.clone();
- }
- }
- class D{
- String name="1";
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- @Override
- public String toString() {
- return "D{" +
- "name='" + name + '\'' +
- '}';
- }
- }
画张图表示

如果两个对象是NEW的
- public class Test1 {
-
- public static void main(String[] args) {
- E e1=new E();
- E e2=new E();
-
- System.out.println(e1.str1==e2.str1);//true
- System.out.println(e1.str2==e2.str2);//false
-
- System.out.println(e1.i1==e2.i1);//true
- System.out.println(e1.i2==e2.i2);//false
- System.out.println(e1.i3==e2.i3);//true
-
- }
- }
- class E{
- String str1="123";//常量池里取 没有就new 然后放入常量池
-
- String str2=new String("123");//new必定创建新对象
-
- Integer i1=1;//常量池里取 没有就new 然后放入常量池
-
- Integer i2=new Integer(1);//new必定创建新对象
-
- Integer i3=Integer.valueOf(1);//常量池里取 没有就new 然后放入常量池
-
- }
下面是深克隆的一种写法
让自定义类也实现克隆,并重写clone方法

然后在对象类的克隆方法改写成下面

这样再运行上面代码, D就是不同的对象了,克隆之后,无论谁改变d的属性,都只影响自己
以集成工具默认重写equals和hashcode不影响执行结果
深克隆还有其他写法