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 树 通过 ...