String类
1,构造方法
String有三种构造方法:
- 把字符串数据,封装为字符串对象
- 把字符数组,封装为字符串对象
- 把字符数组自offset起共count个字符,封装为字符串对象
public static void main(String[] args) {
char[] c = {'a', 'b', 'c'};
String str1 = "abc";//=new String("abc")
String str2 = new String(c);
String str3 = new String(c, 1, 2);
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
}
使用String str=new String(“hello”)方式创建对象,一共创建了几个对象?
一共会创建两个对象,一个是使用new创建的对象,存储在堆中;另一个是常量对象"hello",存储在字符串常量池中。
2,获取方法
public static void main(String[] args) {
String str = "Hello";
System.out.println(str.length());//获取字符串长度
System.out.println(str.charAt(1));//获取字符串中某个字符
System.out.println(str.indexOf('l'));//获取字符串中某个字符首次出现的指针
System.out.println(str.substring(1));//截取1到最后的字符
System.out.println(str.substring(1,4));//截取1到4的字符,不包括4
}
3,判断方法
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String str = scanner.next();
System.out.println("HELLO".equals(str));
System.out.println("HELLO".equalsIgnoreCase(str));
System.out.println(str.startsWith("h"));
System.out.println(str.startsWith("e",1));
System.out.println(str.endsWith("o"));
System.out.println(str.isEmpty());
System.out.println(str.compareTo("A"));//相等返回0
}
4,转化方法
public static void main(String[] args) {
//1)toCharArray():把字符串转换为字符数组
//2)toLowerCase():把字符串转换为小写字符串
//3)toUpperCase():把字符串转换为大写字符串
String str = "Hello";
char[] c = str.toCharArray();
System.out.println(c);
System.out.println(str.toLowerCase());
System.out.println(str.toUpperCase());
}
5,其他常用方法
1)trim():去除字符串两端空格
2)split():去除字符串中指定的的字符,然后返回一个新的字符串数组
3)subSequence(int beginIndex,int endIndex ):截取字符串中指定位置的字符组成一个新的字符串
4)replace(char oldChar, char newChar):将指定字符替换成另一个指定的字符
5)replaceAll(String regex,String replasement):用新的内容替换全部旧内容
6)replaceFirst(String regex,String replacement):替换首个满足条件的内容
7)lastIndexOf(String str):返回指定字符出现的最后一次的下标
8)contains(CharSequence s):查看字符串中是都含有指定字符
9)concat(String str):在原有的字符串的基础上加上指定字符串
练习:输入一个字符串,再输入要查找的字符,判断该字符在该字符串中出现的次数
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入字符串:");
String s = scanner.next();
System.out.println("请输入要查找的字符:");
String c = scanner.next();
String[] sArr = s.split(c);
System.out.println(sArr.length-1);
for (String value : sArr) {
System.out.println(value);
}
}
就算切分后是空字符串,也会出现在字符串数组里面。
6,String不同拼接方式的对比
public static void main(String[] args) {
String s1="Hello";
String s2="World";
String s3="HelloWorld";
String s4="Hello"+"World";
String s5=s1+"World";
String s6="Hello"+s2;
String s7=s1+s2;
System.out.println(s3==s4); //true
System.out.println(s3==s5); //false
System.out.println(s3==s6); //false
System.out.println(s3==s7); //false
System.out.println(s5==s6); //false
System.out.println(s5==s7); //false
System.out.println(s6==s7); //false
String s8=s5.intern();
System.out.println(s3==s8); //true
}
- Java中有常量优化机制,“Hello"和"World"本身就是字符串常量,所以在编译时,会直接把"Hello"和"World"合并成"HelloWorld"字符串,又因为在执行s3的时候已经在常量池中创建了"HelloWorld”,所以s3==s4。
- 当变量与字面量或变量与变量进行拼接时,会在堆中创建一个StringBuilde对象,然后使用StringBuilder的append()方法将变量与字面量或变量与变量进行拼接,最后调用toString()方法转成String对象。所以s5、s6、s7指向的都是堆内存中String对象的地址值。
- 使用intern()这个方法时,首先会检查字符串常量池中是否有对应的字符串,如果存在则返回这个字符串的引用;否则会先将字符串添加到字符串常量池中,然后再返回这个字符串的引用。所以s3==s8。
7,StringBuffer与StringBuilder
StringBuffer、StringBuilder和String类似,底层也是用一个数组来存储字符串的值,并且数组的默认长度为16,即一个空的StringBuffer对象数组长度为16。实例化一个StringBuffer对象即创建了一个大小为16个字符的字符串缓冲区。但是当我们调用有参构造函数创建一个StringBuffer对象时,数组长度就不再是16了,而是根据当前对象的值来决定数组的长度,数组的长度为“当前对象的值的长+16”。所以一个 StringBuffer 创建完成之后,有16个字符的空间可以对其值进行修改。如果修改的值范围超出了16个字符,会先检查StringBuffer对象的原char数组的容量能不能装下新的字符串,如果装不下则会对 char 数组进行扩容。
StringBuffer是怎样进行扩容的呢?
扩容的逻辑就是创建一个新的 char 数组,将现有容量扩大一倍再加上2,如果还是不够大则直接等于需要的容量大小。扩容完成之后,将原数组的内容复制到新数组,最后将指针指向新的 char 数组。
常用方法:
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("abcd");
System.out.println(sb);
sb.append("efg");
System.out.println(sb);
sb.delete(1,5);
System.out.println(sb);
sb.replace(1,3,"j");
System.out.println(sb);
sb.insert(2,"1");
System.out.println(sb);
sb.reverse();
System.out.println(sb);
}
String、StringBuffer和StringBuilder的异同?
相同点:底层都是通过char数组实现的
不同点:
- String对象一旦创建,其值是不能修改的,如果要修改,会重新开辟内存空间来存储修改之后的对象;而StringBuffer和StringBuilder对象的值是可以被修改的;
- StringBuffer几乎所有的方法都使用synchronized实现了同步,线程比较安全,在多线程系统中可以保证数据同步,但是效率比较低;而StringBuilder 没有实现同步,线程不安全,在多线程系统中不能使用 StringBuilder,但是效率比较高。
- 如果我们在实际开发过程中需要对字符串进行频繁的修改,不要使用String,否则会造成内存空间的浪费;当需要考虑线程安全的场景下使用 StringBuffer,如果不需要考虑线程安全,追求效率的场景下可以使用 StringBuilder。