一定义:
字符序列:把多个字符按照一定得顺序排列起来.字符串:把多个字符串串联起来
字符串的分类:
不可变的字符串:String:当前对象创建完毕之后,该对象的内容(字符序列)是不能改变的,一旦内容改变就是一个新的对象.
可变的字符串:StringBuilder/StringBuffer:当对象创建完毕之后,该对象的内容可以发生改变,当内容发生改变的时候,对象保持不变.
字符串的本质(底层是什么其实就是char[]),char表示一个字符,数组表示同一种类型的多个数据如何理解char[]:
String str = “ABCDEFG”; //定义一个字符串对象,等价于
char[] cs = new char[]{‘A’,‘B’,‘C’,‘D’,‘E’,‘F’,‘G’};
二.创建String对象的几种方式
1):直接赋一个字面量: String str1 = “ABCD”;
2):通过构造器创建: String str2 = new String(“ABCD”);
面试题1:上面两种创建方式分别创建了几个对象?
答: String str1 = “ABCD”; 最多创建一个String对象,最少不创建String对象.
如果常量池中,以及存在”ABCD”,那么str1直接引用,此时不创建String对象.
否则,先在常量池先创建”ABCD”内存空间,再引用.
String str2 = new String(“ABCD”);
最多创建两个String对象,至少创建一个String对象.
new关键字:绝对会在堆空间,创建内存区域. 所以至少创建一个String个对象.
面试题2:
public class StringDemo {
private static String getXx() {
return "AB";
}
public static void main(String[] args) {
// 说说下面String对象,彼此之间是否相等.
String str1 = "ABCD";
String str2 = "A" + "B" + "C" + "D";
String str3 = "AB" + "CD";
String str4 = new String("ABCD");
String temp = "AB";
String str5 = temp + "CD";
String str6 = getXx() + "CD";
System.out.println(str1==str2);//true
System.out.println(str1==str3);//true
System.out.println(str1==str4);//false
System.out.println(str1==str5);//false
System.out.println(str1==str6);//false
}
}
String对象比较:
1):单独使用"“引号创建的字符串都是直接量,编译期就已经确定存储到常量池中;
2):使用new String(”")创建的对象会存储到堆内存中,是运行期才创建;
3):使用只包含直接量的字符串连接符如"aa" + “bb"创建的也是直接量编译期就能确定,已经确定存储到常量池中(str2和str3);
4):使用包含String直接量(无final修饰符)的字符串表达式(如"aa” + s1)创建的对象是运行期才创建的,存储在堆中;
5):通过变量/调用方法去连接字符串,都只能在运行时期才能确定变量的值和方法的返回值,不存在编译优化操作.
三.String类中的常用方法:
1):String的创建和转换:
byte[] getBytes():把字符串转换为byte数组
char[] toCharArray():把字符串转换为char数组
String(byte[] bytes):把byte数组转换为字符串
String(char[] value):把char数组转换为字符串
2):获取字符串信息
int length() 返回此字符串的长度
char charAt(int index) 返回指定索引处的 char 值
int indexOf(String str)返回指定子字符串在此字符串中第一次出现处的索引。
int lastIndexOf(String str)返回指定子字符串在此字符串中最右边出现处的索引
3):字符串比较判断
boolean equals(Object anObject) 将此字符串与指定的对象比较。
boolean equalsIgnoreCase(String anotherString) 将此 String 与另一个 String 比较,不考虑大小写
boolean contentEquals(CharSequence cs) 将此字符串与指定的 CharSequence 比较
4):字符串大小写转换
String toUpperCase() 把当前字符串转换为大写(谁调用该方法,谁就是当前字符)
String toLowerCase() 把当前字符串转换为小写
笔试题①:获取以hello开头的文件名的的后缀名
public class StringDemo1 {
public static void main(String[] args) {
//获取以hello开头的文件名的的后缀名
String fileNames = "abc.java;hello.txt;hello.java;hello.class";
//1.将字符串以分号分隔开
String[] names = fileNames.split(";");
for (String name : names) {
//2.得到所有以hello开头的字符串
if(name.startsWith("hello")){
//3.返回指定字符串在此字符串中最右边出现处的索引
int i = name.lastIndexOf(".");
//4.根据索引来截取后缀名
String newName = name.substring(i);
System.out.println(newName);
}
}
}
}
笔试题②:把字符串首字母大写
public class StringDemo2 {
public static void main(String[] args) {
//把单词首字母大写
String str = "adasfagfadf";
//1.截取到首字母并转换为大写
String s = str.substring(0, 1).toUpperCase();
//2.截取后面的所有字母
String s1 = str.substring(1);
String s2=s+s1;
System.out.println(s2);
}
}
四.浅谈一下String, StringBuffer,StringBuilder的区别?
String是不可变类,每当我们对String进行操作的时候,总是会创建新的字符串。操作String很耗资源,所以Java提供了两个工具类来操作String - StringBuffer和StringBuilder。
StringBuffer和StringBuilder是可变类,StringBuffer是线程安全的,StringBuilder则不是线程安全的。所以在多线程对同一个字符串操作的时候,我们应该选择用StringBuffer。由于不需要处理多线程的情况,StringBuilder的效率比StringBuffer高。
常用的方法:
append(Object val):表示追加任意类型数据
StringBuilder deleteCharAt(int index) :删除字符串中,指定位置的字符
reverse() :将此字符序列用其反转形式取代
面试题①String是线程安全的吗?为什么我们使用HashMap的时候总用String做key?
String是不可变类,一旦创建了String对象,我们就无法改变它的值。因此,它是线程安全的,可以安全地用于多线程环境中。
因为字符串是不可变的,当创建字符串时,它的它的hashcode被缓存下来,不需要再次计算。因为HashMap内部实现是通过key的hashcode来确定value的存储位置,所以相比于其他对象更快。这也是为什么我们平时都使用String作为HashMap对象。
面试题②:switch能否应用于String类型上?
答:可以.jdk1.7之后可以应用于String类型上,jdk1.7并没有新的指令来处理switch string,而是通过调用switch中string.hashCode,将string转换为int从而进行判断。