Java 不可变类

immutable object 不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值。

如JDK内部自带的很多不可变类:Interger、Long和String等。

** 不可变类,指的是 该类的实例不可变,而非指向该实例的引用的不可变**

优点

  • 线程安全
  • 当一个对象是不可变的,那么需要拷贝这个对象的内容时,就不用复制它的本身而只是复制它的地址,复制地址(通常一个指针的大小只需要很小的内存空间,具有非常高的效率。同时,对于引用该对象的其他变量也不会造成影响。
  • 此外,不变性保证了hashCode 的唯一性,因此可以放心地进行缓存而不必每次重新计算新的哈希码。而哈希码被频繁地使用, 比如在hashMap 等容器中。将hashCode 缓存可以提高以不变类实例为key的容器的性能。

如何实现

  1. 所有成员都是private final;
  2. 不提供改变成员的方法,setter ;
  3. 确保所有方法不会被重载, 使用final class 强不可变类,或 所有方法加上final;
  4. 如果一个类的成员,不是基本类型primitive type或不可变类, 则在成员初始化和 getter方法时,深度拷贝(复制类的实例而非引用);
  5. 如果有必要,重写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 不可变类的更多相关文章

  1. JAVA不可变类(immutable)机制与String的不可变性--非常好.

    JAVA不可变类(immutable)机制与String的不可变性 https://www.cnblogs.com/jaylon/p/5721571.html

  2. JAVA的可变类与不可变类

    转自: http://www.blogjava.net/hilor/articles/150610.html 可变类和不可变类(Mutable and Immutable Objects)的初步定义: ...

  3. JAVA不可变类(immutable)机制与String的不可变性

    一.不可变类简介 不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值.如JDK内部自带的很多不可变类:Interger.Long和String等. 可变类:相对于不可变类, ...

  4. JAVA不可变类与可变类、值传递与引用传递深入理解

    一个由try...catch...finally引出的思考,在前面已经初步了解过不可变与可变.值传递与引用传递,在这里再次深入理解. 1.先看下面一个try..catch..finally的例子: P ...

  5. 【Java基础】JAVA不可变类(immutable)机制与String的不可变性

    一.不可变类简介 不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值.如JDK内部自带的很多不可变类:Interger.Long和String(8种基本数据类型的包装类和S ...

  6. 创建Java不可变类

    不可变(immutable)类的意思是创建该类的实例后,该实例的Field是不可改变的,Java提供的8个包装类和java.lang.String类都是不可变类. 如果需要创建自定义的不可变类,可遵守 ...

  7. 【转】Java的可变类与不可变类

    1.可变类和不可变类(Mutable and Immutable Objects)的初步定义: 可变类:当你获得这个类的一个实例引用时,你可以改变这个实例的内容. 不可变类:当你获得这个类的一个实例引 ...

  8. Java不可变类与final类

    概念 Java的不可变类是指八个基础类型的包装类和String,他们的数据成员是不可变的.使用加法等操作时,其实是创建了一个新的对象. Java的final类是对类用关键字final进行修饰,说明该类 ...

  9. 创建正真的Java不可变类

    如果需要设计一个不可变类,尤其要注意其引用类型Field,如果其引用类型Field的类是可变的,就必须采取必要的措施来保护该Field所引用的对象不会被修改,这样才能创建真正的不可变类. class ...

随机推荐

  1. [ActionScript 3.0] 自定义右键菜单

    将自定义右键菜单的一些属性和方法归纳到AddRightMenu.as,通过实例化此类,调用相关方法即可测试! package { import flash.display.Sprite; import ...

  2. nginx负载均衡监测节点状态

    1. 安装nginx_upstream_check_module模块 我的实验环境是在/root 和 /application目录下都编译安装了nginx-1.6.3,然后在/root目录下建立一个文 ...

  3. ssh协议git利用ss代理

    前言 不知道ss为何物的绕道 求帐号的绕道 这里只是亲测 ssh协议下的git, 如何判断是什么协议出门左拐 判断是否需要代理 我遇到的问题是: ssh_exchange_identification ...

  4. C# Directory和DirectoryInfo类(文件目录操作)

    对目录操作例子: using System; using System.Collections.Generic; using System.Linq; using System.Text; using ...

  5. 动态树Link-cut tree(LCT)总结

    动态树是个好玩的东西 LCT题集 预备知识 Splay 树链剖分(好像关系并不大) 动态树(Link-cut tree) 先搬dalao博客 什么是LCT? 动态树是一类要求维护森林的连通性的题的总称 ...

  6. [转] Spark快速入门指南 – Spark安装与基础使用

    [From] https://blog.csdn.net/w405722907/article/details/77943331 Spark快速入门指南 – Spark安装与基础使用 2017年09月 ...

  7. Q438 找到字符串中所有字母异位词

    给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引. 字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100. 说明: ...

  8. kafka监控服务搭建

    wget https://github.com/Morningstar/kafka-offset-monitor/releases/download/0.4.1/KafkaOffsetMonitor- ...

  9. $bzoj1021-SHOI2008\ Debt$ 循环的债务 $dp$

    题面描述 \(Alice\).\(Bob\)和\(Cynthia\)总是为他们之间混乱的债务而烦恼,终于有一天,他们决定坐下来一起解决这个问题.不过,鉴别钞票的真伪是一件很麻烦的事情,于是他们决定要在 ...

  10. $bzoj1019-SHOI2008$ 汉诺塔 $dp$

    题面描述 汉诺塔由三根柱子(分别用\(A\ B\ C\)表示)和\(n\)个大小互不相同的空心盘子组成.一开始\(n\)个盘子都摞在柱子\(A\)上,大的在下面,小的在上面,形成了一个塔状的锥形体. ...