零基础学 Java 第四节 (字符串相关类)
本篇文章是《零基础学 Java》专栏的第四篇文章,文章采用通俗易懂的文字、图示及代码实战,从零基础开始带大家走上高薪之路!
String
本文章首发于公众号【编程攻略】
在 Java 中,我们经常使用字符串,所有的字符串值的类型均为String
,它不属于基本类型,它的全名为java.lang.String
,我们有必要在这里学习掌握一些它的基本使用方法。
字符串常量:在 Java 中所有的字符串常量均是以双引号括起来的,比如:
"abc"
等。因为它的类型是String
类型,自然,每个字符串常量均为String
的对象,也自然可以调用String
中的public
(所谓 public 就是全部开放给程序员使用的方法、属性或者类)方法。比如:"abc".indexof('b')
,它的意义就是在"abc"
中,'a'
第一次出现的位置(从 0 开始),它的结果就是 1。字符串比较:
==
和!=
在比较引用类型的数据时是比较引用是不是相同,而不是比较对象中的内容。比如:"abc" == "abc"
结果是什么?答案是true
,这意味着什么?意味着==
左右的这两个常量其实是同一个对象,并不是两个不同的具有相同字符组合的对象。所以,在你的程序中,不管你写多少个"abc"
,这些"abc"
都是同一个字符串。那么如何比较两个字符串的内容是否一样呢?我们使用
String中equals()
方法,比如:比较"abc"
和"abd"
的内容,我们可以这么写:字符串变量的初始化:所谓初始化就是获得第一个值。因为
String
类的构造方法有好几个,所以字符串变量的初始化也会有相应的几个形式,我们这里只了解常用的方式,其他方式,大家自己查看 JDK 说明书进行了解。第一种形式:
我们在学习 Java 的时候,一定要知道原理,不要只知其一不知其二。这条语句的含义是什么呢?我们知道字符串常量也是对象,所以它的意义就是把
"asdf"
的引用放入 s 这个变量中,那么s == "asdf"
的结果呢?自然也是true
。第二种形式:
大家可以看到这种形式是标准的生成类对象的形式,那么这条语句执行以后,
s == "asdf"
的结果呢?此时,就不再是true
,而是false
,它说明 s 引用的"asdf"
和作为参数传递给 String 构造方法的"asdf"
是两个不同的字符串了。这条语句的含义就是以"asdf"
为模板,再创建一个内容为asdf
的字符串对象。但是,s.equals("asdf")
的值呢?因为这两个字符串的字符序列是一致的,所以,结果为true
。常用方法表
补充解释
从上面的方法列表,我们看到有些方法名字相同,但是参数不同的情况,这种情况为方法的重载(overload),比如
valueOf
方法。所谓重载,是在同一个类中,同名但参数表不同的方法的多次定义,这些重载的方法在被调用时,Java 会根据实参的不同而决定调用不同的重载方法。Java 是根据什么区分不同的参数的呢?是根据对应位置参数的类型来区分的。有些方法的前面带有 static 这个修饰词,那么这种方法,我们称之为静态方法,这种方法是通过类名直接调用,而不必通过对象来调用。例如上表中
valueOf
这个方法,调用的时候,形如:String.valueOf(123)
。前表中,我们看到所有的方法前面都有个 public,类对外提供服务的方法,都是通过 public 这个修饰词进行标识的。我们在定义类的方法时,不是所有的方法都是
public
的,有些方法只供类(或包内、或子类可用)内部使用,这就好比大家在超市结账的时候,只需要把货物和钱款交给收银员就行了,至于收银员在随后如何盘存,都是超市内部的机制,我们无需关注一样。有些方法,如:
charAt
可能会抛出异常,但是这些异常在程序中又不必捕获,也不必声明,这是什么情况?我们可以看看这些异常都继承自哪个类:java.lang.RuntimeException
。我们这里说:凡继承自这个类的异常子类在你的程序中可以不进行捕获,也不进行声明,但是一旦发生这种类型的异常,你的程序会被毫不犹豫的中断,由系统对该异常进行处理,而系统处理的很简单,只是打印出出错栈信息,然后中断掉你的程序。所以,如果从你的程序的健壮性考虑,我们最好还是进行捕获并进行处理。
ringBuffer 和 StringBuilder
String 对象一旦创建,它的内容是不能改变的,大家可能说 String 的replace
方法不是在替换子字符串吗?我们要明确,replace
得到的是一个新的字符串,对原字符串没有任何影响。有时候,我们需要在原有字符串的基础上操作,这个时候就需要使用StringBuffer
或者StringBuilder
了。
StringBuffer
用于多线程环境,StringBuilder
用于单线程环境。这两个类中提供public方法
是一致的。在这两个类上的主要操作是 append
和 insert
方法,这两个方法以各种类型重载,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符添加或插入到字符串生成器中。append
方法始终将这些字符添加到生成器的末端;而 insert
方法则在指定的点添加字符。其他还有一些方法,大家可以参考 JDk 说明书。
我们在生成这两种类的对象时,如果不带参数,比如:StringBuffer sb = new StringBuffer()
,它会构造一个其中不带字符的字符串缓冲区,初始容量为 16 个字符。 但是如果使用的是带参数构造方法,比如:StringBuffer sb = new StringBuffer("abc");
它会构造一个字符串缓冲区,并将其内容初始化为 abc 。该字符串的初始容量为 16 加上字符串参数的长度,既是 19。也可以在创建对象的时候,通过传递一个数值来设置字符串缓冲区的大小,比如:StringBuffer sb = new StringBuffer(20);
,这里 20 就是字符串缓冲区的大小。
数组概念
一个数组就是一组数据的序列,该序列中每个元素的类型相同,可以是基本类型,也可以是引用类型。如果是基本类型,每个数组元素所在的内存空间中存放的是基本类型的数值;如果是引用类型,每个数组元素所在的内存空间中存放的是引用。如图:
数组的定义形式(两种):
int[] a1; 这种形式表明 a1 这个变量是数组变量,它的数组元素类型为 int 类型
int a1[]; 这种形式表明 a1[]数组元素的类型为 int 类型,a1 是数组变量
不管哪种形式,我们在定义的时候都不能像 C 语言一样指定数组的大小,我们通过下面的这个例子,来进一步说明它们之间的区别:
数组变量的意义:数组变量是引用类型的变量,这意味着,数组变量中存放的是数组的引用,而非数组本身,数组的存储空间是在初始化的时候在堆(所谓堆,大家可以理解做一个大仓库)中分配的,这一点同 C 语言有很大区别,这也成为 Java 数组的一个优势,数组的大小可以在运行的时候确定,而不必在定义的时候就确定下来。
数组的初始化:数组的初始化像其他类型的变量一样,既可以在定义的同时初始化,也可以在定义以后,在第一次使用的使用初始化。初始化的形式用两种:
int a[] = new int[10]; 这种形式,在堆中分配一段能够放下 10 个 int 类型数据的存储空间,并将其引用放在 a 这个数组变量中;
int a [] = { 1, 2, 3, 4, 5 }; 这种形式其实是把数组{ 1, 2, 3, 4, 5 }的引用放入了 a 中,而且这种形式只能在定义数组的同时进行。
如果数组元素为引用类型,有两种使用大括号的对数组初始化的形式:
数组元素的引用:数组元素的引用也是通过下标进行的,下标可以是一个 int 类型的表达式,但是值的范围必须在
0
至数组大小-1
这个范围内。数组元素的类型既是定义数组时所指定的类型。
多维数组
二维以上的数组就看作多维数组,数组在 Java 中的实现是采用链式存储实现的,如图:
多维数组的定义和初始化原则同一维是一样的,如下:
第一种形式,
使用 new 定义 a2 的大小:
由于在 Java 中采用链式存储数组,数组中向量的大小不必相同,比如:
甚至还可以如下例:
数组作为方法的参数
方法的参数可以是数组,在使用数组参数时需要注意以下事项:
在形参表中,数组名后的方括号不能省略,方括号个数和数组的维数相等
实参表中,数组名后不需括号
参数是数组时,形参和实参传递的是引用
示例:
数组的复制
把一个数组中的内容复制到另一个数组不能使用赋值语句a = b
,这种形式使得a
引用和b
相同的数组。如果需要复制数组,我们可以使用System
类中的 arraycopy
方法,它的方法首部如下:
从指定源数组src
中复制一个数组,从指定位置srcPos
开始,srcPos
到 srcPos+length-1
之间的length
个数组元素,到目标数组dest
的指定位置destPos
开始,destPos
到 destPos+length-1
位置。
如果参数 src
和 dest
引用相同的数组对象,则复制的执行过程就好像首先将 srcPos
到 srcPos+length-1
位置的元素复制到一个有 length
个元素的临时数组,然后再将此临时数组的内容复制到目标数组的 destPos
到 destPos+length-1
位置一样。
以下三种情况会抛出异常:
如果
src
或者dest
为null
,则抛出NullPointerException
异常。只要下列任何情况为真,则抛出
ArrayStoreException
异常并且不会修改目标数组:src
参数不是数组对象。dest
参数不是数组对象。src
和dest
引用的数组元素的类型是不一致的基本类型。src
和dest
参数引用的数组的元素为一个为基本类型,另一个为引用类型如果源数组中
srcPos
到srcPos+length-1
位置上的实际元素通过分配转换并不能全部转换成目标数组的元素类型,则抛出ArrayStoreException
异常。在这种情况下,假设复制过程已经进行到k
个(k < length)这么多,此时抛出异常,从srcPos
到srcPos+k-1
位置上的源数组元素已经被复制到目标数组中的destPos
到destPos+k-1
位置,而目标数组中的其他位置不会被修改。只要下列任何情况为真,则抛出
IndexOutOfBoundsException
异常,并且不会修改目标数组:srcPos
、destPos
、length
参数为负。srcPos+length
大于src.length
,即源数组的长度。destPos+length
大于dest.length
,即目标数组的长度
String 与字符数组
在 Java 中字符数组不能当作字符串来看待,但是我们可以使用字符数组作为模板来创建字符串,如下:
对数组的操作
对数组遍历
所谓遍历(Traversal),是指按照某种方式,依次对某种数据结构中的每个元素做一次且仅做一次的访问。对数组进行遍历通常可以使用循环语句,这里我们再介绍一个专门针对遍历的 foreach 语句,它的语法格式如下:
如下例:
对数组的排序
对数组的排序,我们当然可以自己写出各种标准的排序算法,这里介绍一个工具类java.util.Arrays
(注意是复数)。此类包含用来操作数组(比如排序和搜索)的各种方法。除非特别注明,否则如果该类中的方法的数组参数引用值为 null
,则会抛出 NullPointerException
。
升序排序
该类中有一系列对数组进行排序的方法,方法名为sort
,它的一系列重载实现,可以针对各种数组元素类型的数组进行升序排序。典型的,我们看下面的方法首部:
该方法对传入的 int
型数组a
按数字升序进行排序。该排序算法是一个经过调优的快速排序算法。
我们也可以只对数组中的某一部分进行排序,方法首部如下:
该方法对传入的 int
型数组a
中从fromIndex
到toIndex-1
的元素按数字升序进行排序。同样,它也是一个经过调优的快速排序算法。该方法可能会抛出下面的异常:
IllegalArgumentException
- 如果fromIndex > toIndex
ArrayIndexOutOfBoundsException
- 如果fromIndex < 0
或toIndex > a.length
上面的两个方法,经过重载,第一个参数可以是其他各种类型,包括基本类型和引用类型。
大家可能注意到了,上述的 sort 只能进行升序的排序,如果是其他复杂的排序方式,则就不适用了。
带有 Comparator 的排序
JDK 为我们提供了强大的排序支持,因为涉及到一些我们尚未接触的知识,这里我先只做了解。
这两个的区别在于第一个对整个数组进行排序,第二个可以选择排序范围。
数组元素的查找
对数组中元素进行查找,我们最简单但是效率可能最低下的方法就是对数组进行遍历。同样工具类java.util.Arrays
也为我们提供了可以直接使用的查找方法binarySearch
,该方法也有一系列的重载。使用该方法的前提,该数组必须是通过sort
进行过排序的。它的方法首部如下:
这两个的区别在于第一个对整个数组进行排序,第二个可以选择排序范围。经过重载,第一个参数可以是其他各种类型,包括基本类型和引用类型。
方法中a
为被查找数组,key
是需要在此数组中查找的键值,fromIndex
为起始位置,toIndex-1
为终止位置。
如果key
值包含在数组中,则返回它的索引值;否则返回 (-(插入点) - 1
)。插入点
被定义为将键插入数组的那一点:即第一个大于此键的元素索引,如果数组中的所有元素都小于指定的键,则为 a.length
或者toIndex
,这保证了当且仅当此键被找到时,返回的值将 >= 0,否则为负值。
同样,该方法也有二个带有 Comparator 的方法重载,这里不再赘述。
关于工具类java.util.Arrays
中的其他方法,大家可以查看 JDK 说明书。
问题
用筛法求 1000 以内的素数,并按每行 10 个输出出来。
最后
本文章来自公众号【编程攻略】,更多 Java 学习资料见【编程攻略】
版权声明: 本文为 InfoQ 作者【编程攻略】的原创文章。
原文链接:【http://xie.infoq.cn/article/8b1870827314067c20582b9dd】。文章转载请联系作者。
评论