《Java 编程的逻辑》笔记——第7章 常用基础类(二)

声明:

本博客是本人在学习《Java 编程的逻辑》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。

本博客已标明出处,如有侵权请告知,马上删除。

7.2 剖析 String

字符串操作是计算机程序中最常见的操作之一。Java 中处理字符串的主要类是 String 和 StringBuilder,本节介绍 String。先介绍基本用法,然后介绍实现原理,随后介绍编码转换,分析 String 的不可变性、常量字符串、hashCode 和正则表达式。

7.2.1 基本用法

可以通过常量定义 String 变量

String name = "老马说编程";

也可以通过 new 创建 String 变量

String name = new String("老马说编程");

String 可以直接使用 + 和 += 运算符,如:

String name = "老马";
name+= "说编程";
String descritpion = ",探索编程本质";
System.out.println(name+descritpion); 

输出为:老马说编程,探索编程本质

String 类包括很多方法,以方便操作字符串,比如:

public boolean isEmpty() // 判断字符串是否为空
public int length() // 获取字符串长度
public String substring(int beginIndex) // 取子字符串
public String substring(int beginIndex, int endIndex) // 取子字符串
public int indexOf(int ch) // 在字符串中查找字符,返回第一个找到的索引位置,没找到返回-1
public int indexOf(String str) // 在字符串中查找子字符串,返回第一个找到的索引位置,没找到返回-1
public int lastIndexOf(int ch) // 从后面查找字符,返回从后面数的第一个索引位置,没找到返回-1
public int lastIndexOf(String str) // 从后面查找子字符串,返回从后面数的第一个索引位置,没找到返回-1
public boolean contains(CharSequence s)  // 判断字符串中是否包含指定的字符序列
public boolean startsWith(String prefix) // 判断字符串是否以给定子字符串开头
public boolean endsWith(String suffix) // 判断字符串是否以给定子字符串结尾
public boolean equals(Object anObject) // 与其他字符串比较,看内容是否相同
public boolean equalsIgnoreCase(String anotherString) // 忽略大小写,与其他字符串进行比较,看内容是否相同
public int compareTo(String anotherString) // 比较字符串大小
public int compareToIgnoreCase(String str) // 忽略大小写比较
public String toUpperCase() // 所有字符转换为大写字符,返回新字符串,原字符串不变
public String toLowerCase() // 所有字符转换为小写字符,返回新字符串,原字符串不变
public String concat(String str) // 字符串连接,返回当前字符串和参数字符串合并后的字符串,原字符串不变
public String replace(char oldChar, char newChar) // 字符串替换,替换单个字符,返回新字符串,原字符串不变
public String replace(CharSequence target, CharSequence replacement) // 字符串替换,替换字符序列,返回新字符串,原字符串不变
public String trim() // 删掉开头和结尾的空格,返回新字符串,原字符串不变
public String[] split(String regex) // 分隔字符串,返回分隔后的子字符串数组,原字符串不变

看个 String 的简单例子,按逗号分隔 “hello,world”:

String str = "hello,world";
String[] arr = str.split(",");

arr[0] 为 “hello”, arr[1] 为 “world”。

从调用者的角度理解了 String 的基本用法,下面我们进一步来理解 String 的内部。

7.2.2 走进 String 内部

7.2.2.1 封装字符数组

String 类内部用一个字符数组表示字符串,实例变量定义为:

private final char value[];

String 有两个构造方法,可以根据 char 数组创建 String

public String(char value[])
public String(char value[], int offset, int count)

需要说明的是,String 会根据参数新创建一个数组,并拷贝内容,而不会直接用参数中的字符数组

String 中的大部分方法,内部也都是操作的这个字符数组。比如说:

  • length() 方法返回的就是这个数组的长度
  • substring() 方法就是根据参数,调用构造方法 String(char value[], int offset, int count) 新建了一个字符串
  • indexOf 查找字符或子字符串时就是在这个数组中进行查找

这些方法的实现大多比较直接,我们就不赘述了。

String 中还有一些方法,与这个 char 数组有关:

返回指定索引位置的 char

public char charAt(int index)

返回字符串对应的 char 数组

public char[] toCharArray()

注意,返回的是一个拷贝后的数组,而不是原数组。

将 char 数组中指定范围的字符拷贝入目标数组指定位置

public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) 

7.2.2.2 按 Code Point 处理字符

与 Character 类似,String 类也提供了一些方法,按 Code Point 对字符串进行处理。

public int codePointAt(int index)
public int codePointBefore(int index)
public int codePointCount(int beginIndex, int endIndex)
public int offsetByCodePoints(int index, int codePointOffset)

7.2.3 编码转换

String 内部是按 UTF-16BE 处理字符的,对 BMP 字符,使用一个 char,两个字节,对于增补字符,使用两个 char,四个字节。我们在 2.3 节介绍过各种编码,不同编码可能用于不同的字符集,使用不同的字节数目,和不同的二进制表示。如何处理这些不同的编码呢?这些编码与 Java 内部表示之间如何相互转换呢?

Java 使用 Charset 这个类表示各种编码,它有两个常用静态方法

public static Charset defaultCharset()
public static Charset forName(String charsetName) 

第一个方法返回系统的默认编码,比如,在我的电脑上,执行如下语句:

System.out.println(Charset.defaultCharset().name());

输出为 UTF-8

第二方法返回给定编码名称的 Charset 对象,与我们在 2.3 节介绍的编码相对应,其 charset 名称可以是 US-ASCII, ISO-8859-1, windows-1252, GB2312, GBK, GB18030, Big5, UTF-8,比如:

Charset charset = Charset.forName("GB18030");

String 类提供了如下方法,返回字符串按给定编码的字节表示

public byte[] getBytes()  
public byte[] getBytes(String charsetName)
public byte[] getBytes(Charset charset) 

第一个方法没有编码参数,使用系统默认编码,第二方法参数为编码名称,第三个为 Charset。

String 类有如下构造方法,可以根据字节和编码创建字符串,也就是说,根据给定编码的字节表示,创建 Java 的内部表示。

public String(byte bytes[])
public String(byte bytes[], int offset, int length)
public String(byte bytes[], int offset, int length, String charsetName)
public String(byte bytes[], int offset, int length, Charset charset)
public String(byte bytes[], String charsetName)
public String(byte bytes[], Charset charset)

除了通过 String 中的方法进行编码转换,Charset 类中也有一些方法进行编码/解码,本节就不介绍了。重要的是认识到,Java 的内部表示与各种编码是不同的,但可以相互转换。

7.2.4 不可变性

与包装类类似,String 类也是不可变类,即对象一旦创建,就没有办法修改了。String 类也声明为了 final,不能被继承,内部 char 数组 value 也是 final 的,初始化后就不能再变了。

String 类中提供了很多看似修改的方法,其实是通过创建新的 String 对象来实现的,原来的 String 对象不会被修改。比如说,我们来看 concat() 方法的代码:

public String concat(String str) {
   
    int otherLen = str.length();
    if (otherLen == 0) {
   
        return this;
    }
    int len = value.length;
    char buf[] = Arrays.copyOf(value, len + otherLen);
    str.getChars(buf, len);
    return new String(buf, true);
}

通过 Arrays.copyOf 方法创建了一块新的字符数组,拷贝原内容,然后通过 new 创建了一个新的 String。关于 Arrays 类,我们将在后续章节详细介绍。

与包装类类似,定义为不可变类,程序可以更为简单、安全、容易理解。但如果频繁修改字符串,而每次修改都新建一个字符串,性能太低,这时,应该考虑 Java 中的另两个类 StringBuilder 和 StringBuffer,我们在下节介绍它们。

7.2.5 常量字符串

Java 中的字符串常量是非常特殊的,除了可以直接赋值给 String 变量外,它自己就像一个 String 类型的对象一样,可以直接调用 String 的各种方法。我们来看代码:

System.out.println("老马说编程".length());
System.out.println("老马说编程".contains("老马"));
System.out.println("老马说编程"
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bm1998

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值