不可变类(immutable class)
来源:互联网 发布:c语言的函数 编辑:程序博客网 时间:2024/04/29 02:41
不可变类,顾名思义就是说类的实例是不可被修改的。实例的信息是在创建的时候提供,并且在整个生命周期中都不可改变。
大家都知道Java的String类是immutable。其实primary的包装类都是immutable的。那么如果让你设计和immutable的class要怎么做呢?
immutable 也就是不变的意思。不可改变的。怎么样让一个类的对象不变呢?
第一你肯定想到,这个类不能被继承,于是class 前面要加 final。这是最直接的办法,也是最简单的办法,但是当你将来想对它扩展的时候就做不到了。也许你想在他的基础上定义一个子类也是immutable的。这时候你可以不再class 前面加final,而是在所有的方法上加final,同样可以防止子类重写它的方法。其实不用继承一样可以扩展这个类,通过composite方法。所以不推荐允许继承immutable类。另外,还有一个办法让immutable类不能被继承,那就是将方法私有或者protected也即是保内私有,然后提供一个静态工厂方法来生产实例。这是最推荐的方法,因为这个方法允许包内扩展,对客户类来说是不可继承的。同时静态工厂方法还有许多其他比构造方法好的地方。
第二你也可能会想到属性不能被改变,那field前面也得加final。你还得把属性私有化,防止被直接访问修改。这样就够了吗?那如果有一个其他类的对象的引用属性呢?怎么保证它不被变?
首先你能做到的就是保证自己的方法里面不改变它的值。然后怎么保证别的类不直接改变它呢?这个引用如果是别的对象传给你的呢?怎么保证不变? 同样,如果是方法中要返回这个属性呢?想想看。
如果它也是immutable的自然也就省心了。但如果不是呢?
看来必须得clone一个新的对象了。关于clone,可以参考liuwang126的文章http://liuwang126.iteye.com/blog/272595
下面是完整的Sample。
这可能在一般的开发中不大会用到。可以被看成是一个设计游戏。不过如果我们自己设计API供别人调用,你不得不考虑规则的严谨和你的用意可以准确的表达和限制。
下面对final做个分析。
你有两个原因能够想到用final:design 和 efficiency。 你可以再方法的参数上加上final,保证传入的参数不被改变,这种设计是我们常常推崇的。
你也有两个原因在method前加上final。第一个是保证类的子类不会重写这个方法,这个方法的行为不被改变。这是设计方面的原因。另一个在低版本jdk中利用这点可以提高performance。但是也会有消耗内存的负面影响。在jdk5以后,jvm可以自动改善performance,我们反而不鼓励利用这点来优化性能。应该交给jvm去办。
当你在class前面加上final,说明你不准备也不允许这个类将来被继承。这可能是出于安全或者本身它就不会有子类。这是design方面的原因。final class的方法因为不可能被继承也就被final了,但是属性却没有被final。
和朋友交流了一下,又有了一点新的看法。immutable的本意是想让一个类的对象被创建以后就不要再被修改。有点类似常量。只想让别的程序只读。那就是说不提供写或者修改的方法。只是提供构造函数,一次生成,永不改变。从这个角度上看,也是简化了设计。对于这样的对象,你可以放心的使用,因为你知道他就是你生成时的对象,从来没有也不会被改变。
为什么JDK要设计这么多的immutable的类呢?
因为immutable类比mutable类更加容易设计,实现和使用。而且不易出错,更加安全。
简单:因为对象一旦生成就他的值就固定了,不变了。从对象状态角度上看,它只有一种状态,没有什么状态变化和迁移。相反,对于一个可以变对象,他的状态变化可就多了,你需要有个状态迁移图才能描述清楚他可能的变化,也就是说他的状态空间可能很大。
线程安全:因为没有修改方法,所以你不用考虑同步的问题,在并发环境中也可以放心的并发read。
节省内存:既然不变对象可以自由的共享。你可以让使用者尽量使用已经存在的实例,而不要重复的创建。你可以定义这些类的一些静态的final实例属性,就像定义一个常量一样。
当然你也可以为Immutable 类提供一个静态工厂,由工厂来保证不会创建重复的对象实例。
这样也就节省了内存消耗和垃圾回收负担。如果你有这样的对象,在系统中会被大量的,频繁的,并发的读。不放考虑这种模式。其实String就是一个很好的例子。
很好的构建基石:你应该比较常用到Set和Map,尤其是map的key值,你是否经常需要考虑这些值会不会在你不经意间变了呢?从而使得影响你设定这个set或map的本意。如果用Immutable对象你就不用担心了吧?这样是为什么你总喜欢用String做key值。当然你也可能想尽量避免重写equals和hashCode方法。
不要滥用这种模式
凡是必然是有利有弊。你知道immutable的对象会因为值的不同而生产新的对象,所以你要谨慎设计你的对象和使用方法。比如String,当你在循环里面连接字符串的时候就不建议你用String的+号,而是用BufferString,StringBuffer类用来表示内容可变的字符串,并提供了修改底层字符串的方法。当我们进行字符拼接时,请使用StringBuffer类而非String类,因为前者将比后者快上百倍。这也许也可以知道我们平衡我自己的设计。没准你也可以设计一个immutable类的伙伴(companion)类。
大家都知道Java的String类是immutable。其实primary的包装类都是immutable的。那么如果让你设计和immutable的class要怎么做呢?
immutable 也就是不变的意思。不可改变的。怎么样让一个类的对象不变呢?
第一你肯定想到,这个类不能被继承,于是class 前面要加 final。这是最直接的办法,也是最简单的办法,但是当你将来想对它扩展的时候就做不到了。也许你想在他的基础上定义一个子类也是immutable的。这时候你可以不再class 前面加final,而是在所有的方法上加final,同样可以防止子类重写它的方法。其实不用继承一样可以扩展这个类,通过composite方法。所以不推荐允许继承immutable类。另外,还有一个办法让immutable类不能被继承,那就是将方法私有或者protected也即是保内私有,然后提供一个静态工厂方法来生产实例。这是最推荐的方法,因为这个方法允许包内扩展,对客户类来说是不可继承的。同时静态工厂方法还有许多其他比构造方法好的地方。
第二你也可能会想到属性不能被改变,那field前面也得加final。你还得把属性私有化,防止被直接访问修改。这样就够了吗?那如果有一个其他类的对象的引用属性呢?怎么保证它不被变?
首先你能做到的就是保证自己的方法里面不改变它的值。然后怎么保证别的类不直接改变它呢?这个引用如果是别的对象传给你的呢?怎么保证不变? 同样,如果是方法中要返回这个属性呢?想想看。
如果它也是immutable的自然也就省心了。但如果不是呢?
看来必须得clone一个新的对象了。关于clone,可以参考liuwang126的文章http://liuwang126.iteye.com/blog/272595
下面是完整的Sample。
- package immutable;
- public class Immutable {
- private final int a;
- private static final String b;
- private final ClassA oa;
- static{
- b="";
- }
- public static Immutable getImmutable(int a, ClassA oa){
- return new Immutable(a, oa);
- }
- protected Immutable(int a, ClassA oa){
- this.a=a;
- this.oa=oa.clone();
- }
- public ClassA getOA(){
- return oa.clone();
- }
- public int getA() {
- return a;
- }
- public static String getB() {
- return b;
- }
- public static void main(String[] s){
- ClassA a = new ClassA(2);
- Immutable immutable=new Immutable(1, a);
- ClassA a2 = immutable.getOA();
- if(a==a2){
- System.out.print("a==a2");
- }else{
- System.out.print("a2.a="+a2.getA());
- }
- }
- }
- package immutable;
- public class ClassA implements Cloneable{
- private int a;
- public ClassA(int i){
- a=i;
- }
- public int getA() {
- return a;
- }
- public void setA(int a) {
- this.a = a;
- }
- public ClassA clone(){
- ClassA o = null;
- try{
- o = (ClassA)super.clone();
- }catch(CloneNotSupportedException e){
- e.printStackTrace();
- }
- return o;
- }
- }
- package immutable;
- final class ChildImmutable extends Immutable{
- private final int c;
- public ChildImmutable(int a, ClassA oa, int c) {
- super(a, oa);
- this.c=c;
- }
- public int getC() {
- return c;
- }
- }
这可能在一般的开发中不大会用到。可以被看成是一个设计游戏。不过如果我们自己设计API供别人调用,你不得不考虑规则的严谨和你的用意可以准确的表达和限制。
下面对final做个分析。
你有两个原因能够想到用final:design 和 efficiency。 你可以再方法的参数上加上final,保证传入的参数不被改变,这种设计是我们常常推崇的。
你也有两个原因在method前加上final。第一个是保证类的子类不会重写这个方法,这个方法的行为不被改变。这是设计方面的原因。另一个在低版本jdk中利用这点可以提高performance。但是也会有消耗内存的负面影响。在jdk5以后,jvm可以自动改善performance,我们反而不鼓励利用这点来优化性能。应该交给jvm去办。
当你在class前面加上final,说明你不准备也不允许这个类将来被继承。这可能是出于安全或者本身它就不会有子类。这是design方面的原因。final class的方法因为不可能被继承也就被final了,但是属性却没有被final。
和朋友交流了一下,又有了一点新的看法。immutable的本意是想让一个类的对象被创建以后就不要再被修改。有点类似常量。只想让别的程序只读。那就是说不提供写或者修改的方法。只是提供构造函数,一次生成,永不改变。从这个角度上看,也是简化了设计。对于这样的对象,你可以放心的使用,因为你知道他就是你生成时的对象,从来没有也不会被改变。
为什么JDK要设计这么多的immutable的类呢?
因为immutable类比mutable类更加容易设计,实现和使用。而且不易出错,更加安全。
简单:因为对象一旦生成就他的值就固定了,不变了。从对象状态角度上看,它只有一种状态,没有什么状态变化和迁移。相反,对于一个可以变对象,他的状态变化可就多了,你需要有个状态迁移图才能描述清楚他可能的变化,也就是说他的状态空间可能很大。
线程安全:因为没有修改方法,所以你不用考虑同步的问题,在并发环境中也可以放心的并发read。
节省内存:既然不变对象可以自由的共享。你可以让使用者尽量使用已经存在的实例,而不要重复的创建。你可以定义这些类的一些静态的final实例属性,就像定义一个常量一样。
- package client;
- import immutable.ClassA;
- import immutable.Immutable;
- class Client{
- public static final Immutable A = Immutable.getImmutable(1, new ClassA(1));
- public static final Immutable B = Immutable.getImmutable(2, new ClassA(2));
- }
当然你也可以为Immutable 类提供一个静态工厂,由工厂来保证不会创建重复的对象实例。
这样也就节省了内存消耗和垃圾回收负担。如果你有这样的对象,在系统中会被大量的,频繁的,并发的读。不放考虑这种模式。其实String就是一个很好的例子。
很好的构建基石:你应该比较常用到Set和Map,尤其是map的key值,你是否经常需要考虑这些值会不会在你不经意间变了呢?从而使得影响你设定这个set或map的本意。如果用Immutable对象你就不用担心了吧?这样是为什么你总喜欢用String做key值。当然你也可能想尽量避免重写equals和hashCode方法。
不要滥用这种模式
凡是必然是有利有弊。你知道immutable的对象会因为值的不同而生产新的对象,所以你要谨慎设计你的对象和使用方法。比如String,当你在循环里面连接字符串的时候就不建议你用String的+号,而是用BufferString,StringBuffer类用来表示内容可变的字符串,并提供了修改底层字符串的方法。当我们进行字符拼接时,请使用StringBuffer类而非String类,因为前者将比后者快上百倍。这也许也可以知道我们平衡我自己的设计。没准你也可以设计一个immutable类的伙伴(companion)类。
在我看来,当你想设计一种有结构的常量的时候,你可以考虑设计出一个immutable的类。
转载自:http://jackycheng2007.iteye.com/blog/923644
- 不可变类(immutable class)
- 不可变类(immutable class)
- Java实现Immutable Class(不可变类)要点
- 【Java】【容易忽略的知识点】不可变类 (IMMUTABLE CLASS)
- Java Immutable不可变类
- 不可变类:immutable 与 可变类
- 不可变(Immutable)字符串
- Immutable(不可变)集合
- Immutable Objects 不可变对象
- 可变类和不可变类(Mutable and Immutable Objects)
- java String被设计成不可变(immutable)类
- Guava学习笔记:Immutable(不可变)集合
- Guava学习笔记:Immutable(不可变)集合
- java中不可变对象(Immutable)
- Java不可变对象(Immutable Objects)
- Java-类库-Guava-Immutable(不可变)集合
- Guava学习笔记:Immutable(不可变)集合
- immutable Object 不可变对象设计模式
- Python逆向工程笔记
- 有关C Runtime 的转载
- C#中路径相关操作
- 从程序员到项目经理(11)
- Unity3D Transform中有关旋转的属性和方法测试
- 不可变类(immutable class)
- 开启设计之门 设计基础教程之构图篇
- linux sort 设定tab分隔符
- AAuto - 抓取网页新闻
- C++primer第五版【学习笔记】——第一章
- 古代父母对孩子“七不责” 精髓
- CreateAlias 与 CreateCriteria的区别
- 揭秘谷歌“神秘”的招聘机制
- Java的堆栈分析