zoukankan      html  css  js  c++  java
  • Java技术——String类为什么是不可变的

    0. 前言  

    如果一个对象,在它创建完成之后不能再改变它的状态,包括对象内的成员变量、基本数据类型的值等等。那么这个对象就是不可变的。众所周知String类就是不可变的。转载请注明出处为SEU_Calvin的博客

     

    1. String类为什么是不可变的 

    首先看一下String类的源码中:

    //JDK1.6
    public final class String  
        implements java.io.Serializable, Comparable<String>, CharSequence  
    {  
        /**用于存储字符的数组 */  
        private final char value[];  
        /** 表示String在这个value数组中的起始位置 */  
        private final int offset;  
        /** 字符个数*/  
        private final int count;  
        /** 哈希值 */  
        private int hash; // Default to 0  
      //...
    }
    
    //JDK1.7
    public final class String  
        implements java.io.Serializable, Comparable<String>, CharSequence {  
        /**用于存储字符的数组 */  
        private final char value[];  
        /** 哈希值 */  
        private int hash; // Default to 0  
      //....
    }
    

    从源码中可以看出,无论是JDK6还是7,虽然内部成员有所改变,但是String类终究是对字符数组的封装。而且value也只是一个引用,它指向一个真正的数组对象。源码中并没有提供valueset方法,因此String类一旦初始化,外部便无法修改,同时value被修饰为 private final,在String类内部也无法改变。所以String对象是不可变的。

    我们常用的字符串方法比如substringreplacereplaceAlltoLowerCase方法,给人的感觉好像是可以改变String内的值,但是这些方法的内部其实在完成逻辑后创建了一个新的String对象并返回。以replace为例,以下是一个简单的例子证明这一点。

    String s = "DF2lian";  
    s = s.replace('F', 'A');  
    System.out.println("s = " + s);  //输出DA2lian
    
    String s = "DF2lian";  
    s.replace('F', 'A');  
    System.out.println("s = " + s);  //输出DF2lian
    


    2. String类真的不可变吗 

    从上文可知String的成员变量valueprivate final修饰的,初始化后不可再改变并且不能再指向其他数组对象。但是value本身是一个引用变量,而不是真正的对象。那么我们就可以通过反射得到String对象中的value属性,进而改变value引用的数组的结构。下面是实例代码:

    String s = "DF2lian";   
    //获取String类中的value字段  
    Field valueFieldOfString = String.class.getDeclaredField("value");  
    //改变value属性的访问权限  
    valueFieldOfString.setAccessible(true);  
    //获取s对象上的value属性的值  
    char[] value = (char[]) valueFieldOfString.get(s);  
    //改变value所引用的数组中某个字符  
    value[1] = 'R';  
    System.out.println("s = " + s);  //输出DR2lian
    

  • 相关阅读:
    第七周进度报告
    解析极限编程阅读笔记02
    解析极限编程阅读笔记01
    第六周进度报告
    合作开发项目-地铁线路查询
    构建之法阅读笔记03
    关于DeferredResult的思考
    java实现任务调度
    java里面如何提升编写速度
    收集整理mysql数据库设计规范与原则
  • 原文地址:https://www.cnblogs.com/qitian1/p/6461459.html
Copyright © 2011-2022 走看看