【Java】—— 常用类和基础API:String、StringBuffer、StringBuilder

目录

1. 字符串相关类之不可变字符序列:String

1.1 String的特性

1.2 String的内存结构

1.2.1 概述

1.2.2 练习类型1:拼接

1.2.3 练习类型2:new

1.2.4 练习类型3:intern()

1.3 String的常用API-1

1.3.1 构造器

1.3.2 String与其他结构间的转换

1.4 String的常用API-2

1.4.1 系列1:常用方法

1.4.2 系列2:查找

1.4.3 系列3:字符串截取

1.4.4 系列4:和字符/字符数组相关

1.4.5 系列5:开头与结尾

1.4.6 系列6:替换

1.5 常见算法题目

2. 字符串相关类之可变字符序列:StringBuffer、StringBuilder

2.1 StringBuffer与StringBuilder的理解

2.2 StringBuilder、StringBuffer的API


1. 字符串相关类之不可变字符序列:String

1.1 String的特性

  • java.lang.String 类代表字符串。Java程序中所有的字符串文字(例如"hello" )都可以看作是实现此类的实例。

  • 字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。

  • 字符串String类型本身是final声明的,意味着我们不能继承String。

  • String对象的字符内容是存储在一个字符数组value[]中的。"abc" 等效于 char[] data={'h','e','l','l','o'}

  • private意味着外面无法直接获取字符数组,而且String没有提供value的get和set方法。

  • final意味着字符数组的引用不可改变,而且String也没有提供方法来修改value数组某个元素值

  • 因此字符串的字符数组内容也不可变的,即String代表着不可变的字符序列。即,一旦对字符串进行修改,就会产生新对象。

  • JDK9只有,底层使用byte[]数组。

Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持(toString()方法)。

1.2 String的内存结构

1.2.1 概述

因为字符串对象设计为不可变,那么所以字符串有常量池来保存很多常量对象。

JDK6中,字符串常量池在方法区。JDK7开始,就移到堆空间,直到目前JDK17版本。

举例内存结构分配:

1.2.2 练习类型1:拼接
String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2);
// 内存中只有一个"hello"对象被创建,同时被s1和s2共享。

对应内存结构为:(以下内存结构以JDK6为例绘制):

进一步:

1.2.3 练习类型2:new

String str1 = “abc”; 与 String str2 = new String(“abc”);的区别?

str2 首先指向堆中的一个字符串对象,然后堆中字符串的value数组指向常量池中常量对象的value数组。

  • 字符串常量存储在字符串常量池,目的是共享

  • 字符串非常量对象存储在堆中。

1.2.4 练习类型3:intern()
  • String s1 = "a";

说明:在字符串常量池中创建了一个字面量为"a"的字符串。

  • s1 = s1 + "b";

说明:实际上原来的“a”字符串对象已经丢弃了,现在在堆空间中产生了一个字符串s1+"b"(也就是"ab")。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能。

  • String s2 = "ab";

说明:直接在字符串常量池中创建一个字面量为"ab"的字符串。

  • String s3 = "a" + "b";

说明:s3指向字符串常量池中已经创建的"ab"的字符串。

  • String s4 = s1.intern();

说明:堆空间的s1对象在调用intern()之后,会将常量池中已经存在的"ab"字符串赋值给s4。

结论:

(1)常量+常量:结果是常量池。且常量池中不会存在相同内容的常量。

(2)常量与变量 或 变量与变量:结果在堆中

(3)拼接后调用intern方法:返回值在常量池中

1.3 String的常用API-1

1.3.1 构造器
  • public String() :初始化新创建的 String对象,以使其表示空字符序列。

  • String(String original): 初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。

  • public String(char[] value) :通过当前参数中的字符数组来构造新的String。

  • public String(char[] value,int offset, int count) :通过字符数组的一部分来构造新的String。

  • public String(byte[] bytes) :通过使用平台的默认字符集解码当前参数中的字节数组来构造新的String。

  • public String(byte[] bytes,String charsetName) :通过使用指定的字符集解码当前参数中的字节数组来构造新的String。

1.3.2 String与其他结构间的转换

字符串 --> 基本数据类型、包装类:

  • Integer包装类的public static int parseInt(String s):可以将由“数字”字符组成的字符串转换为整型。

  • 类似地,使用java.lang包中的Byte、Short、Long、Float、Double类调相应的类方法可以将由“数字”字符组成的字符串,转化为相应的基本数据类型

基本数据类型、包装类 --> 字符串:

  • 调用String类的public String valueOf(int n)可将int型转换为字符串

  • 相应的valueOf(byte b)、valueOf(long l)、valueOf(float f)、valueOf(double d)、valueOf(boolean b)可由参数的相应类型到字符串的转换。

字符数组 --> 字符串:

  • String 类的构造器:String(char[]) 和 String(char[],int offset,int length) 分别用字符数组中的全部字符和部分字符创建字符串对象。

字符串 --> 字符数组:

  • public char[] toCharArray():将字符串中的全部字符存放在一个字符数组中的方法。

  • public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin):提供了将指定索引范围内的字符串存放到数组中的方法。

字符串 --> 字节数组:(编码)

  • public byte[] getBytes() :使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。

  • public byte[] getBytes(String charsetName) :使用指定的字符集将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。

字节数组 --> 字符串:(解码)

  • String(byte[]):通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。

  • String(byte[],int offset,int length) :用指定的字节数组的一部分,即从数组起始位置offset开始取length个字节构造一个字符串对象。

  • String(byte[], String charsetName ) 或 new String(byte[], int, int,String charsetName ):解码,按照指定的编码方式进行解码

代码示例:

public void test01() throws Exception {
    String str = "中国";
    System.out.println(str.getBytes("ISO8859-1").length);// 2
    // ISO8859-1把所有的字符都当做一个byte处理,处理不了多个字节
    System.out.println(str.getBytes("GBK").length);// 4 每一个中文都是对应2个字节
    System.out.println(str.getBytes("UTF-8").length);// 6 常规的中文都是3个字节

    /*
     * 不乱码:(1)保证编码与解码的字符集名称一样(2)不缺字节
     */
    System.out.println(new String(str.getBytes("ISO8859-1"), "ISO8859-1"));// 乱码
    System.out.println(new String(str.getBytes("GBK"), "GBK"));// 中国
    System.out.println(new String(str.getBytes("UTF-8"), "UTF-8"));// 中国
}

1.4 String的常用API-2

String 类包括的方法可用于检查序列的单个字符、比较字符串、搜索字符串、提取子字符串、创建字符串副本并将所有字符全部转换为大写或小写。

1.4.1 系列1:常用方法

(1)boolean isEmpty():字符串是否为空

(2)int length():返回字符串的长度

(3)String concat(xx):拼接

(4)boolean equals(Object obj):比较字符串是否相等,区分大小写

(5)boolean equalsIgnoreCase(Object obj):比较字符串是否相等,不区分大小写

(6)int compareTo(String other):比较字符串大小,区分大小写,按照Unicode编码值比较大小 (7)int compareToIgnoreCase(String other):比较字符串大小,不区分大小写

(8)String toLowerCase():将字符串中大写字母转为小写

(9)String toUpperCase():将字符串中小写字母转为大写

(10)String trim():去掉字符串前后空白符

(11)public String intern():结果在常量池中共享

1.4.2 系列2:查找

(11)boolean contains(xx):是否包含xx

(12)int indexOf(xx):从前往后找当前字符串中xx,即如果有返回第一次出现的下标,要是没有返回-1

(13)int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始

(14)int lastIndexOf(xx):从后往前找当前字符串中xx,即如果有返回最后一次出现的下标,要是没有返回-1

(15)int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。

1.4.3 系列3:字符串截取

(16)String substring(int beginIndex) :返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。

(17)String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。

1.4.4 系列4:和字符/字符数组相关

(18)char charAt(index):返回[index]位置的字符

(19)char[] toCharArray(): 将此字符串转换为一个新的字符数组返回

(20)static String valueOf(char[] data) :返回指定数组中表示该字符序列的 String

(21)static String valueOf(char[] data, int offset, int count) : 返回指定数组中表示该字符序列的 String

(22)static String copyValueOf(char[] data): 返回指定数组中表示该字符序列的 String

(23)static String copyValueOf(char[] data, int offset, int count):返回指定数组中表示该字符序列的 String

1.4.5 系列5:开头与结尾

(24)boolean startsWith(xx):测试此字符串是否以指定的前缀开始

(25)boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定前缀开始

(26)boolean endsWith(xx):测试此字符串是否以指定的后缀结束

1.4.6 系列6:替换

(27)String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。 不支持正则。

(28)String replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。

(29)String replaceAll(String regex, String replacement):使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。

(30)String replaceFirst(String regex, String replacement):使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。

1.5 常见算法题目

题目1:模拟一个trim方法,去除字符串两端的空格。

public String myTrim(String str) {
		if (str != null) {
			int start = 0;// 用于记录从前往后首次索引位置不是空格的位置的索引
			int end = str.length() - 1;// 用于记录从后往前首次索引位置不是空格的位置的索引

			while (start < end && str.charAt(start) == ' ') {
				start++;
			}

			while (start < end && str.charAt(end) == ' ') {
				end--;
			}
			if (str.charAt(start) == ' ') {
				return "";
			}

			return str.substring(start, end + 1);
		}
		return null;
	}

	@Test
	public void testMyTrim() {
		String str = "   a   ";
		// str = " ";
		String newStr = myTrim(str);
		System.out.println("---" + newStr + "---");
	}

题目2:将一个字符串进行反转。将字符串中指定部分进行反转。比如“abcdefg”反转为”abfedcg”

	// 方式一:
	public String reverse1(String str, int start, int end) {// start:2,end:5
		if (str != null) {
			// 1.
			char[] charArray = str.toCharArray();
			// 2.
			for (int i = start, j = end; i < j; i++, j--) {
				char temp = charArray[i];
				charArray[i] = charArray[j];
				charArray[j] = temp;
			}
			// 3.
			return new String(charArray);

		}
		return null;

	}

	// 方式二:
	public String reverse2(String str, int start, int end) {
		// 1.
		String newStr = str.substring(0, start);// ab
		// 2.
		for (int i = end; i >= start; i--) {
			newStr += str.charAt(i);
		} // abfedc
			// 3.
		newStr += str.substring(end + 1);
		return newStr;
	}

	// 方式三:推荐 (相较于方式二做的改进)
	public String reverse3(String str, int start, int end) {// ArrayList list = new ArrayList(80);
		// 1.
		StringBuffer s = new StringBuffer(str.length());
		// 2.
		s.append(str.substring(0, start));// ab
		// 3.
		for (int i = end; i >= start; i--) {
			s.append(str.charAt(i));
		}

		// 4.
		s.append(str.substring(end + 1));

		// 5.
		return s.toString();

	}

	@Test
	public void testReverse() {
		String str = "abcdefg";
		String str1 = reverse3(str, 2, 5);
		System.out.println(str1);// abfedcg

	}

2. 字符串相关类之可变字符序列:StringBuffer、StringBuilder

        因为String对象是不可变对象,虽然可以共享常量对象,但是对于频繁字符串的修改和拼接操作,效率极低,空间消耗也比较高。因此,JDK又在java.lang包提供了可变字符序列StringBuffer和StringBuilder类型。

2.1 StringBuffer与StringBuilder的理解

  • java.lang.StringBuffer代表可变的字符序列,JDK1.0中声明,可以对字符串内容进行增删,此时不会产生新的对象。比如:

  • StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且提供相关功能的方法也一样。

  • 区分String、StringBuffer、StringBuilder

    • String:不可变的字符序列; 底层使用char[]数组存储(JDK8.0中)

    • StringBuffer:可变的字符序列;线程安全(方法有synchronized修饰),效率低;底层使用char[]数组存储 (JDK8.0中)

    • StringBuilder:可变的字符序列; jdk1.5引入,线程不安全的,效率高;底层使用char[]数组存储(JDK8.0中)

2.2 StringBuilder、StringBuffer的API

StringBuilder、StringBuffer的API是完全一致的,并且很多方法与String相同。

1、常用API

(1)StringBuffer append(xx):提供了很多的append()方法,用于进行字符串追加的方式拼接

(2)StringBuffer delete(int start, int end):删除[start,end)之间字符

(3)StringBuffer deleteCharAt(int index):删除[index]位置字符

(4)StringBuffer replace(int start, int end, String str):替换[start,end)范围的字符序列为str

(5)void setCharAt(int index, char c):替换[index]位置字符

(6)char charAt(int index):查找指定index位置上的字符

(7)StringBuffer insert(int index, xx):在[index]位置插入xx

(8)int length():返回存储的字符数据的长度

(9)StringBuffer reverse():反转

  • 当append和insert时,如果原来value数组长度不够,可扩容。

  • 如上(1)(2)(3)(4)(9)这些方法支持方法链操作。原理:

2、其它API

(1)int indexOf(String str):在当前字符序列中查询str的第一次出现下标

(2)int indexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str的第一次出现下标

(3)int lastIndexOf(String str):在当前字符序列中查询str的最后一次出现下标

(4)int lastIndexOf(String str, int fromIndex):在当前字符序列[fromIndex,最后]中查询str的最后一次出现下标

(5)String substring(int start):截取当前字符序列[start,最后]

(6)String substring(int start, int end):截取当前字符序列[start,end)

(7)String toString():返回此序列中数据的字符串表示形式

(8)void setLength(int newLength) :设置当前字符序列长度为newLength

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值