《Effective Java》读书笔记 - 最小化类的可变性

Item 15 最小化类的可变性

effective java

如何做到让类不可变?

  1. 不提供改变对象状态的方法。(mutators)
  2. 确保类不会被继承,即用final来限定类。
  3. 让所有的域(field)为final。
  4. 让所有的域private。
  5. 确保所有对可变组件的互斥访问(Ensure exclusive access to any mutable components)

例子:

public final class Complex{
//final class

    private final double re;
    //private final field
    private final double im;

    public Complex(double re,double im){
        this.re = re;
        this.im = im;
    }

    public double realPart(){return re;}
    public double imaginaryPart(){return im;}

    public Complex add(Complex c){
        return new Complex(re+c.re,im+c.im);
        //return new object instead of modify itself
    }

    //Other arithmetic method ommit...
}

为什么要使用不可变对象(immutable objects)?

  1. 不可变对象很简单。不需要考虑对象在变化中是否会变得行为怪异。只要在构造方法中有限制,不可变对象就一直是有效的。
  2. 不可变对象本质上是线程安全的,不需要同步(synchronization)。不可变对象是鼓励共享而不用担心安全。例如以下这种:
    public static final Complex ZERO = new Complex(0,0);
  3. 不可变对象的内部也是鼓励共享的。
  4. 不可变对象作为其他复杂对象的构件(building blocks)是很优秀的。其不变的性质降低了复杂对象的设计难度。

不可变对象的缺点以及优化

  1. 不可变对象的唯一缺点:每次操作都需要创建新对象,在多步操作中造成性能问题。
  2. 优化:
    1. 在多步操作中使用可变的“伴随类”(mutable "companion class")。例如String类与String Buffer类。
    2. 预测哪些多步操作是经常被使用的,提供这些操作的官方方法进行优化。

最佳实践

  1. 提供公有的静态工厂方法(static factory method)并让构造器为私有。

    1. 可以提前检测输入数据的有效性,如果不合法可以直接避免创建对象。
    2. 可以缓存一些常用的对象,优化性能。
    3. 可以添加一些实用的功能。
  2. 制造不可变类的条件可以弱化为任何方法都不能造成对象外部表现的改变。这样我们可以创造一些内部的可变组件用于缓存,进而优化性能。

总结

  1. 设计一个类时首先考虑是否能让它不可变。
  2. 如果类不能做成完全不可变的,将其可变性限制到最低。
  3. 不要在静态工厂方法和构造器之外提供任何的初始化方法。

原文地址:https://www.cnblogs.com/QEStack/p/8453626.html

时间: 2024-11-05 16:08:41

《Effective Java》读书笔记 - 最小化类的可变性的相关文章

Effective Java读书笔记(4 类和接口)

4.1 使类和成员的可访问性最小化 要区别设计良好的模块和设计不好的模块,最重要的因素在于,这个模块对于外部的其他模块而言,是否隐藏其内部数据和其他实现细节.设计良好的模块会隐藏所有的实现细节,把它的API与它的实现清晰的隔离开来,然后模块之间只通过API进行通信,一个模块不需要知道其他模块内部的工作情况,这个概念被称为信息隐藏或封装,是软件设计的基本原则之一. 4.2 在公有类中使用访问方法而非公有域 坚持面向对象程序设计思想:如果类可以在它所在的包的外部进行访问,就提供访问方法,以保留将来改

Effective Java 读书笔记(2创建和销毁对象)

第一章是引言,所以这里不做笔记,总结一下书中第一章的主要内容是向我们解释了这本书所做的事情:指导Java程序员如何编写出清晰.正确.可用.健壮.灵活和可维护的程序. 2.1考虑用静态工厂方法代替构造器 静态工厂方法与构造器相比有四大优势: (1)静态工厂方法有名称,具有适当名称的静态工厂方法易于使用.易于阅读: (2)不必每次在调用它们的时候都创建一个新的对象: (3)可以返回原返回类型的任何子类型的对象: (4)在创建参数化类型实例的时候,它们使代码变得更加简洁. 同时静态工厂方法也有两大缺点

Effective Java读书笔记(3对于所有对象都通用的方法)

3.1 覆盖equals时请遵守通用约定 什么时候应该覆盖Object.equals()方法呢? 如果类具有自己特有的"逻辑相等"概念(不同于对象等同的概念),而且超类还没有覆盖equals以实现期望的行为,这时我们就需要覆盖equals方法. Object.equals()方法具有自反性.对称性.传递性.一致性和与null比较返回false的特点. 实现高质量equals方法的诀窍: (1)使用==操作符检查"参数是否为这个对象的引用".如果是,则返回true,这

[Effective Java 读书笔记] 第三章类和接口 第十二条

第十二条 使类和成员的可访问性最小化 总得来说,我们应该尽量将成员的访问范围限制到最小!有利于解耦,开发.测试和优化都能够更加独立. 对于成员(域,方法,嵌套类和嵌套接口),有四种可能的访问级别,访问范围从小到大: 1. private,只有声明成员的类的内部才能访问 2. 包级私有的,声明成员的类所在的包内的任何类都可以访问,如果成员不显示声明访问级别,就是这种级别,所以也成为缺省访问级别 3.protected,声明成员的类及其子类可以访问,并且声明类所在包中的任何类也可以访问 4.publ

effective java 读书笔记——类和接口

上周因为准备考试等一堆原因,没空看书,今天补上一点. 类和接口是java程序设计语言的核心,它们也是java语言的基本抽象单元,java语言提供了很多强大的基本元素,供程序员设计类和接口,这一章讲的是一些指导原则,可以设计出更加有用,健壮和灵活的类和接口. 第1条:使类和成员的可访问性最小化 首先说一个概念:模块之间只能通过它们的API进行通信,一个模块不需要知道其他模块的内部工作情况,这个概念叫做“信息隐藏”,或者“封装”.(对,这就是面向对象的中封装继承多态三大特性之一的封装) 信息隐藏之所

Effective Java 读书笔记之三 类和接口

一.使类和成员的可访问性最小化 1.尽可能地使每个类或者成员不被外界访问. 2.实例域决不能是共有的.包含公有可变域的类不是线程安全的. 3.除了公有静态final域的特殊情形之外,公有类都不应该包含公有域,并且确保公有静态final域所引用的对象不可变. 二.在公有类中使用访问方法而非公有域 1.如果类是包级私有的,或者是私有的嵌套类,直接暴露它的数据域并没有本质的错误. 2.公有类永远都不应该暴露可变的域. 三.使可变性最小化 不可变的类是指其实例不能被修改的类.为使类不可变,需要遵循以下五

Effective java读书笔记

2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己 计在16年要看12本书,主要涉及java基础.Spring研究.java并发.JVM.分布式之类的.在今年面试的时候深受打击,到处都是问分布式.集群的?难道现在工作两三年的都这么牛逼了?都在搞分布式.集群之类的? 2016书单如下: 1.深入理解Java虚拟机:JVM高级特性与最佳实践---(已看,预计今年看三遍) 2.Oracle查询优化改写技巧与案例---(已看) 3.Ef

Effective Java 读书笔记之七 通用程序设计

一.将局部变量的作用域最小化 1.在第一次使用变量的地方声明 2.几乎每个变量的声明都应该包含一个初始化表达式:try-catch语句是一个例外 3.使方法小而集中是一个好的策略 二.for-each循环优先于传统的for循环 1.for-each循环在简洁性和预防bug方面有着传统的for循环无法比拟的优势,而且没有性能损失. 2.三种不能使用for-each循环的情况: a.过滤:需要显式的迭代器的remove方法 b.转换:需要显式的迭代器或数组索引,以便设定值 c.平行迭代:多个相关集合

effective java读书笔记1——创建和销毁对象

今天刚开始读effective java,中文版的读起来很拗口,但感觉收获很多. 另外,这本书的内容是针对Java 1.5和1.6的. 在这里整理一下第2章:创建和销毁对象 的内容. 第一条:考虑用静态工厂方法代替构造器 这一条针对的情景是要获得类的实例时.一般说来,想要获得类的实例,都是通过构造函数(书里叫做构造器). 最常见的构造函数是这样的,没有返回参数,名字和类名相同. public class A{ public A(int a){ //构造函数内容 ... } } 而所谓的静态工厂,