Java的clone机制及其重要的可变类与不可变类要义
2008-05-03 17:20
309 查看
当方法中传递的参数是基本数据类型时,采用的是值传递;当输入参数是对象时,采用的是引用传递。这是“影子克隆(shallow clone)”。如果想要按值传递参数,该类就要实现cloneable接口,并实现clone方法,将“对象名.clone()”做参数传递(deep clone)。
Object 类有 clone() 方法: protected native Object clone() throws CloneNotSupportedException;
该方法是 protected 的,显然是留待被子类 override 的。该方法又是 native 的,必然做了与具体平台相关的底层工作。
事实上,类 Object 的 clone() 方法首先会检查 this.getClass() 是否实现了 Cloneable 接口。 Cloneable 只是一个标志接口而已,用来标志该类是否有克隆功能。
public interface Cloneable {
}
如果 this.getClass() 没有实现 Cloneable 接口, clone() 就会抛 CloneNotSupportedException 返回。否则就会创建一个类型为 this.getClass() 的对象 other ,并将 this 各 field 的值赋值给 other 的对应 field ,若是基本数据类型及非可变类类型的field则是按值,若可变类类型则按引用赋值,然后返回 other 。
所谓不可变类,是指当创建了这个类的实例后,就不允许修改它的属性值。 它包括:
primitive变量: boolean,byte, char, double ,float, integer, long, short
jdk的不可变类:jdk的java.lang包中 Boolean, Byte, Character, Double, Float, Integer, Long, Short, String
可变类,是当你获得这个类的一个实例引用时,你可以改变这个实例的内容。 可变类对象间用“=”赋值,则会是使两个对象实际上会引用同一个实例。所以,只有实现深度clone才能使可变类对象的修改不影响原始对象的值。然而,对于不可变类,可变类的特性也是很有意义的,有的时候我们不希望重复创建相同的内容的实例。因此,我们也可以利用不可变类获得实例缓存。如:
Integer a=Integer.valueOf(10);
Integer b= Integer.valueOf(10);
则只会在第一次创建取值为10的Integer对象。也就是说a和b指向同一处内存上的内容。
那应该如何创建一个自己的不可变类:
·所有成员都是private
·不提供对成员的改变方法,例如:setXXXX
·确保所有的方法不会被重载。手段有两种:使用final Class(强不可变类),或者将所有类方法加上final(弱不可变类)。
·如果某一个类成员不是原始变量(primitive)或者不可变类,必须通过在成员初始化(in)或者get方法(out)时通过深度clone方法,来确保类的不可变。
反言之,任何提供了外部可修改途径的自定义类都是可变类。因而,只有实现深度clone才能使可变类对象按值赋给另一个对象,而不是按引用。例如,在自定义的类 A 中,假设用户声明一个不可变类 B 的field,并提供了可修改 B 值的途径。显然,A便因此成为一个可变类,尽管它包括有不可变类的字段,或者根本没有可变类的字段。
参考:
孙卫琴,《JAVA面向对象编程》,2006年版
Roger Tu,《Java Clone机制》,2007年3月,http://www.blogjava.net/RogerTwain
冠林,《可变类和不可变类(Mutable and Immutable Objects)》,2007年9月http://hi.baidu.com/%D5%C5%B9%DA%C1%D6/blog/item/f0aaa8af98eaafcf7cd92ab3.html
Object 类有 clone() 方法: protected native Object clone() throws CloneNotSupportedException;
该方法是 protected 的,显然是留待被子类 override 的。该方法又是 native 的,必然做了与具体平台相关的底层工作。
事实上,类 Object 的 clone() 方法首先会检查 this.getClass() 是否实现了 Cloneable 接口。 Cloneable 只是一个标志接口而已,用来标志该类是否有克隆功能。
public interface Cloneable {
}
如果 this.getClass() 没有实现 Cloneable 接口, clone() 就会抛 CloneNotSupportedException 返回。否则就会创建一个类型为 this.getClass() 的对象 other ,并将 this 各 field 的值赋值给 other 的对应 field ,若是基本数据类型及非可变类类型的field则是按值,若可变类类型则按引用赋值,然后返回 other 。
所谓不可变类,是指当创建了这个类的实例后,就不允许修改它的属性值。 它包括:
primitive变量: boolean,byte, char, double ,float, integer, long, short
jdk的不可变类:jdk的java.lang包中 Boolean, Byte, Character, Double, Float, Integer, Long, Short, String
可变类,是当你获得这个类的一个实例引用时,你可以改变这个实例的内容。 可变类对象间用“=”赋值,则会是使两个对象实际上会引用同一个实例。所以,只有实现深度clone才能使可变类对象的修改不影响原始对象的值。然而,对于不可变类,可变类的特性也是很有意义的,有的时候我们不希望重复创建相同的内容的实例。因此,我们也可以利用不可变类获得实例缓存。如:
Integer a=Integer.valueOf(10);
Integer b= Integer.valueOf(10);
则只会在第一次创建取值为10的Integer对象。也就是说a和b指向同一处内存上的内容。
那应该如何创建一个自己的不可变类:
·所有成员都是private
·不提供对成员的改变方法,例如:setXXXX
·确保所有的方法不会被重载。手段有两种:使用final Class(强不可变类),或者将所有类方法加上final(弱不可变类)。
·如果某一个类成员不是原始变量(primitive)或者不可变类,必须通过在成员初始化(in)或者get方法(out)时通过深度clone方法,来确保类的不可变。
反言之,任何提供了外部可修改途径的自定义类都是可变类。因而,只有实现深度clone才能使可变类对象按值赋给另一个对象,而不是按引用。例如,在自定义的类 A 中,假设用户声明一个不可变类 B 的field,并提供了可修改 B 值的途径。显然,A便因此成为一个可变类,尽管它包括有不可变类的字段,或者根本没有可变类的字段。
参考:
孙卫琴,《JAVA面向对象编程》,2006年版
Roger Tu,《Java Clone机制》,2007年3月,http://www.blogjava.net/RogerTwain
冠林,《可变类和不可变类(Mutable and Immutable Objects)》,2007年9月http://hi.baidu.com/%D5%C5%B9%DA%C1%D6/blog/item/f0aaa8af98eaafcf7cd92ab3.html
相关文章推荐
- Java的clone机制及其可变类与不可变类
- 内功修炼(八)---java---反射机制(重要)
- Java中的克隆(Clone)机制
- Java中的可变类和不可变类
- Java细节与规范:ArrayList为何建议赋予默认值及其扩容机制
- android binder机制及其源码解析 之第二节重要函数讲解之常用数据结构(一)
- java中equals和==之间的区别?clone方法的作用,及其为什么要使用clone方法?如何使用clone复制对象?以及深克隆浅克隆
- java回调机制及其实现
- Java中的克隆(Clone)机制
- JAVA程序的类加载及其反射机制
- Java clone机制
- Java中的克隆(Clone)机制
- Java基础:泛型及其擦除性、不可协变性
- Java基础:JAVA程序类加载及其反射机制
- Finally in Java 及其机制的讨论
- JAVA 注解机制及其原理
- 【Java基础】JAVA不可变类(immutable)机制与String的不可变性
- java clone()机制
- Java中的String的 方法归类 及其 不可变性
- Object.clone()方法引申出的浅克隆、深克隆、java原型模式的实现、不可变类的实现