Java 不可变类
Java 不可变类
immutable object 不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值。
如JDK内部自带的很多不可变类:Interger、Long和String等。
** 不可变类,指的是 该类的实例不可变,而非指向该实例的引用的不可变**
优点
- 线程安全
 - 当一个对象是不可变的,那么需要拷贝这个对象的内容时,就不用复制它的本身而只是复制它的地址,复制地址(通常一个指针的大小只需要很小的内存空间,具有非常高的效率。同时,对于引用该对象的其他变量也不会造成影响。
 - 此外,不变性保证了hashCode 的唯一性,因此可以放心地进行缓存而不必每次重新计算新的哈希码。而哈希码被频繁地使用, 比如在hashMap 等容器中。将hashCode 缓存可以提高以不变类实例为key的容器的性能。
 
如何实现
- 所有成员都是private final;
 - 不提供改变成员的方法,setter ;
 - 确保所有方法不会被重载, 使用final class 强不可变类,或 所有方法加上final;
 - 如果一个类的成员,不是基本类型primitive type或不可变类, 则在成员初始化和 getter方法时,深度拷贝(复制类的实例而非引用);
 - 如果有必要,重写hashCode equals, 应保证在equals相等时,hashCode也相等。
 
通过反射修改String 对象的值
//用反射获取 修改string 值;
    public static void main(String[] args){
        String s= "Hello World";
        System.out.println(" s: "+s);
        try {
            Field value = String.class.getDeclaredField("value");
            value.setAccessible(true);
            char[] vs = (char[]) value.get(s);
            vs[5] = 'F';
            System.out.println(" s after: "+ s);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
如果需要设计一个不可变类,尤其要注意其引用类型Field,如果其引用类型Field的类是可变的,就必须采取必要的措施来保护该Field所引用的对象不会被修改,这样才能创建真正的不可变类。
class Name{
    private String first;
    private String last;
    public Name(){}
    public Name(String f, String l){
        first = f;
        last  = l;
    }
    public void setFirst(String first) {this.first = first;}
    public String getFirst() {return first;}
    public String getLast() {return last;}
    public void setLast(String last) {this.last = last;}
    @Override
    public String toString() {
        return "Frist: "+first + " last: " + last;
    }
}
class Person{
    private final Name name;
    public Person(Name name){
        this.name = new Name(name.getFirst(),name.getLast());
    }
    public Name getName() {
        return new Name(name.getFirst(),name.getLast());
    }
    @Override
    public String toString() {
        return getClass().getName() + "@[name="+this.getName() +"]";
    }
}
public class ImmutableTestTwo {
    public static void main(String[] args){
        Name n1 = new Name("悟空", "孙");
        Person p1 = new Person(n1);
        System.out.println(p1.getName().getFirst());
        n1.setFirst("八戒");
        System.out.println(p1.getName().getFirst());
    }
}
或者做如下修改:
将Name类的setter方法删除掉,这样Name类是不可变的类,Person类也是不可变的类。
参考资料
从final的作用剖析String被设计成不可变类的深层原因
Java 不可变类的更多相关文章
- JAVA不可变类(immutable)机制与String的不可变性--非常好.
		
JAVA不可变类(immutable)机制与String的不可变性 https://www.cnblogs.com/jaylon/p/5721571.html
 - JAVA的可变类与不可变类
		
转自: http://www.blogjava.net/hilor/articles/150610.html 可变类和不可变类(Mutable and Immutable Objects)的初步定义: ...
 - JAVA不可变类(immutable)机制与String的不可变性
		
一.不可变类简介 不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值.如JDK内部自带的很多不可变类:Interger.Long和String等. 可变类:相对于不可变类, ...
 - JAVA不可变类与可变类、值传递与引用传递深入理解
		
一个由try...catch...finally引出的思考,在前面已经初步了解过不可变与可变.值传递与引用传递,在这里再次深入理解. 1.先看下面一个try..catch..finally的例子: P ...
 - 【Java基础】JAVA不可变类(immutable)机制与String的不可变性
		
一.不可变类简介 不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值.如JDK内部自带的很多不可变类:Interger.Long和String(8种基本数据类型的包装类和S ...
 - 创建Java不可变类
		
不可变(immutable)类的意思是创建该类的实例后,该实例的Field是不可改变的,Java提供的8个包装类和java.lang.String类都是不可变类. 如果需要创建自定义的不可变类,可遵守 ...
 - 【转】Java的可变类与不可变类
		
1.可变类和不可变类(Mutable and Immutable Objects)的初步定义: 可变类:当你获得这个类的一个实例引用时,你可以改变这个实例的内容. 不可变类:当你获得这个类的一个实例引 ...
 - Java不可变类与final类
		
概念 Java的不可变类是指八个基础类型的包装类和String,他们的数据成员是不可变的.使用加法等操作时,其实是创建了一个新的对象. Java的final类是对类用关键字final进行修饰,说明该类 ...
 - 创建正真的Java不可变类
		
如果需要设计一个不可变类,尤其要注意其引用类型Field,如果其引用类型Field的类是可变的,就必须采取必要的措施来保护该Field所引用的对象不会被修改,这样才能创建真正的不可变类. class ...
 
随机推荐
- Using Request Headers for Metadata Address
			
问题描述 我将一个在本地调试正常的service部署到服务器后遇到了添加服务引用失败的问题.在把配置文件中基址使用的localhost替换成服务器的ip地址后问题得到了解决.但我感觉这并不是一个因为粗 ...
 - ubuntu配置多网,网关不起作用的问题
			
在/etc/network/interfaces 中设置网络 auto eth0 iface eth0 inet static address 192.168.50.1 gateway 192.168 ...
 - MySql 的操作日志 历史记录
			
如何查看mysql数据库操作记录日志 1.首先确认你日志是否启用了mysql>show variables like 'log_bin'. 2.如果启用了,即ON,那日志文件就在mysql的安装 ...
 - JAVA编译结果中有****$1.class的
			
java编译后的文件名字带有$接数字的就是匿名内部类的编译结果,接名字的就是内部类的编译结果 例如:TestFrame$1.class是匿名内部类的编译结果,TestFrame$MyJob.class ...
 - DFS-20190206
			
找出所有方案 排列和组合问题 排列: https://www.lintcode.com/problem/combination-sum/description public class Solutio ...
 - PHP的curl实现get,post 和 cookie (转)
			
类似于dreamhost这类主机服务商,是显示fopen的使用 的.使用php的curl可以实现支持FTP.FTPS.HTTP HTPPS SCP SFTP TFTP TELNET DICT FILE ...
 - 查找Ubuntu下包的归属
			
今天在制作docker时,发现我的程序有些依赖的包不太好找应该安装什么. 在centos下面,可以用命令: rpm -qf <libraryname> 在Ubuntu下面,发现一个网站基本 ...
 - 后缀自动机 && 题目
			
因为明天要讲解后缀自动机了,所以只能抱抱佛脚,临时做做题目.其实很久以前看过,但是不太懂,看的是clj的原文,不太懂.现在只能临时看看是怎么弄的,应付下. ---------------------- ...
 - Java常见的错误种类
			
数组中的错误: 越界: java.lang.ArrayIndexOutOfBoundsException 数组越界,如果声明 了5个元素的数组,但是在取值的时候用到了索引5,那就越界了 空指针:jav ...
 - JavaScript HTML DOM学习记录
			
HTML DOM (文档对象模型) 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model). HTML DOM 模型被构造为对象的树. HTML DOM 树 通过 ...