• 可变对象(immutable)和不可变对象(mutable)


    可变对象(immutable)和不可变对象(mutable)

    这个是之前一直忽略的一个知识点,比方说说起String为什么是一个不可变对象,只知道因为它是被final修饰的所以不可变,而没有抓住不可变三个字的重点:

    1、不可变对象就是那些一旦被创建,它们的状态就不能被改变的对象,每次对它们的改变都是产生了新的对象

    2、可变对象就是那些创建后,状态依然可以被改变的对象

    举个例子:String和StringBuilder,String是不可变的,因为每次对String对象的修改都将产生一个新的String对象,而原来的对象保持不变;StringBuilder是可变的,因为每次对StringBuilder的修改都作用于该对象本身,并没有新的对象产生。如果这么说还不够清楚,截取两段源码,首先是String的concat方法,用户向已有的字符串后面拼接新的字符串:

    复制代码
     1 public String concat(String str) {
     2     int otherLen = str.length();
     3     if (otherLen == 0) {
     4         return this;
     5     }
     6     char buf[] = new char[count + otherLen];
     7     getChars(0, count, buf, 0);
     8     str.getChars(0, otherLen, buf, count);
     9     return new String(0, count + otherLen, buf);
    10     }
    复制代码

    看到第9行,new了一个新的String出来。然后看一下StringBuilder,StringBuilder最常用的应该就是append方法了,append一个字符串的时候会调用StringBuilder的父类AbstractStringBuilder的append方法:

    复制代码
    1 public AbstractStringBuilder append(String str) {
    2         if (str == null) str = "null";
    3         int len = str.length();
    4         ensureCapacityInternal(count + len);
    5         str.getChars(0, len, value, count);
    6         count += len;
    7         return this;
    8     }
    复制代码

    第5行的这个value就是一个char型数组"char[] value;",每次对StringBuilder的操作都是对value的改变。

    不可变的对象对比可变对象有两点优势:

    1、保证对象的状态不被改变

    2、不使用锁机制就能被其他线程共享

    实际上JDK本身就自带了一些不可变类,比如String、Integer、Float以及其他的包装类,判断的方式就是看它们真正的那个对象是不是final的就好了。

    我们自己也可以创建不可变对象,创建不可变对象应该遵循几个原则:

    1、不可变对象的状态在创建之后就不能发生改变,任何对它的改变都应该产生一个新的对象

    2、不可变对象的所有属性应该都是final的

    3、对象必须被正确地创建,比如对象引用在创建过程中不能泄露

    4、对象应该是final的,以此来限制子类继承父类,以避免子类改变了父类的不可变特性

    使用不可变类的好处:

    1、不可变类是线程安全的,可以不被synchronized修饰就在并发环境中共享

    2、不可变对象简化了程序开发,因为它无需使用额外的锁机制就可以在线程之间共享

    3、不可变对象提高了程序的性能,因为它减少了synchronized的使用

    4、不可变对象时可以被重复利用的,你可以将它们缓存起来,就像字符串字面量和整型数值一样,可以使用静态工厂方法来提供类似于valueOf这样的方法,它可以从缓存中返回一个已经存在的不可变对象,而不是重新创建一个

    不可变对象虽然好,但是它有一个很大的缺点就是会制造出大量的垃圾,给垃圾收集带来很大的麻烦,由于它们不能被重用而且,所以不可变对象的使用依赖于开发人员合理的使用。另外,不可变对象也有一些安全问题,比如密码就建议不要用String,因为:

    如果密码是以明文的形式保存成字符串 ,那么它将一直留在内存中,直到垃圾收集器把它清除。而由于字符创被放在字符串缓存池中以方便重用,所以它就可以在内存中被保留很长时间,而这将导致安全隐患,因为任何能够访问内存的人都可以清晰地看到文本中的密码,这也是为什么总是应该用加密的形式而不是明文来保存密码。由于字符串是不可变的,所以没有任何方式可以修改字符串的值,因为每次修改都将产生新的字符串,而如果使用char[]来保存密码,就可以将其中所有元素都设置为空或者是零。所以将密码保存到字符数组中很明显地降低了密码被窃的风险。

  • 相关阅读:
    英语翻译预测
    mybatis 实现增删改查
    jsp项目 在maven中使用,web.xml pome.xml 的配置
    来整理一份我觉得比较重要的小概念
    前端开发项目资源网站
    css 选择器符号
    css实现三栏布局的几种方法及优缺点
    MVC设计思想
    WebSocket 与 Polling , Long-Polling , Streaming 的比较!
    移动端视频h5表现问题汇总
  • 原文地址:https://www.cnblogs.com/haitaofeiyang/p/7725274.html
Copyright © 2020-2023  润新知