文章目录
String对象的特点
String是JDK中内置的一个类:java.lang.string
- 1.String表示字符串类型,属于引用数据类型,不属于基本数据类型.
- 2.Java中使用双引号括起来的都是String对象。例如:“abc”、“lei”、“hello world!”,这就是三个对象。
- 3.Java中规定,双引号括起来的字符串是不可变的,也就是说“abc”从出生到消亡双引号里的内容是不会变的,不可能变成“abcd”,也不可能变成“ab”。
- 4.字符串都是直接存储在“方法区”的字符串常量池当中的。
- 5.为什么把字符串存储在“字符串常量池”当中呢。因为字符串在实际开发中使用的很频繁,为了提供效率所以存储在“字符串常量池中”。
String对象创建的两种方式
方式一:通过字符串常量的方式创建
//方式一:通过常量的方式创建string对象
//以下两行代码表示底层创建了3个字符串对象,都在字符串常量池当中。
String s1 = "abcdef";
String s2 = "abcdef" + "xy";
方式一 的内存图(截图于老杜JAVA),s1和s2的内存地址指向了字符串常量池中的字符串。因为s2是“abcdef”和“xy”的拼接,又因为“abcdef”,s1已经创建了,所以s2直接拿过来。这也就是为什么要把字符串存储在方法区的字符串常量池中的原因,第一次创建了,第二次使用时就不用创建了直接拿过来用。
方式二:通过new对象的方式创建
//通过new的方式创建String对象。
//分析:结合以上内容可以先分析s3的“xy”从哪来。
//提示:凡是“”括起来的都在字符串常量池中。
//注意:new对象的时候一定在堆内存中开辟空间。
String s3 = new String("xy");
方式二的内存图,s3在内存中存在的形式就是,栈中的s3的内存地址指向堆中的String对象,堆中的String对象中的内存地址又指向方法区中“xy”的内存地址。
如果堆里面new的是一个User对象,User对象里有一个String类型的name属性,则User的name里存储的并不是具体的字符串,而是存储的是字符串在字符串常量池中的内存地址。
String对象的“==”和“equals”
思考1,方式一创建的String对象中(s1 == s2)的结果。要知道“==”判断的是内存地址
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2);
}
分析,字符串“hello”存储在方法区的字符串常量池中,栈中的s1和s2存储的都是“hello”的内存地址。字符串常量池中有的常量,不会被重复创建。所以s1 == s2为true。
思考2,方式二 new的String对象中(x == y)的结果。要知道new出来的对象在堆中开辟空间。且“==”判断的是内存地址。
public static void main(String[] args) {
String x = new String("xyz");
String y = new String("xyz");
System.out.println(x == y);
}
分析,既然new出来的对象在堆内存中开辟空间,也就意味着每一个new出来的对象都有一个单独的堆内存地址。虽然堆中的对象都指向的是“xyz”中的字符串常量池中的内存地址,但栈中的x和y都指向x和y在堆内存中的不同的堆内存地址。所以xy为false。
于是乎我们得出结论,字符串对象之间的比较不能使用“”。
"=="不保险,应该调用String对象的equals方法
String对象的比较到底是用“==”还是equals呢?
翻看源码可知Object的equals的方法默认也是使用“==”做比较。
那咱们再来看看String对象的equals方法(String对象重写了equals方法)
所以以上案例中x和y的比较应该使用equals。
"testString"为什么可以通过(.点)调出equals方法
因为“testString”就是一个String字符串对象,只要是对象就能调用方法。
String k = new String("testString");
System.out.println("testString".equals(k));
System.out.println(k.equals("testString"));
以上两种使用equals方式做比较都可以,但是推荐使用"testString".equals(k)。因为如果k为null的话,k.equals(“testString”)就会报空指针异常。使用为空的对象调用方法就会出错。
分析以下程序创建了几个对象
/**
* @author lei
* @date 2022/4/26 0026 18:35
* @description 分析以下程序创建了几个对象
*/
public class StringTest03 {
public static void main(String[] args) {
/**
*一共创建了3个对象
* 方法区字符串常量池中有一个:“hello”
* 堆内存当中有两个String对象。
*/
String s1 = new String("hello");
String s2 = new String("hello");
}
}
String对象重写了toString方法
public class StringTest04 {
public static void main(String[] args) {
String s1 = "hello world";
/**
* 根据之前所学:输出一个对象的引用的时候,会自动调用Object的toString()方法,
* 该方法会自动输出对象的内存地址。
* 但此时我们可以看出s1输出的是“hello world”
* 结论:String类已经重写了toString()方法。
*/
System.out.println(s1.toString());
/**
* 字符集中,97是a,98是b,99是c
*/
byte[] bytes = {97,98,99};
String s2 = new String(bytes);
System.out.println(s2.toString());
System.out.println(s2);
}
}
所以 System.out.println(s2.toString());
System.out.println(s2);输出的是同样的结果。
string.replaceAll();字符串替换
#replaceAll()的源码
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}