美文网首页
经典面试题:String str = new String("a

经典面试题:String str = new String("a

作者: 云芈山人 | 来源:发表于2021-06-26 03:26 被阅读0次

    在JVM中,会单独划分一块内存给String。字符串的分配需要消耗高昂的时间和空间,且使用又比较频繁。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行优化:使用字符串常量池。每当创建字符串常量时,JVM会先检查字符串常量池,如果存在,则返回引用地址;如果不存在,就会实例化该字符串并且放到常量池中。由于String字符串的不可变性,常量池中不会出现两个相同的字符串。

    如果在常量池中,“abc”如果存在,就直接把“abc”对象的引用地址赋给str。找不到则创建对象“abc”,再把地址赋给str。

    Object obj = new Object();
    平常都会说创建了obj对象,事实上obj只是一个变量,变量里保存了Object对象的引用地址。
    引用类型声明的变量是指该变量在内存中实际存储的一个引用地址,实体在堆中。

    所以说变量是可以变的,但是实体对象不能变,即str是可变的,但“abc”不可变。

    那么,String为什么是不可变的?

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
    
        private final char value[];
        private int hash; // Default to 0
        public String() {
            this.value = new char[0];
        }
    
        public String(String original) {
            this.value = original.value;
            this.hash = original.hash;
        }
        ...
    }
    

    由源码可知:

    1. String类是final修饰的;
    2. String存储内容是char数组;
    3. char数组是final修饰的。

    final关键字
    1.修饰类:则类不可被继承,类中的成员变量可以按需求设为final,类中的方法隐式被指定为final;
    2.修饰方法:不能重写(但可被重载几个final修饰的方法)。这里需注意:重写的前提是子类可继承父类此方法,若final修饰的方法同时也是private的,则子类中定义了同样的方法名和参数,则不产生重写与final的冲突,也就是说该方法属于子类,与父类没有关系。(类的private方法,隐式的被指定为final方法)
    3.修饰基本数据类型:表示该基本数据类型的值一旦被初始化后就不能被改变。
    4.修饰引用类型:初始化后不能再指向其他对象(引用地址不可变),但对象的内容可以发生改变。
    5.修饰成员变量(属性):必须要显示初始化。(两种初始化方式:a.申明的时候赋值;b.在其类的所有构造器中都为其赋值。)。

    String的其它方法
        public String concat(String str) {
            int otherLen = str.length();
            if (otherLen == 0) {
                return this;
            }
            int len = value.length;
            char buf[] = Arrays.copyOf(value, len + otherLen);
            str.getChars(buf, len);
            //返回新的对象
            return new String(buf, true);
        }
    
        public String replace(char oldChar, char newChar) {
            if (oldChar != newChar) {
                int len = value.length;
                int i = -1;
                char[] val = value; /* avoid getfield opcode */
    
                while (++i < len) {
                    if (val[i] == oldChar) {
                        break;
                    }
                }
                if (i < len) {
                    char buf[] = new char[len];
                    for (int j = 0; j < i; j++) {
                        buf[j] = val[j];
                    }
                    while (i < len) {
                        char c = val[i];
                        buf[i] = (c == oldChar) ? newChar : c;
                        i++;
                    }
                    return new String(buf, true);
                }
            }
            return this;
        }
    

    String的方法都不是在原有的字符串上进行的,而是重新生成一个新的字符串对象。即原始字符串是不改变的。

    结论:

    • String对象一旦被创建就是固定不变的,对于String的任何改变都不会影响到原对象,相关的任何变化性的操作都会生成新的对象。
    • String对象每次有变化性操作(有变化的情况)的时候,都会new一个String对象。
    各JDK版本的常量位置.png

    分析:

    String str = new String("abc");
    首先,new一个对象在堆中,将new String("abc")的对象的引用地址赋值给变量str。先去常量池查找“abc”是否存在。若存在,直接放引用地址;若不存在,创建“abc”对象,并将引用地址赋给String的有参构造里。

    答案:

    如果常量池中存在,则只需创建一个对象,否则需要创建两个对象。

    相关文章

      网友评论

          本文标题:经典面试题:String str = new String("a

          本文链接:https://www.haomeiwen.com/subject/acvwyltx.html