今天来说说字符串。
其实上一篇Java回顾里说了一些关于字符串的东西,比如说字符串池,引用等等,今天详细的说一下字符串这个东西。
首先字符串,也就是Java里常说的String这个东西,是一个最终类,就是不能被继承的类,是一个引用数据类型:
//这是Java中字符串类的定义(当然,没copy它实现的接口)
public final class String{...}
这是首先要明确的,它是一个最终类,是一个引用数据类型。
如何创建字符串:
1、不使用new的方式:
//数据类型 变量名 = 变量值(一般用双引号括起代表字符串)
String prompt = "Hello World";
2、使用new的方式:
//数据类型 变量名 = new关键字 数据类型(变量值)
String prompt = new String("Hello World");//调用String类中的构造方法
两种有什么区别呢?
不使用new的方式,字符串创建在字符串池中;
使用new的方式,字符串在字符串池和堆内存中都创建;
注意:使用new的方式创建的字符串优先使用堆内存中的对象。
字符串的不变性
字符串的不变性是指字符串一旦创建,任何方法都不能修改其内容。
举个例子:
String s = "abc";
s = "abcd";
这并不是说“abc”变成了“abcd”,而是变量s里存的地址变了,第一行它指向字符串“abc”,第二行指向字符串“abcd”,字符串“abc”还是存在的。这就是我为什么一直强调String是引用数据类型的原因。
另外呢,可能还有这样的意思,是对之前字符串创建的补充:
不使用new创建的时候,会先在字符串池中查找,如果该字符串存在,则将该字符串地址赋给变量,如果不存在,则创建,在字符串池中不会有重复的字符串,创建好的字符串也不会被修改,变得只是变量的引用,而不是字符串内容。
字符串的常用操作
1、字符串拼接:
//方式一:+
String s1 = "Hello "+"World";
//方式二:concat()方法
String s2 = "Hello ".concat("World");
最终拼接的结果都是“Hello World”,当然,使用方式二的时候我们常常是用变量。
2、字符串比较:
一般是两种方式:
(1)==:比较两个字符串的地址,相等为true不等为false
(2)equals方法:比较两个字符串的内容,相等为true不等为false
(2.5)equalsIgnoreCase方法:忽略大小写比较字符串内容是否相等
举个例子:
//不使用new方式创建字符串:
String s1 = "Hello";
//使用new方式创建字符串:
String s2 = new String("Hello");
//使用两种方式比较并打印比较结果
System.out.println(s1 == s2);//false
System.out.println(s1.equals(s2));//true
为什么呢?上面说了,==是比较地址,是字符串池中的地址,而使用new方式创建的字符串会优先使用堆内存中的对象;而equals方法比较内容,就相等了,都是Hello。
我们看一下equals方法:
//公有 返回布尔值 传入参数是个Object类型的参数
public boolean equals(Object anObject) {
//this代表调用者,比较调用者和传入参数是否相等
if (this == anObject) {
return true;
}
//向下转型前的判断,被比较的是否是String类型
if (anObject instanceof String) {
//把传入参数从Object类型转为String类型
String anotherString = (String)anObject;
//通过一个整型变量来存储字符串长度(调用者)
int n = value.length;
//判断调用字符串的长度和比较字符串长度是否相等
if (n == anotherString.value.length) {
//一个字符一个字符比较是否相等
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
之前说了,==比较的是地址,而使用new方法创建的字符串优先使用的是堆内存中的对象,那有没有一个方法让它返回字符串池中的实例呢?有:
//不使用new方式创建字符串:
String s1 = "Hello";
//使用new方式创建字符串:
String s2 = new String("Hello");
//使用两种方式比较并打印比较结果
System.out.println(s1 == s2);//false
System.out.println(s1 == s2.intern());//true
intern()方法:返回字符串池的实例。
我们再看个例子:
String s1 = "hello";
String s2 = " world";
String s3 = "hello world";
String s4 = s1 + s2;
System.out.println(s1 == s4);//false
我们看到,都是不使用new的创建方式,但是为什么最后s1和s4的地址不相等呢?
我们就要深入的了解一下字符串拼接了:
字符串的拼接过程,实际上是通过建立一个StringBuffer,然后调用StringBuffer的append方法,最后再将StringBuffer转为字符串。
即 String s4 = s1 + s2;这一步的时候,s4指向的是s1和s2通过StringBuffer拼接后转成的字符串,这是一个字符串对象,存在堆内存中。
StringBuffer 和 StringBuilder
StringBuffer 和 StringBuilder 是专门用来拼接字符串的类:
StringBuffer是线程安全的,相对而言执行效率低;
StringBuilder是非线程安全的,相对而言执行效率高。
常用的方法:
append():添加
insert():插入
delete():删除
reverse():反转
toString():将StringBuilder/StringBuffer对象转为字符串对象。
//创建StringBuffer对象
StringBuffer sb = new StringBuffer();
//调用append方法,添加Hello
sb.append("Hello");
//StringBuffer对象转为字符串对象
String s = sb.toString();
今天关于字符串就写这么多,里面还有一些方法比如说取子串substring()、查找子串indexOf()等等,包括StringBuffer里面的插入方法和删除方法也没有写例子演示,因为这些直接查API就可以知道用法,甚至IDE工具自动联想功能都可以看出来怎么用,就没有多写,关于Java回顾系列还是想写一些可能会忽略掉或者理解性的东西。
谢谢观看,欢迎各位大佬批评指正。