1、java语言支持四种类型:
(1)接口(interface):
(2)类(class):
(3)数组(Array):
(4)基本类型(primitive):唯一非引用类型(reference type)
2、方法签名:包括方法名称、参数,不包括返回值;
《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《
3、不可变类
- 实例不可被修改类
- 每个实例中包含的所有信息,必须在创建的时候提供,并在整个生命周期不可变
- 例如:String、基本类型包装类、BigInteger、BigDecimal
- 比可变类,易于设计使用,不易出错、更加安全
4、成为不可变类,五条规则
(1)不提供任何修改对象状态的方法
(2)保证类不会被扩展
- 这样可以防止粗心、恶意子类,假装对象状态已经改变;
- 防子类化,一般使用 final 类
(3)所有的类都是 final
- 通过系统的强制,表明意图
(3.1)不可变类变成 final 的另一种做法:
- 使不可变类所有构造方法都变成私有或包级私有,添加公有静态工厂,替换公有构造器
(4)所有域都私有
- 技术上允许不可变类具有公有 final 域(域包含基本类型值或 不可变对象引用)
- 不建议上述做法原因:以后版本无法改变内部表示法
(5)确保对任何可变组件的互斥访问
- 如果类具有可变对象的域,须保证客户端无法或者这些对象的引用
- 不要用客户端提供的对象引用初始化 可变对象的域
- 不要从任何访问方法返回该对象引用
- 在构造器、访问方法、readObject方法(76条)中,请使用保护性拷贝(39条)
5、函数方式的模式
- 对操作数进行运算,但不修改,返回新创建的实例
- 大多数不可变类都是用该模式
- 该做法带来了不可变性
- 约束关系在整个生命周期都不变,不需要额外代码维护约束关系
6、不可变对象本质上是线程安全的,且不要求线程同步
- 多线程并发访问不可变类对象,不会破坏对象,线程安全最容易实现
- 不可变对象可以被自由的共享
- 鼓励客户端尽可能重用现有实例(简单实现:频繁用到的值,提供公有静态 final 常量)
- 对不可变类提供静态工厂<1条>,缓存公用频繁使用的实例
- 基本类型包装类、BigDecimal等就有这样静态工厂
- 使用静态工厂而不是公有构造器,以后添加缓存更灵活
7、不可变对象可以被自由的共享
- 永远不需要进行保护性拷贝<39条>
- 不应该对不可变类提供 clone 方法或 拷贝构造器<11条>
- String类有拷贝构造器,尽量不要使用<5条>
8、不仅可以共享不可变对象,可以共享内部信息
- 不可变类BigInteger,在使用negate()获得相反数时,内部mag指向原有对象的mag数组
- 因为是不可变类,对象不会被修改才可以这么操作
9、不可变对象真正缺点:
- 对于每一个单独的值都需要一个单独的对象;
- 比如:一个百万位的BigInteger,运算时需要不停创建新对象,性能消耗巨大;
- BitSet 则允许固定时间内,改变某一位
10、如果不可预测,提供公有可变嵌套
- String类的可变公有嵌套:StringBuild(和已经基本废止的StringBuffer)
11、如果可预测,可以采用内部可变对象,存取中间值
- 这样,不用每一步都创建不可变对象
12、BigInteger和BigDecimal刚北边写出来时,不可变类必须是 final 未得到广泛认同
- 这俩类,存在被继承和被篡改的风险
13、不可变类没有方法会修改对象,所有域必须是 final
- 为提高性能可以有非 final 的域:第一次运算时将开销昂贵的结果保存起来,下次直接用
- 不可变性,保证了结果的正确性
14、序列化功能一条告诫:
- 不可变类实现了Serializable接口,需要显式readObject等4个方法
- 攻击者可能从不可变类创建可变对象<76条>
15、没有好的理由,类就要做成不可变得
16、类不能做成不可变的,也要尽量限制其可变性;
17、除非有好的理由,每个域都应该是 final 的
18、构造器和静态工厂外,不应再提供公有初始化方法
19、不可变类不要提供重新初始化方法