zoukankan      html  css  js  c++  java
  • Java 不可变类

    Java 不可变类

    immutable object 不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值。
    如JDK内部自带的很多不可变类:Interger、Long和String等。
    ** 不可变类,指的是 该类的实例不可变,而非指向该实例的引用的不可变**

    优点

    • 线程安全
    • 当一个对象是不可变的,那么需要拷贝这个对象的内容时,就不用复制它的本身而只是复制它的地址,复制地址(通常一个指针的大小只需要很小的内存空间,具有非常高的效率。同时,对于引用该对象的其他变量也不会造成影响。
    • 此外,不变性保证了hashCode 的唯一性,因此可以放心地进行缓存而不必每次重新计算新的哈希码。而哈希码被频繁地使用, 比如在hashMap 等容器中。将hashCode 缓存可以提高以不变类实例为key的容器的性能。

    如何实现

    1. 所有成员都是private final;
    2. 不提供改变成员的方法,setter ;
    3. 确保所有方法不会被重载, 使用final class 强不可变类,或 所有方法加上final;
    4. 如果一个类的成员,不是基本类型primitive type或不可变类, 则在成员初始化和 getter方法时,深度拷贝(复制类的实例而非引用);
    5. 如果有必要,重写hashCode equals, 应保证在equals相等时,hashCode也相等。

    通过反射修改String 对象的值

    //用反射获取 修改string 值;

        public static void main(String[] args){
            String s= "Hello World";
            System.out.println(" s: "+s);
            
            try {
                Field value = String.class.getDeclaredField("value");
                value.setAccessible(true);
                char[] vs = (char[]) value.get(s);
    
                vs[5] = 'F';
                
                System.out.println(" s after: "+ s);
    
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    
    
    

    如果需要设计一个不可变类,尤其要注意其引用类型Field,如果其引用类型Field的类是可变的,就必须采取必要的措施来保护该Field所引用的对象不会被修改,这样才能创建真正的不可变类。

    class Name{
        private String first;
        private String last;
    
        public Name(){}
    
        public Name(String f, String l){
            first = f;
            last  = l;
        }
    
        public void setFirst(String first) {this.first = first;}
        public String getFirst() {return first;}
    
        public String getLast() {return last;}
        public void setLast(String last) {this.last = last;}
    
        @Override
        public String toString() {
            return "Frist: "+first + " last: " + last;
        }
    }
    
    class Person{
        private final Name name;
    
        public Person(Name name){
            this.name = new Name(name.getFirst(),name.getLast());
        }
    
        public Name getName() {
            return new Name(name.getFirst(),name.getLast());
        }
    
        @Override
        public String toString() {
            return getClass().getName() + "@[name="+this.getName() +"]";
        }
    }
    
    public class ImmutableTestTwo {
        public static void main(String[] args){
    
            Name n1 = new Name("悟空", "孙");
            Person p1 = new Person(n1);
            System.out.println(p1.getName().getFirst());
            n1.setFirst("八戒");
            System.out.println(p1.getName().getFirst());
        }
    }
    
    

    或者做如下修改:
    将Name类的setter方法删除掉,这样Name类是不可变的类,Person类也是不可变的类。

    参考资料

    从final的作用剖析String被设计成不可变类的深层原因

    创建正真的Java不可变类

  • 相关阅读:
    小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-9.使用JWT生成用户Token回写客户端
    小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-8.用户模块开发之保存微信用户信息
    小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-7.授权登录获取微信用户个人信息实战
    小D课堂-SpringBoot 2.x微信支付在线教育网站项目实战_5-6.微信扫码登录回调本地域名映射工具Ngrock
    Vmware Briged方式使虚拟机上网
    设置VIM的配色方案
    SecureCRT辅助解决方案
    ARM标准汇编与GNU汇编
    arm:c语言和汇编混合编程
    assert()用法
  • 原文地址:https://www.cnblogs.com/ironbrady/p/6669653.html
Copyright © 2011-2022 走看看