Java核心技术第3章(3)

3.6 字符串

从概念上将, Java字符串就是Unicode字符序列.Java没有内置的字符串类型,而是在标准Java类库中提供了一个预定义类,叫做String.每个用双引号括起来的字符串都是String类的一个实例:
String e = "";					// an empty string
String greeting = "hello";		

3.6.1 子串

String类的substring方法可以从一个较大的字符串提取出一个子串,例如:
String greeting = "hello";
String s = greeting.subString(0, 3);
创建了一个由字符"hel"组成的字符串.
substring方法的第二个参数是不想复制的第一个位置.这里要复制位置为0,1,2的字符.
substring的工作方式有一个优点:容易计算子串的长度.字符串s.substring(a,b)的长度为b-a.

3.6.2 拼接

Java语言语序使用+号连接(拼接)两个字符串.
String expletive = "Expletive";
String PG13 = "deleted";
String message = expletive + PG13;
上述代码将"Expletivedeleted"赋给变量message。
当将一个字符串与一个非字符串的值进行拼接时,后者被转换成字符串(任何一个Java对象都可以转换成字符串).例如:
int age = 13;
String rating = "PG" + age;
rating被设置为"PG13";
这种特性通常用在输出语句中.例如:
System.out.println("The answer is " + answer);

3.6.3 不可变字符串

String类没有提供用于修改字符串的方法.如果希望将greeting的内容修改为"Help!",不能直接将greeting的最后两个位置的字符修改为'p'和'!'.如何 修改这个字符串呢? 在Java中,应该首先提取需要的字符,然后再拼接上替换的字符串:
greeting = greeting.substring(0, 3) + "p!";
上面这条语句将greeting修改为"Help!".
由于不能修改Java字符串中的字符,所以在Java文档中将 String类对象称为不可变字符串. 不能修改字符串中的任何一个字符,但可以修改字符串变量greeting,让它引用另外一个字符串.
这样是否会降低运行效率呢?看起来好像修改一个代码单元要比创建一个新字符串更加简洁.答案是:也对,也不对.的确,通过拼接"Hel"和"p!"来创建一个新字符串的效率确实不高.但是, 不可变字符串却有一个优点:编译器可以让字符串共享.
为了弄清楚具体的工作方式,可以想象将各种字符串存放在公共的存储池中.字符串变量指向存储池中相应的位置.如果复制一个字符串变量,原始字符串与复制的字符串共享相同的字符.
总而言之,Java的设计者认为共享带来的高效率远远胜于提取,拼接字符串所带来的低效率.查看程序会发现:很少需要修改字符串,而是往往需要对字符串进行比较.
注释:C程序员第一次接触Java字符串的时候,常常会感到疑惑,因为总是将字符串认为是字符型数组:
char greeting[] = "hello";
这种认识是错误的, Java字符串更像 char* 指针.
char* greeting = "hello";
当采取另一个字符串替换greeting的时候,Java代码主要进行下列操作:
char* temp = malloc(6);
strncpy(tmp, greeting, 3);
strncpy(temp + 3, "p!", 3);
greeting = temp;
的确,现在greeting指向字符串"help!".Java要比一连串的strncpy调用舒适的多.然而如果将greeting赋予另外一个值又会怎么样呢?
greeting = "howdy";
这样做会不会产生内存泄露呢?毕竟,原始字符串放置在堆中.十分幸运,Java将自动地进行垃圾回收.如果一块内存不再使用了,系统最终会将其回收.
C++ string对象也自动地进行内存的分配与回收.内存管理是通过构造器,赋值操作和析构器显式执行的.然而,C++字符串是可修改的.也就是说,可修改字符串中的单个字符.

3.6.4 检测字符串是否相等

可以使用equals方法检测两个字符串是否相等.对于表达式:
s.equals(t)
如果字符串s与字符串t相等,则返回 true;否则返回 false.s与t可以是字符串变量,也可以是字符串常量.
要检测两个字符串是否相等,而不区分大小写,可以使用equalsIgnoreCase方法.
"hello".equalsIgnoreCase("Hello");
一定不能使用==运算符检测两个字符串是否相等.这个运算符 只能确定两个字符串是否放置在同一个位置上.当然,如果字符串放置在同一个位置上,它们必然相等.但是,完全有可能将内容相同的多个字符串的拷贝放置在不同的位置上.
String greeting = "hello";
if (greeting == "hello")
    // probably true
if (greeting.substring(0, 3) == "hel")
    // probably false
    如果虚拟机始终将相同的字符串共享,就可以使用 == 运算符检测是否相等.但实际上, 只有字符串常量是共享,而 + 或 substring 等操作符产生的结果并不是共享的.因此,千万不要使用 == 运算符检测字符串的相等性.
    注释
:C++的string类重载了 == 运算符以便检测字符串内容的相等性.可惜Java没有采用这种方式,它的字符串"看起来,感觉起来"与数值一样,但进行相等性测试时,其操作方式又类似于指针.
    C程序员不实用 == 对字符串进行比较,而是用stcmpy函数.Java的compareTo方法与strcmp完全类似,因此可以这样使用:
if (greeting.compareTo("hello") == 0)
    不过使用equals看起来更为清晰.

3.6.5   空串与Null串

    空串""是长度为0的字符串.可以调用以下代码检测字符串是否为空:
if (str.length() == 0)
    或
if (str.equals("")
    空串是一个Java对象,有自己的串长度(0)和内容(空).不过String变量还可以存放一个特殊的值,名为 null,这表示目前没有任何对象与该变量关联.要检查一个字符串是否为null,要使用以下条件:
if (str == null)
    有时候要检查一个字符串既不是null也不为空串,这种情况下就需要使用以下条件:
if (str != null && str.length() != 0)
    首先要检查str不为null(如果在null值上调用方法,会出现错误).

3.6.6   代码点与代码单元

    Java字符串由 char 序列组成,char 数据类型是采用UTF-16编码表示Unicode代码点的代码单元.大多数的常用Unicode字符使用一个代码单元就可以表示,而辅助字符需要一对代码单元表示.
    length方法将返回UTF-16编码表示的给定字符串所需要的 代码单元数量.例如:
String greeting = "hello";
int n = greeeting.length();     // is 5
    要想得到实际的长度,即代码点的长度,可以调用:
int cpCount = greeting.codePointCount(0, greeting.length());

3.6.7   字符串API

    Java中的String类包含了50多个方法.绝大多数都非常有用.
    注释:本书中每一个API的注释都以形如java.lang.String的类名开始.类名之后是一个或多个方法的名字,解释和参数描述.
char charAt(int index)
    返回给定位置的代码单元,除非对底层的代码单元感兴趣,否则不需要使用这个方法.
int codePointAt(index)
    返回从给定位置开始或结束的代码点
int offsetByCodePoints(int startIndex, int cpCount);
    返回从startIndex代码点开始,位移cpCount后的代码点索引
int compareTo(String other)
    按照字典顺序,如果字符串位于other之前,返回一个负数;如果字符串位于other之后,返回一个正数;如果两个字符串相等,返回0.
boolean endsWith(String suffix)
    如果字符串以suffix结尾,返回 true
boolean equals(Object other)
    如果字符串与other相等,返回 true
boolean equalsIgnoreCast(String other)
    如果字符串与other相等(忽略大小写),返回 true
int index0f(String str)
int index0f(String str, int fromIndex)
int index0f(int cp)
int index0f(int cp, int fromIndex)
    返回与字符串str或代码点cp匹配的第一个子串的开始位置.这个位置从索引0或fromIndex开始计算.如果在原始串中不存在str,返回-1
int lastIndex0f(String str)
int lastIndex0f(String str, int fromIndex)
int lastIndex0f(int cp)
int lastIndex0f(int cp, int fromIndex)
    返回与字符串st或代码点cp匹配的最后一个子串的开始位置.这个位置从原始串尾端或fromIndex开始计算.
int length()
    返回字符串的长度
int codePointCount(int startIndex, int endIndex)
    返回startIndex和endIndex-1之间的代码点数量.没有配对成的代用字符将计入代码点
String replace(CharSequence oldString, CharSequence newString)
    返回一个新字符串.这个字符串用newString代替原始字符串中所有的oldString.可以用String或StringBuilder对象作为CharSequence参数.
boolean startsWith(String prefix)
    如果字符串以prefix字符串开始,返回 true
String substring(int beginIndex)
String substring(int beginIndex, int endIndex)
    返回一个新字符串.这个字符串包含原始字符串中从beginIndex到串尾货endIndex-1的所有代码单元
String toLowerCase()
    返回一个新字符串.这个字符串将原始字符串中的所有大写字母改成小写字母
String toUpperCase()
    返回一个新字符串.这个字符串将原始字符串中的所有小写字母改成大写字母
String trim()
    返回一个新字符串.这个字符串将删除原始字符串中头部和尾部的空格

3.6.8   阅读联机API文档

    到官网下载API http://www.oracle.com/technetwork/java/javase/documentation/jdk8-doc-downloads-2133158.html.

3.6.9   构建字符串

    有时候,需要由较短的字符串构建字符串. 采用字符串连接的方式达成此目的的效率比较低.每次连接字符串,都会构建一个新的String对象,既耗时,又浪费空间.使用StringBuilder类就可以避免这个问题的发生.
    如果需要许多小段的字符串构建一个字符串,那么应该按照下列步骤进行.首先构建一个空的字符串构建器:
StringBuilder builder = new StringBuilder();
    当每次需要添加一部分内容时,就调用append方法.
builder.append(ch);             // appends a single character
builder.append(str);            // appends a string
    在需要构建字符串时就调用toString方法,将可以得到一个String对象,其中包含了构建器中的字符序列.
String completedString = builder.toString();
    下面的API注释包含了StringBuilder类中的重要方法.
StringBuilder()
    构造一个空的字符串构建器
int length()
    返回构建器或缓冲器中的代码单元数量
StringBuilder append(String str)
    追加一个字符串并返回 this
StringBuilder append(char c)
    追加一个代码单元并返回 this 
StringBuilder appendCodePoint(int cp)
    追加一个代码点,并将其转换为一个或两个代码单元并返回 this
void setCharAt(int i, char c)
    将第 i 个代码单元设置为 c
<pre name="code" class="java">StringBuilder insert(int offset, String str)
     在offset位置插入一个字符串并返回 this 

StringBuilder insert(int offset, char c)
    在offset位置插入一个代码单元并返回 this
StringBuilder delete(int startIndex, int endIndex)
    删除偏移量从startIndex到endIndex-1 的代码单元并返回 this
String toString()
    返回一个与构建器或缓冲器内容相同的字符串
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值