Java学习之不可变类以及缓存实例的不可变类

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_43271086/article/details/91861214

不可变类的意思是创建该类的实例后,该实例的实例变量是不可变的。

创建不可变类,可以遵守以下规则:

  1. 使用private和final修饰符来修饰成员变量。
  2. 提供带参数构造器,用于根据传入参数来初始化类里的成员变量。
  3. 仅为该类成员变量提供getter方法。
  4. 如果有必要,重写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);

    }
}

理解:就是系统将对象进行了缓存,如果新创建的对象和原来一样,就从原来的缓存中拿出来。

猜你喜欢

转载自blog.csdn.net/weixin_43271086/article/details/91861214