版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
不可变类的意思是创建该类的实例后,该实例的实例变量是不可变的。
创建不可变类,可以遵守以下规则:
- 使用private和final修饰符来修饰成员变量。
- 提供带参数构造器,用于根据传入参数来初始化类里的成员变量。
- 仅为该类成员变量提供getter方法。
- 如果有必要,重写object类的hashcode()和equals()方法。
1,下面测试一段代码:
public class ImmutableStringTest {
public static void main(String[] args) {
String str1=new String("hello");
String str2=new String("hello");
System.out.println(str1==str2);
System.out.println(str1.equals(str2));
System.out.println(str1.hashCode());
System.out.println(str2.hashCode());
}
}
输出:
false
true
99162322
99162322
原因:==测试地址是否一样,equals主要测试值是否相等,hashcode()通过字符序列计算得到,所以值相等
总结而来就是:当程序创建一个对象后,该队象的实例变量的值不能被改变
2,我们将一个类的变量在另外一个类中创建,该怎末变成一个不可变类呢?
看下面的代码:
public class Name {
private String firstname;
private String lastname;
public Name(){};
public Name(String firstname,String lastname){
this.firstname=firstname;
this.lastname=lastname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getFirstname(){
return this.firstname;
}
public String getLastname(){
return this.lastname;
}
}
//创建不可变类时出现的误区
public class Person {
private final Name name;
public Person(Name name){
this.name=name;
}
public Name getName(){
return name;
}
public static void main(String[] args) {
Name n=new Name("悟空","孙");
Person p=new Person(n);
System.out.println(p.getName().getFirstname());
n.setFirstname("八戒");
System.out.println(p.getName().getFirstname());
}
}
当你输出后会发现,他的值从悟空变成八戒了
原因:这跟以前我讲用final修饰引用变量,然而他引用的对象的值却是可以改变的,但他的地址一直不变。来想想我们这个,在person类中name引用了该Name对象,就导致person对象的name的firstname会发生改变。
那么怎么改变呢?
看下面的代码:
public class Name {
private String firstname;
private String lastname;
public Name(){};
public Name(String firstname,String lastname){
this.firstname=firstname;
this.lastname=lastname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getFirstname(){
return this.firstname;
}
public String getLastname(){
return this.lastname;
}
}
public class Person1 {
private final Name name;
public Person1(Name name){
this.name=new Name(name.getFirstname(),name.getLastname());
}
public Name getName(){
return new Name(name.getFirstname(),name.getLastname());
}
public static void main(String[] args) {
Name n=new Name("陈勃","庞");
Person1 p=new Person1(n);
System.out.println(p.getName().getLastname()+p.getName().getFirstname());
n.setFirstname("某人");
System.out.println(p.getName().getLastname()+p.getName().getFirstname());
}
}
输出:
庞陈勃
庞陈勃
原因分析:在上面我们可以看到,我们在构造器和获得他的过程中都新建了一个对象,这样做就避免了用以前的对象,而那个对象被已经改变的过程,新建的过程就避免了这样。
3.缓存实例的不可变类
优点:当某个不变的实例变量被多个对象使用时就可以缓存他,这样就可以避免系统开销。
import java.util.concurrent.Callable;
/*
缓存不可变类对象
*/
public class CacheImmutale {
private static int MAX_SIZE = 10;
private static CacheImmutale [] cache= new CacheImmutale[MAX_SIZE];
private static int pos=0;
private final String name;
private CacheImmutale(String name){
this.name=name;
}
public String getName(){
return this.name;
}
public static CacheImmutale 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 CacheImmutale(name);
pos=1;
}
else {
cache[pos++]=new CacheImmutale(name);
}
return cache[pos-1];
}
public boolean equals(Object obj){
if(this==obj){
return true;
}
if(obj!=null&&obj.getClass()==CacheImmutale.class){
CacheImmutale ci=(CacheImmutale) obj;
return name.equals(ci.getName());
}
return false;
}
public int hashcode(){
return name.hashCode();
}
public static void main(String[] args) {
CacheImmutale c1=CacheImmutale.valueOf("hello");
CacheImmutale c2=CacheImmutale.valueOf("hello");
System.out.println(c1==c2);
}
}
上面的过程是没有封装的过程,相了解的可以看一下,我们如果用就可以直接写,例如Java提供的java.lang.Integer类就和面这个类似,
看下面的代码:
public class ItegerCacheTest {
public static void main(String[] args) {
//生成新的integer对象
Integer in1=new Integer(6);
//生成新的对象并且缓存他
Integer in2=Integer.valueOf(6);
//直接从缓存的地方进行提取
Integer in3=Integer.valueOf(6);
System.out.println(in1==in2);
System.out.println(in2==in3);
//由于integer只能缓存-128-127之间的值
//因此200不能被缓存
Integer in4=Integer.valueOf(200);
Integer in5=Integer.valueOf(200);
System.out.println(in4==in5);
}
}
理解:就是系统将对象进行了缓存,如果新创建的对象和原来一样,就从原来的缓存中拿出来。