EffectiveJava(15)强化对象和域的不可变性
概念:
不可变类是其实例不能被修改的类,不可变类比可变类更加易于设计 实现和使用.它们不容易出错,而且更加安全.
优点
1.不可变对象只有创建时状态.
2.不可变对象本质上是线程安全的,它们不要求同步
3.不可变对象和其内部信息可以被自由共享.这条导致的结果是不可变类永远也不需要进行任何拷贝(拷贝对象始终为原始对象).
public static final Complex ZERO = new Complex(0.0);
4.不可变对象为其他对象提供了大量构件,其他对象无论是否可变.
缺点:
它只有唯一一个缺点:对于每个不同的值都需要单独创建一个对象
改变BigInteger的低位
BigInteger moby = new BigInteger("198");
//多步骤操作,每个步骤都会创建一个对象,除了最后的结果之外,其他对象都会被抛弃
moby = moby.flipBit(0);
//它只有在需要进一的时候,才会自减一 199>198 100-198>101-199
System.out.println(moby);
运行之后我们可以看到,需要很长时间才能计算完成
针对它的性能问题(缺点)也有优化方法
1.猜测会经常使用哪些多步骤操作,然后将他们作为基本类型提供
2.提供一个公有的可变嵌套类:String的可变嵌套类为StringBuilder
不可变类创建规则:
1.不要提供任何会修改对象状态的方法
2.保证类不会被扩展:防止子类假装对象的状态已经改变而破坏该类的不可变行为
a.一般把类声明为final
b.让类的所有构造器都变成私有的或者包级私有的,并添加公有的静态工厂方法
有关于静态工厂方法,请跳转:http://blog.csdn.net/jacxuan/article/details/56849989
// public Complex(double re, double im) {
// this.re = re;
// this.im = im;
// }
// 通过让类的所有构造器变成私有或者包级私有并添加公有的静态工厂来代替公有构造器来让不可变类变为final
private Complex(double re, double im) {
this.re = re;
this.im = im;
}
public static Complex valueOf(double re, double im) {
return new Complex(re, im);
}
3.使所有域都是final的
4.使所有域都成为私有的:防止被域引用的可变对象的权限,并防止客户端直接修改这些对象.公有final域不建议
5.确保对于任何可变组件的互斥访问:如果类具有指向可变对象的域,则必须确保该类的客户端无法获得指向这些对象
的引用.并且,永远不要用客户端提供的对象引用来初始化这样的域,也不要从任何访问方法中返回该对象的引用.
6.坚决不要为每个get方法编写一个相应的set方法.
创建一个不可变的类:
这个类表示一个复数(具有实部和虚部),他除了提供标准的Object方法之外,还提供了针对实部和虚部的访问方法
,以及四种混合运算.
注意这些算法运算是如何创建并返回新的Complex实例的
public final class Complex {
public final double re;
public final double im;
public Complex(double re, double im) {
this.re = re;
this.im = im;
}
// Accessors with no corresponding mutators
// 访问器没有相应的调整器
public double realPart() {
return re;
}
public double imaginaryPart() {
return im;
}
public Complex add(Complex c) {
return new Complex(re + c.re, im + c.im);
}
public Complex subtract(Complex c) {
return new Complex(re - c.re, im - c.im);
}
public Complex multiply(Complex c) {
return new Complex(re * c.re - im * c.im, re * c.im + c.re);
}
public Complex divide(Complex c) {
double tmp = c.re * c.re + c.im * c.im;
return new Complex((re * c.re + im * c.im) / tmp, (im * c.re - re * c.im));
}
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Complex))
return false;
Complex c = (Complex) o;
// See page 43 to find out why we use compare instead of ==
// 见43页找出为什么我们使用比较而不是= =
return Double.compare(re, c.re) == 0 && Double.compare(im, c.im) == 0;
}
@Override
public int hashCode() {
int result = 17 + hashDouble(re);
result = 31 * result + hashDouble(im);
return result;
}
private int hashDouble(double im2) {
long longBits = Double.doubleToLongBits(re);
return (int) (longBits ^ (longBits >>> 32));
}
@Override
public String toString() {
return "(" + re + "+" + im + "i)";
}
}
ps:如果你正在编写一个安全性依赖于BigInteger或者BigDecimal参数的不可变性,就必须进行检查,
以确定这个参数是真正的BinInteger或BigDecimal,而不是不可信任的子类的实例.如果是后者的
话,必须假设它是可变的前提下对它进行可变性拷贝
public static BigInteger safeInstance(BigInteger val){
if(val.getClass()!=BigInteger.class)
return new BigInteger(val.toByteArray());
return val;
}
总结:如果类不能被做成不可变的,仍然应该尽可能限制它的可变性.
EffectiveJava(15)强化对象和域的不可变性的更多相关文章
- Delphi属性比对象的域有更强的功能
8.4 Delphi自定义组件(3) http://tech.163.com 2006-04-29 11:49:34 来源: 清华大学出版社 网友评论0 条 论坛 3. 测试未安装的组件 在将新组 ...
- EffectiveJava——用函数对象表示策略
有些语言支持函数指针.代理.lambda表达式,或者支持类似的机制,允许程序把“调用特殊函数的能力”储存起来并传递这种能力.这种机制通常用于允许函数的调用者通过传入第二个函数,来指定自己的行为.比较器 ...
- 《深入Java虚拟机学习笔记》- 第15章 对象和数组
1.针对对象的操作码 实例化一个新对象需要通过new操作码来实现. 对象的创建 操作码 操作数 说明 new index 在堆中创建一个新的对象,将其引用压入栈 new操作码后面紧跟一个无符号16位数 ...
- ServletContext对象--三大域对象
Servlet三大域对象的应用 request.session.application(ServletContext) ServletContext是一个全局的储存信息的空间,服务器开始就存在,服务器 ...
- java web jsp学习笔记--概述-常用语法,指令,动作元素,隐式对象,域对象
JSP学习笔记 1.什么是jsp JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术.JSP/Servlet规范.JS ...
- JSP中的9大内置对象四大域与servlet里的三大域
九大内置对象 隐式对象 说明 out 转译后对应JspWriter对象,其内部关联一个PringWriter对象 request 转译后对应HttpServletRequest/ServletRequ ...
- JSP--JSP语法--指令---九大隐式对象--四大域对象--JSP内置标签--JavaBean的动作元素--MVC三层架构
一.JSP 原理:JSP其实就是一个servlet. Servlet负责业务逻辑处理,JSP只负责显示.开发中,JSP中不能有一行JAVA代码 二.JSP语法 1. JSP模板元素:JSP中HTML标 ...
- JSP--JSP语法--指令--include(动态包含/静态包含)--九大隐式对象--四大域对象--JSP内置标签--JavaBean的动作元素--MVC三层架构
一.JSP 原理:JSP其实就是一个servlet. Servlet负责业务逻辑处理,JSP只负责显示.开发中,JSP中不能有一行JAVA代码 二.JSP语法 1. JSP模板元素:JSP中HT ...
- javaweb九大个内置对象,四大域
9个内置对象如下: 1.session对象:会话对象 当客户端第一次访问服务器的页面时,web服务器会自动为该客户端创建一个session对象并分配一个唯一的id号 常常用它来在多个页面间共享数据,如 ...
随机推荐
- bzoj1396&&2865 识别子串 后缀自动机+线段树
Input 一行,一个由小写字母组成的字符串S,长度不超过10^5 Output L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长. Sample Input agoodco ...
- 汕头市队赛SRM15
T1——czl SRM 15 众所周知,czl家养了一只可♂爱的***(已屏蔽),那只东西很贪吃,所以czl家很多零食仓库,然而这些仓库里有很多老鼠. 为了心爱的***,czl决定点燃纯艾条,用烟熏老 ...
- HDU 4649 Professor Tian (概率DP)
Professor Tian Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)To ...
- Hidden (NOIP模拟赛)(字符串模拟QAQ)
原题传送门 神奇的题目诶 原来以为字符串比较一定要O(NlogN) 结果发现可以均摊O(N) 首先我们来讲一讲原理 我们有3个指针i,j,k i=0,j=1,k=0 一开始我们不断对k+1直到找到ch ...
- kvm qemu内幕介绍
转自:http://blog.csdn.net/wj_j2ee/article/details/7978259目录 1 硬件虚拟化技术背景 2 KVM的内部实现概述 2.1 KVM的抽象对象 2.2 ...
- Linux getcwd()的实现【转】
转自:http://www.cnblogs.com/alan-forever/p/3721908.html 通过getcwd()可以获取当前工作目录. 1 #include <unistd.h& ...
- 获取URL中的文件的扩展名
问题: 尽可能多地写出获取文件扩展名的方法: //方法一(分割数组) function getExt($url){ $arr = explode('.',$url); $len = count($ar ...
- centos7部署nagios
一.Nagios简介 Nagios是一款开源的电脑系统和网络监视工具,能有效监控Windows.Linux和Unix的主机状态,交换机路由器等网络设置,打印机等.在系统或服务状态异常时发出邮件或短信报 ...
- Netty源码学习(七)FastThreadLocal
0. FastThreadLocal简介 如同注释中所说:A special variant of ThreadLocal that yields higher access performance ...
- NYOJ 21.三个水杯-初始态到目标态的最少次数-经典BFS
题目传送门:biubiubiu~ 三个水杯 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 给出三个水杯,大小不一,并且只有最大的水杯的水是装满的,其余两个为空杯子. ...