素材牛VIP会员
java的string存放位置的疑惑
 lu***ng  分类:Java代码  人气:1218  回帖:6  发布于6年前 收藏

有一道题是这样的:

new String("aaa")创建了几个对象? 答案是创建一个或2个,理由是如果常量区中存在了aaa变量,则只在堆中创建一个;如果常量区不存在aaa变量,则分别在常量区和堆中各创建一个。

但我实际测试的结果却不符:

String s1 = new String("aaa");
String s2 = "aaa";
System.out.println(s1 == s2); //false

如果说new String("aaa")在堆中和常量区中都创建了对象,那么为什么s2不直接复用s1的常量池的引用呢?

补充:
发现自己想错了,s1应该指向的堆中的元素,而s2指向的是常量池中的,所以两者不相等是对的,那有没有办法测试测试出new String("aaa")也同时在常量池中创建对象了呢?

又或者String s3 = "aa".concat("a"); 请问这个s3是指向堆中还是指向常量池的,它能否复用常量池中的变量呢?

 标签:stringjava

讨论这个帖子(6)垃圾回帖将一律封号处理……

Lv1 新人
陌***人 PHP开发工程师 6年前#1

String不是每次赋值都重新创建一个String对象实例吗?所以才会有StringBuilder呀。

Lv5 码农
麦***j 产品经理 6年前#2
//    new一次就是在堆中创建一个新的对象。不new的话aaa直接在字符串常量中取值;
//    String s2 = "aaa"; 先在内存中寻找aaa,如果有,则将aaa的内存首地址指向了s1,
      如果没有则在堆中中创建一个新的对象。

//    String s1 = new String("aaa");//  
//    不管"aaa"在内存中是否存在,都会在堆中开辟新空间,将字符串"aaa"的内存首地址指向s1。


String a = "aaa";//   aaa在常量池中创建一个对象,将内存首地址指向了a
String b = "aaa";//    直接aaa已经存在的内存首地址指向b。
String c = new String("aaa");// 不管存在与否,在堆中创建1个空间,内存首地址与常量池中的地址完全不同
System.out.println(a==b);// true
System.out.println(a==c);// false
Lv7 码师
15***by 产品经理 6年前#3

按照面向对象的思想,有没有同时在常量池创建对象,可能String自己最清楚,嗯,他有一个intern()方法。

Lv6 码匠
pu***04 交互设计师 6年前#4

问题一:

String a = “aaa”,会在常量池中创建对象,如果常量池中存在同样的对象,那a就直接指向该对象。而 String a = new String("aaa"),若常量池中存在,则不在常量池中创建,只在堆中创建。

String a = new String("aaa");
String b = new String("aaa");
System.out.println(a == b);//比较两者堆中的引用返回false
System.out.println(a.intern() == b.intern());//比较两者常量池中的引用,返回true

问题二:

从源码中找答案String s3 = "aa".concat("a"); 其实就相当于 String s3 = new String("aaa"),会在堆中创建对象。

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);
}

Lv5 码农
me***20 技术总监 6年前#5
    String s1 = new String("aaa");
    String s2 = "aaa";
    System.out.println(s1 == s2); //false
    System.out.println(s1.intern() == s2); //true

当一个String实例调用intern()方法时,会查找常量池中是否有相同的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个等于str的字符串并返回它的引用,由于s2已经在常量池中,所以s1.intern()不会再创建,而是直接引用同一个"aaa"。

如果这个还不够明显,那么我们就来试验,

public class Cons {
    public static void main(String[] args) throws InterruptedException {
        String s1 = new String("vv");
    }
}

然后命令行

注意常量池有 VV

Lv3 码奴
路***侠 JS工程师 6年前#6

前面几位的回答已经非常好了,我补充一句,我们经常说的“把字符串放到常量池”是指把字符串的引用放到字符串常量池(String Pool,本质是一个哈希表)中,字符串本身还是放在堆上的。

 文明上网,理性发言!   😉 阿里云幸运券,戳我领取