您的位置:首页技术文章
文章详情页

java的string存放位置的疑惑

【字号: 日期:2023-12-12 11:40:08浏览:16作者:猪猪

问题描述

有一道题是这样的:

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是指向堆中还是指向常量池的,它能否复用常量池中的变量呢?

问题解答

回答1:

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

然后命令行

java的string存放位置的疑惑

注意常量池有 VV

回答2:问题一:

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

String a = new String('aaa');String b = new String('aaa');System.out.println(a == b);//比较两者堆中的引用返回falseSystem.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);}回答3:

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

回答4:

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

回答5:

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

回答6:

// new一次就是在堆中创建一个新的对象。不new的话aaa直接在字符串常量中取值;// String s2 = 'aaa'; 先在内存中寻找aaa,如果有,则将aaa的内存首地址指向了s1, 如果没有则在堆中中创建一个新的对象。// String s1 = new String('aaa');// // 不管'aaa'在内存中是否存在,都会在堆中开辟新空间,将字符串'aaa'的内存首地址指向s1。String a = 'aaa';// aaa在常量池中创建一个对象,将内存首地址指向了aString b = 'aaa';// 直接aaa已经存在的内存首地址指向b。String c = new String('aaa');// 不管存在与否,在堆中创建1个空间,内存首地址与常量池中的地址完全不同System.out.println(a==b);// trueSystem.out.println(a==c);// false

标签: java
相关文章: