0
点赞
收藏
分享

微信扫一扫

【Java面向对象】String、字符串常量池(String Constant Pool)、字符串的初始化、intern 方法、字符串的常用方法(截取)

产品喵dandan米娜 2022-02-27 阅读 78

String

文章目录


Java 中用 java.lang.String 类代表字符串:

  • Java 9 以前,底层使用 char[] 存储字符数据
    从 Java 9 开始,底层使用 byte[] 存储字符数据
  • 所有字符串字面量(比如 "abc" )都是 String 类的实例
  • String 对象一旦创建完毕,它的字符内容不可以修改

在这里插入图片描述

首先来看一段代码:并思考一下这段代码的输出是否与你想的不一样。

public class Main {
	public static void main(String[] args) {
		String s = "555";
		s += "555";
		s = "666";
		test(s);
		System.out.println(s); // 666
	}
	static void test(String str) {
		str += "555";
	}
}

String s = "555";s += "555";s = "666" 等操作都会在堆空间开辟一块新的内存空间,因为 String 是不可变字符串,每次要修改栈空间的变量sstr的值,只能改变它的指针指向,令指针指向堆空间新的内存。

我们知道,成员变量、函数形参等都是开辟在栈空间的(因为随时可能销毁),而上面代码中的 sstr 实际上在栈空间不是同一块布局,test 方法修改的是 str 的指向的值,所以 s 的值不会变。

在这里插入图片描述

字符串常量池(String Constant Pool)

Java 中有个字符串常量池(String Constant Pool,简称 SCP)

  • 从 Java 7 开始属于堆空间的一部分(以前放在方法区)

当遇到字符串字面量时,会去查看 SCP

  • 如果 SCP 中存在与字面量内容一样的字符串对象 A 时,就返回 A
  • 否则,创建一个新的字符串对象 D,并加入到 SCP 中,返回 D
String s1 = "mj"; // SCP中不存在字符串对象"mj"
String s2 = "mj"; // SCP中存在字符串对象"mj", 直接返回SCP中的"mj"
// 因此上面两个字符串对象是同一个对象
System.out.println(s1 == s2); // true

在这里插入图片描述

字符串的初始化

在 C语言里,字符数组就是字符串;在 Java 中,String 底层是由 char[] 组成的,但是他们不完全是一个东西。

在这里插入图片描述

利用 Java 的断点调试功能来验证上图:右半部分中的表示不是真实的内存地址,但是可以理解为标识不同则内存地址不同,相同则内存地址相同。可以看到 s1s2s3s4css5s6 的标识都是不同的;但是 s1s2s3s4 指向的value 的标识都是30,与上图展示的一致;s5s6 指向的value 的标识都是31。

在这里插入图片描述

intern 方法

A.intern 方法的作用:

  • 如果 SCP 中存在与 A 内容一样的字符串对象 C 时,就返回 C
  • 否则,将 A 加入到 SCP 中,返回 A
int a = 1, b = 2, c = 3;
String s1 = String.format("%d%d%d", a, b, c);
String s2 = String.format("%d%d%d", a, b, c);
// 去常量池中寻找"123", 发现没有, 就将s1的值"123"放入常量池
String s3 = s1.intern(); // s3、s1都指向了常量池中的"123"
String s4 = s2.intern(); // 返回常量池的"123"
String s5 = "123"; // s5指向常量池中的"123"

System.out.println(s1 == s2); // false
System.out.println(s1 == s3); // true
System.out.println(s1 == s4); // true
System.out.println(s1 == s5); // true

字符串的常用方法(截取)

// 去除左右的空格: "123  456"
" 123  456  ".trim();

// 转为大写字母: "ABC"
"abc".toUpperCase();
// 转为小写字母: "abc"
"ABC".toLowerCase();

// 是否包含某个字符串: true
"123456".contains("34");
// 是否以某个字符串开头: true
"123456".startsWith("123");
// 是否以某个字符串结尾: true
"123456".endsWith("456");

// 将字符串分隔为数组: [1, 2, 3, 4]
"1_2_3_4".split("_");

// 比较字符串的大小: <
"abc".compareTo("adc");
// 忽略大小写比较字符串的大小: <
"abc".compareTo("ADC");

String s1 = "abc";
String s2 = new String("abc");
// 查看字符串的内容是否相等: true
s1.equals(s2);
// 忽略大小写查看字符串的内容是否相等: true
"abc".equalsIgnoreCase("ABC");

// 字符串的替换
String str = "hello123";
// 由于String是不可变字符串, 必须用变量接收
str = str.replace("123", "666"); // hello666

穿插个知识点,Eclipse 中 抽取代码块的快捷键:先选中代码块,ALT + SHIFT + M

在这里插入图片描述

字符串截取内存分析图

String str = "abcdea";
// 字符串的截取区间: [2, 4)
str.substring(2, 4);  // cd
str.substring(2); 	  // cdea

str.indexOf("a"); 	  // 0
str.lastIndexOf("a"); // 5
str.indexOf("z"); 	// -1

在这里插入图片描述

举报

相关推荐

0 条评论