一、不可变类
不可变类指的是一个对象被创建出来之后,在它的整个生命周期之中,它的成员变量就不能被修改了,它有点类似于常量,只允许别的程序读,不允许别的程序进行修改。 在java中,所有的包装类,都是不可变类如Integer/Float等。
如String类是不可变类,平时咱写的s+="helloword"这种操作并不是吧原来的字符串修改了,而是在内存中新创建了一个String对象,然后让s指向了它,而原来的字符串还是存在内存空间中的。
创建一个不可变类需要遵守的五条规则:
- 所有的成员变量都使用
private来修饰 - 不提供修改器方法set,只提供构造函数,一次生成永远不变
- 确保方法不会被子类覆盖,可以用
final修饰类,也可以用final修饰方法 - 如果一个成员变量不是不可变量,那么在提供访问器方法get的时候,需要返回
clone的内容 - 有必要的话可以重写
equal和hashcode,比较内容相同时,hashcode也相等,这样确认该类能正确使用hashmap等容器
不可变类的缺点
- 会因为值不同而创建新的对象
- 在常量池中被共享,即使这个对象不再使用(如密码),它也会在内存中存在一段时间,这时候有权限访问memory dump的程序都能访问到这块内容,就可能把敏感数据暴露出去。因此存密码用字符数组会更安全,一旦不再使用密码之后就可以手动把字符数组设置为空。
二、==和equal
对于==,基础类型比较值,引用类型比较地址。
如果没有重写对象中的equal()方法,那equal()是等价于==的。
开发人员可以通过重写equal()方法来决定什么类的比较逻辑。
这里得提到hashcode(),如果没有重写hashcode()方法,那么任何对象的hashcode都不相等。 同时在重写了equal()方法之后没有重写hashcode()方法的话,就无法与基于hash的集合类结合一起正常运行。
三、static
static关键字主要有两个作用:
- 为某一个特定数据类型或者对象分配单一的储存空间,与创建对象的个数无关。
- 实现某个方法或者属性与类关联,而不是对象
特点:被修饰的部分会随着类的加载而加载,不会重复加载,执行的顺序在main方法前,在jvm中存在与方法区。
四、final
三句话:
- 被修饰的属性不可变
- 被修饰的方法不能被重写
- 被修饰的类不能被继承
需要注意的是,修饰的属性,如果是引用类型的话,是引用不可变,而不是对象不可变。
五、transient
被transient关键字修饰的属性,不会被序列化。
序列化的特点:
- 如果一个类能被序列化,那它的子类也可以序列化。
- static、transien修饰的属性不能序列化
六、volatile
保证线程安全中的可见性和有序性,不能保证原子性。
实现是基于内存栅栏:
一个volatile数据被修改的时候,jvm会执行一个Write-Barrier操作,把当前工作内存的数据写入主存,并且让引用了该地址的数据变成脏数据,那么其他程序去读取该数据时,发现工作内存的是脏数据啦,就回去主存中取,这就保证了可见性。
有序性是因为volatile修饰的属性不会被jvm重排序。