String s = new String() 并输出发生了什么

对于下列语句大家在熟悉不过

String name=new String("HXZ");
System.out.println(name+"is my name");

可是真正问你这里面从底层到底发生了什么,可能就有一些人就开始支支吾吾了,今天就从底层开始剖析一下:
首先我们需要知道jvm的内存模型,即五大块:

  1. 方法区
  2. 程序计数器
  3. 本地方法栈
    图源网络
    (关于jvm内存模型的具体解释,以后博主会出一篇博客,今天先不做过多讨论,因为这一部分很重要不是一两句话就能说完的。)

紧接着这个模型图片之后的是一个问题,那就是这行代码究竟创建了几个String对象呢?
答案是一个或者两个:

1 个的情况: 如果字符串池中已经存在了"HXZ"这个对象,那么直接在创建一个对象放入堆中,返回 name 引用。
2 个的情况: 如果方法区的字符串池中未找到"HXZ"这个对象,那么分别中和 字符串池中创建一个对象,但是如果遇到了new关键字,则还是会在内存(不是字符串池)中创建一个对象,然后将对象返回给引用name。字符串池中的比较都是采用equals()方法。
代码测试:

package test;

import java.util.ArrayList;
/**
 * 
 * @author hxz
 * @description String类测试
 * @version	1.0
 * @data 2020年2月5日 上午11:01:23
 */
public class MyTest {

	public static void main(String[] args) {
			String str = "abc";
			char[] array = { 'a', 'b', 'c' };
			String str2 = new String(array);
			// 使用intern()将str2字符串内容放入常量池
			str2 = str2.intern();
			// 这个比较用来说明字符串字面常量和我们使用intern处理后的字符串是在同一个地方
			System.out.println(str == str2);
			// 那好,下面我们就拼命的intern吧
			ArrayList<String> list = new ArrayList<String>();
			for (int i = 0; i < 1000000000; i++) {
				String temp = String.valueOf(Integer.MAX_VALUE).intern();
				list.add(temp);
			}
	}
		
}

在这里插入图片描述
在这里插入图片描述
按照测试,出现了OOM异常,报错信息显示的是:堆内存OutOfMemoryError,这是为什么呢?
首先:

  1. new String都是在堆上创建字符串对象。
    当调用 intern() 方法时,
    编译器会将字符串添加到常量池中(stringTable维护),
    并返回指向该常量的引用。
  2. 又因为,在JDK1.7的HotSpot中,已经把原本放在永久代的字符串常量池移出,JDK8元空间彻底取代永久代,此时字符串常量池还在堆,所以String变量是以字符数组的形式储在堆。所以这里报错的还是OOME异常指向了heap space即堆。

下面我们做一下解析:

  1. 首先:生成新的字符串 new String(STR1)放在堆中;
  2. 复制该字符串;
  3. 加载字符串常量"HXZ"(STR2),放在方法区的字符串池中;
  4. 调用字符串的构架器(Constructor);
  5. 保存该字符串到数组中(从位置0开始);
    这里有必要说一下为什么放在数组里:首先我们知道java的八个基本类型里面是没有String类型的,而调用的打印流PrintStream类可以格式化基本类型,如int,long等格式化为文本,所以,这里是转换为一个数组,而不是直接打印String。
  6. 从java.io.PrintStream类(打印流)中得到静态的out变量;
  7. 生成新的字符串缓冲变量new StringBuffer(STRBUF1);
  8. 复制该字符串缓冲变量;
  9. 调用字符串缓冲的构架器(Constructor);
  10. 保存该字符串缓冲到数组中(从位置1开始);
  11. 以STR1为参数,调用字符串缓冲(StringBuffer)类中的append()方法;
  12. 加载字符串常量"is my name"(STR3);
  13. 以STR3为参数,调用字符串缓冲(StringBuffer)类中的append()方法;
  14. 对于STRBUF1执行toString命令;
  15. 调用out变量中的println方法,输出结果。
发布了9 篇原创文章 · 获赞 73 · 访问量 8739

猜你喜欢

转载自blog.csdn.net/AAAhxz/article/details/103573481