不可变对象条件

对象需要满足一下三个条件才是不可变对象:

1、对象创建以后其状态就不能修改

2、对象所有域都是final类型

3、对象是正确创建的(对象在创建期间,this引用没有溢出)

简而言之就是将类声明为final,将所有的成员声明为私有的,对变量不提供set方法。将所有可变的成员声明为final。在get方法中不返回对象本身,而是克隆对象的拷贝。(可参考String类)。

final关键字

final关键字可修饰类、方法和变量。在修饰类时,这个类是不允许被继承。final类中的方法会被隐式的被指定为final方法。修饰方法是为了锁定方法不被继承类修改,即final方法不允许被修改,一个类的private方法会被隐式指定为final类型。final修饰变量可分为两种情况。一、修饰基本数据类型时,一旦被final修饰,这个变量的数值就不能被修改了。二、修饰引用类型变量时,则是让它在初始化之后就不能指向其他对象(可修改该引用变量的成员变量)。例如:

@Slf4j
public class ImmutableExample1 { private final static Integer a = 1;
private final static String b = "2";
private final static Map<Integer, Integer> map = new HashMap(); static {
map.put(1, 2);
map.put(3, 4);
map.put(5, 6);
} public static void main(String[] args) {
map.put(1, 3);
log.info("{}", map.get(1));
}
}

虽然map声明为final对象,但是依然可以往里放入键值对。

Java提供常见不可变对象

Collections.unmodifiableXXX:Collection、List、Set、Map等。

@Slf4j
public class ImmutableExample2 { private static Map<Integer, Integer> map = Maps.newHashMap(); static {
map.put(1, 2);
map.put(3, 4);
map.put(5, 6);
map = Collections.unmodifiableMap(map);
} public static void main(String[] args) {
map.put(1, 3);
log.info("{}", map.get(1));
} }

执行结果如下:

发现执行结果为抛出异常信息,不允许被修改。我们可以用这个方法来修饰不可变的集合对象。

查看源码的主要方法实现:

public class Collections {
// Suppresses default constructor, ensuring non-instantiability.
private Collections() {
} private final Map<? extends K, ? extends V> m; UnmodifiableMap(Map<? extends K, ? extends V> m) {
if (m==null)
throw new NullPointerException();
this.m = m;
} ... ... public V put(K key, V value) {
throw new UnsupportedOperationException();
}
public V remove(Object key) {
throw new UnsupportedOperationException();
}
public void putAll(Map<? extends K, ? extends V> m) {
throw new UnsupportedOperationException();
}
public void clear() {
throw new UnsupportedOperationException();
} ... ... }

其实就是将put方法等直接抛出异常,防止修改。

其他工具提供的不可变对象

Googel常用的工具包Guava同样也提供了很多不可变对象的方法如 ImmutableXXX:Collection、List、Set、Map等。

Java多线程——不可变对象的更多相关文章

  1. 从火箭发场景来学习Java多线程并发闭锁对象

    从火箭发场景来学习Java多线程并发闭锁对象 倒计时器场景 在我们开发过程中,有时候会使用到倒计时计数器.最简单的是:int size = 5; 执行后,size—这种方式来实现.但是在多线程并发的情 ...

  2. Java多线程操作同一个对象,线程不安全

    Java多线程操作同一个对象 发现问题:多个线程操作同一资源的情况下,线程不安全,数据紊乱 代码: package multithreading; // Java多线程操作同一个对象 // 买火车票的 ...

  3. Java多线程编程核心技术---对象及变量的并发访问(二)

    数据类型String的常量池特性 在JVM中具有String常量池缓存的功能. public class Service { public static void print(String str){ ...

  4. java String不可变对象,但StringBuffer是可变对象

    什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不 ...

  5. java 多线程访问同一个对象数据保护的问题

    java 多线程同时访问统一个数据的时候,会引起一些错误,后面的线程会修改数据,而前面的线程还在使用修改前的内容, 使用 synchronized 关键字,保证代码块只能有一个线程来访问 public ...

  6. Java多线程对同一个对象进行操作

    示例: 三个窗口同时出售20张票. 程序分析: 1.票数要使用一个静态的值. 2.为保证不会出现卖出同一张票,要使用同步锁. 3.设计思路:创建一个站台类Station,继承THread,重写run方 ...

  7. java多线程系列(二)---对象变量并发访问

    对象变量的并发访问 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我 ...

  8. Java多线程编程核心技术---对象及变量的并发访问(一)

    synchronized同步方法 "非线程安全"其实会在多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是"脏读",也就是渠道的数据其实是被更改 ...

  9. Java多线程之释放对象的锁

          由于等待一个锁定线程只有在获得这把锁之后,才能恢复运行,所以让持有锁的线程在不需要锁的时候及时释放锁是很重要的.在以下情况下,持有锁的线程会释放锁: 1. 执行完同步代码块. 2. 在执行 ...

随机推荐

  1. [BZOJ5006][LOJ#2290][THUWC2017]随机二分图(概率+状压DP)

    https://loj.ac/problem/2290 题解:https://blog.csdn.net/Vectorxj/article/details/78905660 不是很好理解,对于边(x1 ...

  2. 【树上莫队】bzoj3757 苹果树

    学习这位神犇的:http://blog.csdn.net/jiangyuze831/article/details/41476865 注意: ①排序时第一关键字是左端点所在块编号(块状树),第二关键字 ...

  3. 109.关路灯(区间dp)

    1258 关路灯  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 大师 Master 题解 查看运行结果 题目描述 Description 多瑞卡得到了一份有趣而高薪的工作.每 ...

  4. iOS键盘监听事件

    1.注册键盘通知事件 NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; // 键盘将出现事件监听 [center ...

  5. Flex页面跳转的五种实现方式

    Flex页面跳转有很多值得学习的地方,本文向大家介绍一下Flex页面跳转的几种方式,主要包括五种方式,这里为大家一一介绍. AD:   在学习Flex的过程中,你可能会遇到Flex页面跳转的概念,这里 ...

  6. 关于JS中原型链中的prototype与_proto_的个人理解与详细总结

    一直认为原型链太过复杂,尤其看过某图后被绕晕了一整子,今天清理硬盘空间(渣电脑),偶然又看到这图,勾起了点回忆,于是索性复习一下原型链相关的内容,表达能力欠缺逻辑混乱别见怪(为了防止新人__(此处指我 ...

  7. 百度display name为中文导致奔溃,productName和budlename区分出来

    把"xxx-info.plist"中的"Bundle display name"的值改成了英文,或者把它的值修改成系统默认的"${PRODUCT_NA ...

  8. 如何用路由器改成WiFi Pineapple系统镜像网络流量

    本文主要介绍利用自己现有的设备,如何制作和使用WiFi Pineapple镜像网络流量,利用DWall模块分析用户数据,然后根据自己的需求,给DWall加入了日志记录功能.最后介绍了如何防范wifi ...

  9. CentOS7下nrpe3.0安装(转)

    本人菜鸟一枚,在学习nagios的时候碰到了很多问题,在网上找了很多相关的教程,都是老版本的,怎么装都不对,强迫症的我非要按装新版本,老版本的教程怎么搞都不行,只能自己研究了. 首先,下载nrpe3. ...

  10. vagrant 知识库

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明 http://wushaobo.info/?p=83 Vagrant让虚拟化技术走近寻常家.脚踏实地地说,网络上类似“两分钟入门”的文 ...