String类在所有项目开发之中都会使用到!
1. 实例化方式
① 直接赋值:String str= "Hello world";
② 通过构造方法产生对象(传统法):String str = new String("Hello world");
public class ShiLiHua {
public static void main(String[] args) {
String str1 = "Hello world";
String str2 = new String("Hello world!!!");
System.out.println(str1);
System.out.println(str2);
}
}
***** 2. 字符串的相等比较
如果现在有两个int
型变量,判断其相等可以使用 " == " 完成这是毋庸置疑的。但是如果要比较的是两个String
类型呢?
public class XiangDengBiJiao {
public static void main(String[] args) {
int a = 10;
int b = 10;
System.out.println(a==b);
String str1 = "Hello";
String str2 = new String("Hello");
System.out.println(str1==str2);
}
}
现在两个字符串内容相同,而使用 " == " 得到的结果却是不同的。
- 内存图分析如下:
结论:" == " 操作符用于比较两个变量的值是否相等,对于基本类型而言比较的就是数值大小;而对于引用类型而言,比较的实际上是保存的地址是否相等而不会比较内容。
所以在字符串比较时,需要使用的是String类提供的equals()
方法,这个方法区分大小写。要想不区分大小写可以使用equalsIngoreCase()
方法。
public class XiangDengBiJiao {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = new String("Hello");
String str3 = "hello";
System.out.println(str1.equals(str2));
System.out.println(str1.equals(str3));
System.out.println(str1.equalsIgnoreCase(str3));
}
}
面试题:请解释String类 " == " 与 equals 的区别。
① " == "进行的是数值比较,比较的是两个字符串对象的内存地址数值。
② " equals() "可以进行字符串内容的比较。
3. String类的匿名对象
所有字符串常量 (直接写出来的用" "括起来的字符串) 都是String类的匿名对象。
public class NiMingDuiXiang {
public static void main(String[] args) {
String str1 = new String("Hello");
System.out.println("Hello".equals(str1));
System.out.println(str1.equals("Hello"));
//还有假设用户没有输入的情况下
String str2 = null;
System.out.println("Hello".equals(str2));
System.out.println(str2.equals("Hello"));
}
}
结论:在进行接收用户输入数据的时候一定要考虑到用户没有输入的问题,以上面代码为例,用户没有输入的时候,str2.equals("Hello")
一定会出现空指针异常的错误 。而任何的字符串常量都是String类的匿名对象,该对象永远不会为null,所以"Hello".equals(str2)
运行正常。因此在比较两个字符串是否等于特定字符串时,将字符串常量写在equals
前面,通过字符串常量来比较。
4. 两种实例化方式的区别
① 直接赋值:
public class ShiLiHuaQuBie {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "Hello";
System.out.println(str1==str2);
}
}
可是我们刚刚已经说过 " == " 对于字符串来说是比较地址的,开辟新空间之后肯定用 " == " 结果是false的,这里的结果是true说明是没有开辟新空间的,这是为什么呢?
- 内存图分析如下:
原因:在JVM内部会维护一个字符串常量池(对象数组),若采用直接赋值的方式进行String类的实例化操作,那么该对象会自动保存到对象池中。若下一次继续使用直接赋值的方式实例化String对象,先在对象池中寻找是否有指定对象,若有,直接引用,否则创建新空间,经新对象入池以供下次使用。也就是String类所谓的共享设计模式。
② 构造赋值:
String类本身毕竟是一个类,既然是类,那么类中一定存在构造方法。类对象使用构造方法实例化是标准做法。
public class ShiLiHuaQuBie {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = new String("Hello");
System.out.println(str1==str2);
}
}
结论:说明构造方法产生的字符串常量并没有保存在对象池中。但是可以使用intern()
方法手工入池,也是String类提供的方法。
public class ShiLiHuaQuBie {
public static void main(String[] args) {
String str1 = "Hello";
String str2 = new String("Hello");
//手工入池
String str3 = str2.intern();
System.out.println(str1==str2);
System.out.println(str1==str3);
}
}
但是当使用构造方法实例化字符串时,实际上会开辟两次空间。因为程序执行顺序是从右向左执行的!!!以String str = new String("Hello")
为例:
- 内存图分析如下:
面试题:请解释String类中两种对象实例化的区别。
① 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
② 构造方法:会开辟两块堆内存空间,其中一块成为垃圾空间,不会自动保存在对象池中,可以使用intern()
方法手工入池。
5. 字符串常量不可变更
public class BuKeBianGeng {
public static void main(String[] args) {
String str = "Hello";
str += "world";
str += "!!!!";
System.out.println(str);
}
}
- 内存图分析如下:
结论:堆中常量的值无法更改,但是栈中的指向可以更改。而且字符串不要改变太多次,慎用 “+” 字符串拼接操作,因为会产生大量垃圾空间。
原则:
① 字符串使用就采用直接赋值。
② 字符串比较就使用equals()
实现。
③ 字符串别改变太多。
6. 字符与字符串的相互转换
字符串就是一个字符数组,所以在String类里面支持字符数组转换为字符串以及字符串变为字符的操作方法。
① char[ ] => String
public String(char[] value)
:将字符数组全部转为字符串
public String(char[] value, int offset, int len)
:将字符数组的部分内容转为字符串
public class ZiFuYuZiFuChuan {
public static void main(String[] args) {
//将字符串变为字符数组
String str = "Hello world";
char[] data = str.toCharArray();
for(int i = 0; i < data.length; i++) {
System.out.print(data[i]+"、");
}
//字符数组转为字符串
System.out.println("\n"+new String(data));
System.out.println(new String(data, 3, 7));
}
}
② String => char
public char charAt(int index)
:取得字符串指定索引的字符,从0开始
public class ZiFuYuZiFuChuan {
public static void main(String[] args) {
String str = "Hello";
System.out.println(str.charAt(0));
//如果现在超过了字符串长度,则会产生StringIndexOutOfBoundsException异常
System.out.println(str.charAt(5));
}
}
③ String => char[ ]
public char[] toCharArray()
:将字符串转为字符数组
public class ZiFuYuZiFuChuan {
public static void main(String[] args) {
String str = "Hello world";
char[] data = str.toCharArray();
for(int i = 0; i < data.length; i++) {
System.out.println(data[i]);
}
}
}
- 现在有一个字符串判断其是否由数字所组成。
- 因为现在不知道字符串的长度以及包含的内容,所以最好的做法是将字符串变为字符数组而后判断每一位字符是否是 " 0 " ~ " 9 "之间的内容,如果是则为数字。
public class ShuZi {
public static void main(String[] args) {
String str = "ab12cd";
char[] data = str.toCharArray();
int i;
for(i = 0; i < data.length; i++) {
if(data[i] >= '0' && data[i] <= '9') {
System.out.println("有数字");
break;
}
}
if(i > data.length) {
System.out.println("没有数字");
}
}
}
7. 字节与字符串的转换
字节常用于数据传输以及编码转换的处理之中,在String中提供有对字节的支持。
① byte[ ] => String
public String(byte[] value)
:将字节数组全部转为字符串
public String(byte[] value, int offset, int len)
:将字节数组的部分内容转为字符串
public class ZiJieYuZiFuChuan {
public static void main(String[] args) {
//转换成字节数组
String str = "Hello";
byte[] data = str.getBytes();
for(int i = 0; i < data.length; i++) {
System.out.println(data[i]);
}
//转换成字符串
System.out.println(new String(data));
System.out.println(new String(data, 1, 3));
}
}
② String => byte[ ]
public byte[] getBytes()
:将字符串转为字节数组
public byte[] getBytes(String charSet)
:将字符串按照指定编码格式转为字节数组
Linux默认编码为UTF-8,在Windows默认编码是GBK。
public class ZiJieYuZiFuChuan {
public static void main(String[] args) {
String str = "Hello";
byte[] data = str.getBytes();
for(int i = 0; i < data.length; i++) {
System.out.println(data[i]);
}
}
}
8. 字符串的比较
比较相等:equals
和equalsIngoreCase
比较大小:public int compareTo(String anotherString)
:比较两个字符串的大小关系。(负数:小于 0:相等 正数:大于)
public class BiJiaoDaXiao {
public static void main(String[] args) {
String str1 = "abc";
String str2 = "aBc";
System.out.println(str1.compareTo(str2));
}
}
结论:按照ASCII码比较,只要发现不相等的内容算出差值直接返回,不会继续向下查找。且比较汉字没什么意义。
9. 字符串查找
contains()
:判断一个字符串是否存在
indexOf()
:返回下标int型
lastIndexOf()
:(从指定位置)从后向前查找
startsWith()
:(从指定位置)判断是否以指定字符串开头
endsWith()
:判断是否以指定字符串结尾
public class ChaZhao {
public static void main(String[] args) {
String str = "$$helloworld!!";
System.out.println(str.contains("hello"));
System.out.println(str.indexOf("o"));
//indexOf如果没有返回-1
System.out.println(str.indexOf("o", 7));
System.out.println(str.lastIndexOf("e"));
System.out.println(str.lastIndexOf("e", 10));
System.out.println(str.startsWith("$$"));
System.out.println(str.startsWith("h", 2));
System.out.println(str.endsWith("!!"));
}
}
10. 字符串替换
Public String replaceAll(String regex, String replacement)
:将字符串中所有指定内容替换为新内容
public String replaceFirst(String regex, String replacement)
:将字符串首个字符替换为指定内容
public class TiHuan {
public static void main(String[] args) {
String str = "Hello world";
System.out.println(str.replaceFirst("H", "h"));
System.out.println(str.replaceAll("l", "_"));
}
}
***** 11. 字符串拆分
public String[] split(String regex)
:按照指定格式将字符串全部拆分
public String[] split(String regex, int limit)
:将字符串部分拆分,数组长度为限定limit长度
注意返回值是字符串数组而不是字符串!!!
public class ChaiFen {
public static void main(String[] args) {
String str = "Hello world !!!";
String[] result1 = str.split(" ");
for(String s : result1) {
System.out.println(s);
}
String[] result2 = str.split(" ", 2);
for(String s : result2) {
System.out.println(s);
}
}
}
- 一般IP地址会用到拆分,IP地址里面的 " . " 有特殊含义,所以要转义。
split
方法中的参数时正则表达式," . " 原本需要一个 " \ " 来转义,但是正则表达式中 " \ " 也需要一个 " \ " 来转义,所以一共需要两个 " \ "。
public class ChaiFen {
public static void main(String[] args) {
String str = "192.168.1.1";
String[] result = str.split("\\.");
for(String s : result) {
System.out.println(s);
}
}
}
12. 字符串截取
public String substring(int beginIndex)
:从指定索引开始截取到字符串结尾
public String substring(int beginIndex, int endIndex)
:从指定索引开始截取到指定索引结束
public class JieQu {
public static void main(String[] args) {
String str = "Hello world";
System.out.println(str.substring(5));
System.out.println(str.substring(5, 8));
}
}
观察得出substring()
方法截取字符串是左闭右开区间。
注意substring
的写法,string不大写!!!
13. 其他方法
trim()
:去掉字符串的左右两边空格,中间保留
toUpperCase()
:将字符串转大写处理
toLowerCase()
:将字符串转小写处理
length()
:返回字符串长度,既可以作为属性也可以作为方法
isEmpty()
:判断是否是空字符串,不包含null (即无法判断是null的情况)
null
是空对象;""
是空字符串对象,也是个对象。而isEmpty是要通过对象才能调用的,所以null没法判断。
public class QiTa {
public static void main(String[] args) {
String str = " hello world ";
System.out.println(str.trim());
System.out.println(str.toUpperCase());
System.out.println(str.toLowerCase());
System.out.println(str.length());
}
}
- 如何只将首字母大写呢?String类并没有提供首字母大写操作,需要自己实现。
public class ShouZiMuDaXie {
public static void main(String[] args) {
String str = "hello world";
System.out.println(firstUpperCase(str));
}
public static String firstUpperCase(String str) {
return str.substring(0, 1).toUpperCase()+str.substring(1);
}
}
- 如何判断用户的输入就是个空字符串呢?
public class empty {
public static void main(String[] args) {
String str = null;
//如果换成是 str.isEmpty() || str == null,一上来就是个空对象,
//短路与,NullPointerException。
if(str == null || str.isEmpty()) {
System.out.println("空字符串");
}
}
}