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. linux开始之旅-01 linux需要知道的这几位

    首先介绍几个人,没有这几个人就没有linux. 第一个:肯·汤普逊(左)和丹尼斯·里奇(右)  ------ C语言之父   ------学计算机的人都应该认识吧,计算机学院楼道里面都会有这两位. 美 ...

  2. mysql基本用法

    mysql的基本用法     一.创建数据库 create database day02 default character set utf8; -- 创建表 create table user( i ...

  3. Kettle 解决数据锁的问题(事务(进程 ID 51)与另一个进程被死锁在 锁 资源上)

    1.Kettle做了一个作业, 执行的时候问题发生在步骤2和步骤3之间,也就是步骤2还未完全执行完的时候,步骤3就要更新步骤2插入的数据,造成死锁.(我的理解是既然都分开作业了,那么每个作业都是一个单 ...

  4. CF1097D Makoto and a Blackboard(期望)

    [Luogu-CF1097D] 给定 \(n,k\)一共会进行 \(k\) 次操作 , 每次操作会把 \(n\) 等概率的变成 \(n\) 的某个约数 求操作 \(k\) 次后 \(n\) 的期望是多 ...

  5. Mastache.js学习笔记(转自小花喵)

    简单的记录我使用Mastache的使用. 为什么使用JS模板引擎? 当数据结构复杂,Js的拼接凌乱,难以维护,但是又需要通过ajax加载数据的时候: 而Mastache的上手难度不高,并符合大部分业务 ...

  6. 关于锚点定位,ul设置fixed后,div被覆盖一部分的问题

    例如: 问题: 刚开始的时候 .ul是正常显示的,当页面的滚动条滚动到一定的高度是 ,ul就被设置为 position:fixed:那么 点击 li相对应div就会被 固定定位的ul覆盖住一部分. 解 ...

  7. ES6新特性整理,你需要了解的ES6知识

    ES6是新版本JavaScript语言的标准,上一次标准的制订还是2009年出台的ES5.目前ES6的标准化工作已经完成,14年12月份放出了正式版本. 目前主流的浏览器都支持运行ES6代码,如果你的 ...

  8. JAVA统计一定范围内的质数个数

    public class TestNumber{ public static void main(String[] args){ System.out.println(roundPrimeCount( ...

  9. Asp.Net webconfig中使用configSections的用法

    最近闲来无事,研究研究公司的框架,无意中打开了webconfig页面,发现了一个我不认识的节点<configSections></configSections>,于是百度之,大 ...

  10. Ubuntu14.04下编译安装或apt-get方式安装搭建Apache或Httpd服务(图文详解)

    不多说,直接上干货! 写在前面的话 对于 在Ubuntu系统上,编译安装Apache它默认路径是在/usr/local/apache2/htdocs 或者编译安装httpd它默认路径是在/usr/lo ...