美文网首页
经典面试题: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