不可变对象条件

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

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. POJ2032 Building a Space Station(Kruskal)(并查集)

    Building a Space Station Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 7469   Accepte ...

  2. 礼物(BFS)

    礼物 时间限制: 1 Sec  内存限制: 64 MB提交: 39  解决: 4[提交][状态][讨论版] 题目描述 给出一个n行m列的点阵,“.”表示可通行格子,“#”表示不可通行格子,“K”表示国 ...

  3. Centos7下安装7za 及7za常用命令

    安装必备环境 yum install kernel-devel kernel-headers gcc-c++ make bzip2 下载源码(16.02版本,2016.10.04 publish) w ...

  4. [BZOJ 3170] 松鼠聚会

    Link: BZOJ 3170 传送门 Solution: $Knowledge Point:$ 切比雪夫距离$DIST(a,b)=max\{ |X'_a-X'_b|,|Y'_a-Y'_b|\}$ 曼 ...

  5. 【数位dp】hdu2089 不要62

    http://www.cnblogs.com/xiaohongmao/p/3473599.html #include<cstdio> using namespace std; int n, ...

  6. 【分块】【线段树】bzoj3212 Pku3468 A Simple Problem with Integers

    线段树入门题…… 因为poj原来的代码莫名RE,所以丧病地写了区间修改的分块…… 其实就是块上打标记,没有上传下传之类. #include<cstdio> #include<cmat ...

  7. Problem E: 调用函数,求m-n之间的所有完数

    #include<stdio.h> int factorsum(int number)//定义函数 { ; ;i<number;i++) ) s+=i; return s; } in ...

  8. Linux下的echo输出换行符

    echo -e "text1\ntext2" -e表示开启转移字符

  9. javascript 常用手势 分析

    javascript 常用手势, 个人觉得有3个 tap,swipe(swipeLeft,swipeRight,swipeTop,swipeRight),hold tap 是轻击 判断的原则是,在to ...

  10. 怎样使用libcurl获取隐藏了文件后缀的url网络文件类型

    CURLINFO_CONTENT_TYPE CURL: Get Returned Content Mime Type 例如 :以下代码可以查询出天地图的tile图像类型为jpg "http: ...