您的位置:首页 > 编程语言 > Java开发

不可变类详解

2015-04-01 21:05 211 查看
不可变类(immutable)类的意思是说创建给雷的实例后,该实例的Field是不可改变的。Java提供的8个包装类和Java.lang.String类都是不可变类

如果需要自己创建自定义的不可变类

(1)使用private和final修饰该类的Field

(2)提供带参数的构造器,用于根据传入参数来初始化类里的Field

(3)仅为该类的Field提供getter方法,不要为给类的field提供setter方法

(4)如果有必要,重写Object的equals方法和hashcode方法

 

/*

自己定义了个不可变类

*/

 

public class Address

{

//不可变类的两个成员都是String类,是不可变类,即Address满足不可变类的第一个条件

private final String detail;

private final String postCode;

public Address()

{

}

//提供带参数的构造器

public Address(String detail, String postCode)

{

this.detail = detail;

this.postCode = postCode;

}

//提供了getter方法,不提供setter方法

public String getDetail()

{

return this.detail;

}

public String getPostCode()

{

return this.postCode();

}

//重写了Object类的equals()方法和hashCode()方法

public boolean equals(Object obj)

{

if (obj == this)

{

return true;

}

if (obj != null && Address.class == obj.getClass())

{

Address ad = (Address)obj;

if (this.getAddress() == ad.getAddress() && this.getpostCode() == obj.getPostCode())

{

return true;

}

}

return false;

}

}

public boolean hashCode()

{

return detail.hashCode()+postCode.hashCode() * 31;

}

 

 

当一个内的内部是普通类的引用时,这个普通类可以随意更改类的Field,当使用final修饰引用变量时,仅表示这个引用类型变量不可被重新赋值,但引用类型变量所指向的对象依然可改变,这给就产生了一个问题:当创建不可变类时,如果它包含的Field的类型是可变的,那么其对象的Field依然是可变的---这个不可变类其实是失败的

 

 

class Name

{

private String firstName;

private String lastName;

public Name()

{

}

public Name(String firstName, String lastName)

{

this.firstName = firstName;

this.lastName = lastName;

}

public String getFirstName()

{

return this.firstName;

}

public String getLastName()

{

return this.lastName;

}

public void setFirstName(String firstName)

{

this.firstName = firstName;

}

public void setLastName(String lastName)

{

this.lastName = lastName;

}

}

 

public class Person

{

private final Name name;

public Person(Name name)

{

this.name = name;

}

public Name getName()

{

return this.name;

}

public static void main(String[] args)

{

Name n = new Name("陈", "奇");

Person p = new Person(n);

System.out.println(p.getName().getFirstName());

n.setFirstName("chen");

System.out.println(p.getName().getFirstName());

}

}

 

 

不难发现,Person对象的name的fiestName已经改变

 

为了保持Person对象的不可变类,必须保护好Person对象的引用类型Field:name;让程序无法访问到Person对象的name field,也就无法利用name Field的可变性来改变Person对象

 

public Person(Name name)

{

this.name = new Name(name.getFirstName(), name.getLastName());

}

public Name getName()

{

return new Name(name.getFirsName(), name.getLastName());

}

 

把Name对象的实例重新复制一份传入到Person对象的name Field,这样即使更改name,也改变不了Person对象的name实例

 

缓存实例的不可变类

不可变类的实例状态不可改变,可以很方便的呗多个对象共享,如果程序需要使用相同的不可变类实例,则应考虑缓存这种不可变类的实例,毕竟重复创建相同的对象没有太大的意义

class CacheImmutable

{

private static int MAX_SIZE = 10;

private static CacheImmutable[] cache = new CacheImmutable[MAX_SIZE];

private static int pos = 0;

private final String name;

private CacheImmutable(String name)

{

this.name = name;

}

public String getName()

{

return name;

}

public static CacheImmutable valueOf(String name)

{

for (int i=0; i<MAX_SIZE; ++i)

{

if (cache[i] != null && cache[i].getName().equals(name))

{

return cache[i];

}

}

if (pos == MAX_SIZE)

{

cache[0] = new CacheImmutable(name);

pos = 1;

}

else

{

cache[pos++] = new CacheImmutable(name);

}

return cache[pos-1];

}

public boolean equals(Object obj)

{

if (this == obj)

{

return true;

}

if (obj != null && CacheImmutable.class == obj.getClass())

{

CacheImmutable ci = (CacheImmutable)obj;

return name.equals(ci.getName());

}

return false;

}

public int hashCode()

{

return name.hashCode();

}

}

 

public class CacheImmutableTest

{

public static void main(String[] args)

{

CacheImmutable c1 = CacheImmutable.valueOf("hello");

CacheImmutable c2 = CacheImmutable.valueOf("hello");

System.out.println(c1 == c2);

}

}

 

 

Java.lang.Integer类也提供了缓存机制,如果采用new构造器来创建对象,则每次返回全新的Integer对象,如果采用valueOf()方法来创建Integer对象,则会缓存该方法创建的对象

 

static final Integer[] cache = new Integer[-(-128) + 127 + 1];

static {

for (int i=0; i<cache.length; i++)

{

cache[i] = new Integer(i-128);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  不可变类 java