Immutable Pattern是指那些有着能够保证实例状态绝不会改变的类(immutable类),在访问这样的实例中,可以省去使用共享机制所会浪费的时间。如果能妥善使用可以提高程序性能。
*一个使用Immutable Pattern的Person类的例子
package day18;
public final class Person {//final不是Immutable Pattern的必要条件
private final String name;
private final String address;//这两个private不是Immutable Pattern的必要条件
public Person(String name,String address)
{
this.name=name;
this.address=address;
}
public String getName()
{
return name;
}
public String getAddress()
{
return address;
}
public String toString()
{
return "[Person:name="+name+",address="+address+"]";
}
}
//用来显示Person实例的线程类
package day18;
public class PrintPersonThread extends Thread {
private Person person;
public PrintPersonThread(Person person)
{
this.person=person;
}
public void run()
{
while(true)
{
//当字符串与实例以+运算符连接时,会自动调用实例的toString()方法
System.out.println(Thread.currentThread().getName()+"prints"+person);
}
}
}
package day18;
public class Main {
public static void main(String[] args) {
Person lzh=new Person("lzh","China");
new PrintPersonThread(lzh).start();
new PrintPersonThread(lzh).start();
new PrintPersonThread(lzh).start();
}
}
部分运行结果:
Thread-2prints[Person:name=lzh,address=China]
Thread-2prints[Person:name=lzh,address=China]
Thread-2prints[Person:name=lzh,address=China]
Thread-2prints[Person:name=lzh,address=China]
Thread-1prints[Person:name=lzh,address=China]
Thread-2prints[Person:name=lzh,address=China]
Thread-1prints[Person:name=lzh,address=China]
Thread-1prints[Person:name=lzh,address=China]
Person类被声明成final是指Person类不允许别人定义它的子类,这不是Immutable Pattern的必要条件,但是预防子类可能修改字段的值是一种安全措施。
Person类的name字段与address字段被设置成private,即只有类内可以看得到,这也不是Immutable Pattern的必要条件。以上可以明确表达程序员的意图,就算不小心写了指定的程序代码,编译器会替我们找出错误。因为删除了synchronized,这样做是为了保护类的不变性,如果再失去不变性,类的安全性也丧失了。
何时使用Immutable Pattern?
①当实例产生后,状态不再变化时。
不需要定义setter方法(如setName、setAddress)是重点所在。
②实例需要共享,而且访问很频繁时。
因为该Pattern不需要使用synchronized保护,这可以在不丧失安全性和生命性的前提下,提高程序的执行性能。
成对的mutable类与immutable类
假设在程序代码里发现一个类setter方法还是有被用到,这种时候可以把观察整个程序如何运用这个类,根据使用setter方法的情况和不使用setter方法的情况,把这个类二分成mutable类和immutable类,并且设计成从这两个类中的任何一个实例可以构造出另一个类的实例。
例如Java标准类链接库里就有java.lang.StringBuffer类和java.lang.String类是成对的mutable类与immutable类。前者是可以自由改写的,为确保改写安全在改写操作时都有synchronized保护;后者无法修改,但引用的速度比较快(另:若要由多个字符串建立出新的字符串,StringBuffer类的速度会比String快)。并且两个类都有以对方为参数的构造器。
注意下面两个操作也有可能危及类的不变性:
①直接以getter方法返回字段所保存的实例。
getter方法应用来返回字段值。
②将构造器的参数传入的实例,直接存进字段里。
标准链接库里使用到的Immutable Pattern
表示字符串的java.lang.String类
表示颜色的java.awt.Color类
包装类(wrapper class):
java.lang.Boolean
java.lang.Byte
java.lang.Character
java.lang.Double
java.lang.Float
java.lang.Integer
java.lang.Long
java.lang.Short
java.lang.Void(这个类是用来保存基本类型void的Class对象的实例,使用在Reflection与serialization等机制上)
对final的说明
final 类
当类被声明成final时,无法定义这个类的子类。因为无法定义子类,所以final类声明的方法也不会被覆盖(override)。
final方法
若将实例方法声明成final时,这个方法无法被子类覆盖(override)。若将类方法声明成final时,这个方法无法被子类隐藏(hide)。(注意:实例方法被子类的方法覆盖时,实际调用哪个方法是在执行时决定的;类方法被子类的方法隐藏时,实际调用哪个方法是在编译时决定的)
final字段
Final字段的值只能指定一次
要将值指定给final非静态变量字段,有下面两种方法:
①在声明字段时直接赋初值
class OK{
final int value=123;
}
②在构造器中将值赋给blank final字段
class OK{
final int value;
OK()
{
this.value=123;
}
}
要将值指定给final静态变量字段,有下面两种方法:
①在声明字段时直接赋初值
class OK{
static final int value=123;
}
②在static块(静态初始化子)中将值赋给blank final字段
class OK{
static final int value;
static
{
value=123;
}
}
final变量与final参数
final变量的值只能指定一次,final参数的值一次都不能指定,因为当方法被调用时,已经有值传入进去了。