String类源码及其补充解析

String类源码及其补充解析

String源码解析具体内容详见转载: http://www.hollischuang.com/archives/99
补充解析:
1:关于value
引用
       /**值用于字符存储,---String内部的第一个属性*/
        private final char value[ ];
        这是一个字符数组,并且是final类型,他用于存储字符串内容,从fianl这个关键字中我们可以看出,String的内容一旦被初始化了是不能被更改的。 虽然有这样的例子: String s = “a”; s = “b” 但是,这并不是对s的修改,而是重新指向了新的字符串, 从这里我们也能知道,String其实就是用char[]实现的。

        String是final修饰的,表示该类不能被继承,String内的方法不能被重写。内部维护了一个char[ ]来存储String的值。
public class IntertorTest {

    public static void main(String[] args) {
        // 1
        String str = "abc";
        // 2
        char[] data = {'a','b','c'};
        String a = new String(data);
    }
    
}
1和2其实是一样的。


2:关于hash
 
引用
      /*缓存字符串的散列码。默认为0*/
        private int hash;

问题考点:为什么hashCode值选择为31? 详解转载自: https://segmentfault.com/a/1190000010799123

首先看下String类中hashCode()的源码:
        public int hashCode() {
            int h = hash;
            if (h == 0 && value.length > 0) {
                char val[] = value;

                for (int i = 0; i < value.length; i++) {
                    h = 31 * h + val[i];
                }
                hash = h;
            }
            return h;
        }

hashcode()方法解释为数学表达式,即为:h = 31^(n-1)*val[0]+31^(n-2)*val[1]+31^(n-3)*val[2]+......+31^0*val[n-1]
例如:字符串"abcd", h = 31^(3)*a + 31^(2)*b+31^(1)*c+31^(0)*d

解题答案:
1:31是一个不大不小的质数,是作为 hashCode 乘子的优选质数之一。
注:将hash值选为质数可以降低hash冲突。
2:31可以被JVM优化,31 * i = (i << 5) - i。(优化内容:乘法可以用移位和减法代替,以获得更好的性能。)

3:String类的常量池
        JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。Java能够进行这样的优化是因为字符串是不可变的,可以不用担心数据冲突进行共享。
        [字符串常量池(String pool, String intern pool, String保留池)]是Java堆内存中一个特殊的存储区域, 当创建一个String对象时,jvm会先去常量池用寻找是否存在该值,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象,若不存在于常量池,则会新创建一个对象。(针对String a = "1",a = "2")
注:不该创建对象还是重新引用,改变的都是指针的地址。
总结:
1:单独使用""引号创建的字符串都是常量,编译期就已经确定存储到String Pool中;    
2:使用new String("")创建的对象会存储到堆中,是运行期新创建的;    
3:使用只包含常量的字符串连接符如"aa" + "aa"创建的也是常量,编译期就能确定,已经确定存储到String Pool中;    
4:使用包含变量的字符串连接符如"aa" + s1创建的对象是运行期才创建的,存储在堆中;
引用
String s = new String("abc")这个语句创建了几个对象。
创建了2个对象:
第一个对象是"abc"字符串存储在常量池中,首先若常量池中没有则创建一个对象存于常量池。 
第二个对象在JAVA堆中的 String 对象,new出来的对象都存在于堆中(这是不会变的)。

问题考点:为什么String会被设计为final?
解题答案:
1:为了安全。
        String被许多的Java类(库)用来当做参数,例如网络连接地址URL,文件路径path,还有反射机制所需要的String参数等, 假若String不是固定不变的,将会引起各种安全隐患。且在多线程情况下是线程安全的。
2:支持字符串常量池,能提:高性能和减少内存开销。





猜你喜欢

转载自834434471.iteye.com/blog/2412795