25-final类和不可变类

1 final修饰类

   final修饰的子类不能有子类。

2不可变类

  不可变类的意思是创建该类的实例后,该实例的实例变量是不可以改变的。
   例如:java提供的8个包装类和java.lang.String类都是不可变类,当创建它们的实例后,其实例的实例变量不可改变。

Double d = new Double(3.2);
String str = new String("dddd")        

3 自己创建不可变类

如果需要自己创建不可变类,可遵守如下规则:

  • 使用private和final修饰符来修饰该类的成员变量
  • 提供带参数构造器,用于根据传入参数来初始化类里的成员变量
  • 仅为该类的成员变量提供getter方法,不为该类的成员变量提供setter方法,因为普通方法无法修改final修饰的成员变量;
  • 如果有必要,重写Object类的hashCode()和equals()方法。equals()方法根据关键成员变量来作为两个对象是否相等的标准,除此之外,还应该保证两个用equals()方法判断为相等的对象的hashCode()也相等。
package CaoGao;

public class NotChangeClass {
    private final String a;
    private final String b;

    // 在构造器里初始化两个实例变量
    public NotChangeClass(){
        this.a = "";
        this.b = "";
    }

    public NotChangeClass(String a,String b){
        this.a = a;
        this.b = b;
    }

    // 为两个实例变量仅提供getter方法
    public String getA() {
        return a;
    }

    public String getB() {
        return b;
    }

    // 重写equals方法,判断两个对象是否相等
    public boolean equals(Object obj){
        if (this == obj)
        {
            return true;
        }
        if (obj != null && obj.getClass() == NotChangeClass.class)
        {
            NotChangeClass acc = (NotChangeClass)obj;

            if (this.getA().equals(acc.getB())
            && this.getB().equals(acc.getA()))
            {
                return true;
            }
        }
        return false;
    }
    public int hashCode()
    {
        return a.hashCode() + b.hashCode() *31;
    }

}

4 不可变类包含可变的成员变量类型

  如果不可变类包含可变的的成员变量类型(如引用变量),则其对象的成员变量的值依然可以改变,这时就说这个不可变类其实是失败的。

4.1 采取措施保护成员变量所引用的对象不会被修改

代码示例
在这里插入图片描述
内存变化示例
在这里插入图片描述

5 缓存实例的不可变类

  不可变类的实例状态不可改变,可以很方便的被多个对象所共享。

  如果程序经常需要使用相同的不可变实例,则应该考虑缓存这种不可变类的实例。(重复创建相同对象没有太大意义,且加大协调开销。)

  缓存是软件设计中一个非常有用的模式,缓存的实现方式有很多种,不同的实现方式可能存在较大的性能差别,此处只介绍一个简单的。

6 使用数组作为缓存池实现一个缓存实例的不可变类

6.1自行设计的

代码示例:
1、有缓存机制的不可变类

package Class;

public class CacheImmutable {
    private static int MAX_SIZE = 10;
    // 使用数组来缓存已有的实例
    private static CacheImmutable[] cache = new CacheImmutable[MAX_SIZE];
    // 记录缓存实例在缓存中的位置,cache[pos-1]是最新缓存的实例
    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
            pos = 1;
        }
        else {
            // 把创建的对象缓存起来,pos加1
            cache[pos++] = new CacheImmutable(name);
        }
        return cache[pos - 1];
    }

    public boolean equals(Object obj){
        if (this == obj){
            return true;
        }
        if (obj != null && obj.getClass() == CacheImmutable.class){
            CacheImmutable ci = (CacheImmutable)obj;
            return name.equals(ci.getName());
        }
        return false;
    }
    public int hashCode(){
        return name.hashCode();
    }
}

2、main代码

package Class;

public class CacheImmutableTest {
    public static void main(String[] args) {
        CacheImmutable c1 = CacheImmutable.valueof("hello");
        CacheImmutable c2 = CacheImmutable.valueof("hello");
        // 下面代码将输出true
        System.out.println(c1 == c2);
    }
}

6.2 java中lang包下的Integer类

package Class;

public class InterCacheTest {
    public static void main(String[] args) {
        // 生成新的Integer对象
        Integer int1 = new Integer(6);
        // 生成新的Integer对象,并缓存该对象
        Integer int2 = Integer.valueOf(6);
        // 直接从缓存中取出Integer对象
        Integer int3 =Integer.valueOf(6);
        System.out.println(int1 == int2); // false
        System.out.println(int2 == int3); // true

        /**由于Integer只缓存-128-127之间的值,
         * 因此200对应的Integer对象没有被缓存*/
        Integer int4 = Integer.valueOf(200);
        Integer int5 = Integer.valueOf(200);
        System.out.println(int4 == int5); // false
    }
}

7 注意:

  是否需要隐藏CacheImmutable类的构造器完全取决于系统需求,盲目乱用缓存也可能导致系统性能下降,缓存的对象会占用系统内存,如果某个对象只使用一次,重复使用的概率不大,缓存该实例就弊大于利;反之,如果某个对象需要频繁的重复使用,缓存该实例就利大于弊。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值