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号 常常用它来在多个页面间共享数据,如 ...
随机推荐
- hdu 4679 树的直径
/* 题目大意:给n个点n-1条边的树,求删除哪条边时两个树中最大的直径与边权的乘积最小. 树的直径(Diameter)是指树上的最长简单路. 直径的求法:两遍BFS (or DFS) 若删除的边不是 ...
- error LNK2001: 无法解析的外部符号 "public: virtual long __stdcall CBaseFilter(转)
原文转自 https://www.cnblogs.com/xiongjiaji/archive/2010/12/31/2476565.html 今天用VS2005编译DirectShow程序,发现出来 ...
- 《Linux命令行与shell脚本编程大全 第3版》创建实用的脚本---11
以下为阅读<Linux命令行与shell脚本编程大全 第3版>的读书笔记,为了方便记录,特地与书的内容保持同步,特意做成一节一次随笔,特记录如下:
- http请求分析
一个Http请求一般始于如下几种方式: 1.在浏览器中输入一个URL地址 2.网页中的一个超链接 3.Response.Redirect("http://www.sohu.com" ...
- 链表各种操作及其实现方法(c实现)
链表是一种最简单的数据结构之一,经常会被面试官用来考察应聘者的基础扎不扎实,最近也到了求职季,所以我把自己对链表的一些理解写出来,希望能跟大家交流交流: 链表的概念其实挺简单,无非就是一个利用指针将数 ...
- 获取dnspod指定域名的记录
#!/usr/bin/python #-*- coding: utf-8 -*- import os,requests,json import re,time,xlsxwriter #时间 date= ...
- idea 创建web工程
相关工具版本 说明:IntelliJ IDEA 版本为2018JDK 版本为1.8tomcat 版本为apache-tomcat-7.0.59 1,创建Project:依次点击File–new Pro ...
- Jquery实现逐屏加载图片
引用jquery.scrollLoading.js $(document).ready(function () { //实现图片慢慢浮现出来的效果 $("img").load(fu ...
- Laravel中setAttribute和queryScope的用法
setAttribute使用场景: 数据在存入数据库的时候需要进行预先处理,每次都会写很多重复代码,使用 setAttribute之后就可以在数据填充时自动完成. setAttribute的写法:se ...
- (23)C#XML操作
APP.config是一个典型的XML文件 打开vs2008在项目上右键-添加-新建项 选择应用程序配置文件,默认名称为APP.config,新建打开后默认代码如下 <?xml version= ...