共计 10560 个字符,预计需要花费 27 分钟才能阅读完成。
本篇文章是《零根底学 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"
的内容,咱们能够这么写:"abc".equals("abd") 或者 "abd".equals("abc")
-
字符串变量的初始化:所谓初始化就是取得第一个值。因为
String
类的构造方法有好几个,所以字符串变量的初始化也会有相应的几个模式,咱们这里只理解罕用的形式,其余形式,大家本人查看 JDK 说明书进行理解。-
第一种模式:
String s = "asdf";
咱们在学习 Java 的时候,肯定要晓得原理,不要只知其一不知其二。这条语句的含意是什么呢?咱们晓得字符串常量也是对象,所以它的意义就是把
"asdf"
的援用放入 s 这个变量中,那么s == "asdf"
的后果呢?天然也是true
。 -
第二种模式:
String s = new String("asdf");
大家能够看到这种模式是规范的生成类对象的模式,那么这条语句执行当前,
s == "asdf"
的后果呢?此时,就不再是true
,而是false
,它阐明 s 援用的"asdf"
和作为参数传递给 String 构造方法的"asdf"
是两个不同的字符串了。这条语句的含意就是以"asdf"
为模板,再创立一个内容为asdf
的字符串对象。然而,s.equals("asdf")
的值呢?因为这两个字符串的字符序列是统一的,所以,后果为true
。
-
- 罕用办法表
办法首部 | 办法性能 | 可能抛出的异样 |
---|---|---|
public char charAt(int index) | 返回指定索引处的 char 值。索引范畴为从 0 到 length() – 1。序列的第一个 char 值位于索引 0 处,第二个位于索引 1 处,依此类推,这相似于数组索引。 | index 的值如果不在字符串长度范畴内,会产生IndexOutOfBoundsException ,该异样能够不进行捕捉。 |
public boolean contains(CharSequence s) | 当且仅当此字符串蕴含指定的 s 字符序列时,返回 true。 | NullPointerException – 如果 s 为 null,该异样能够不进行捕捉 |
public boolean equals(Object anObject) | 将此字符串与指定的对象比拟。当且仅当该参数不为 null,并且是与此对象示意雷同字符序列的 String 对象时,后果才为 true。 | 无 |
public boolean equalsIgnoreCase(String anotherString) | 将此 String 与另一个 String 比拟,不思考大小写。如果两个字符串的长度雷同,并且其中的相应字符都相等(疏忽大小写),则认为这两个字符串是相等的。 | 无 |
public int compareTo(String anotherString) | 如果参数字符串等于此字符串,则返回值 0;如果此字符串按字典程序小于字符串参数,则返回一个小于 0 的值;如果此字符串按字典程序大于字符串参数,则返回一个大于 0 的值。 | 无 |
public int compareToIgnoreCase(String str) | 按字典程序比拟两个字符串,不思考大小写。依据指定 String 大于、等于还是小于此 String(不思考大小写),别离返回一个负整数、0 或一个正整数。 | 无 |
public int indexOf(int ch) | 在此对象示意的字符序列中第一次呈现该字符的索引;如果未呈现该字符,则返回 -1。 | 无 |
public int indexOf(int ch,int fromIndex) | 从指定的索引(含)开始搜寻,返回在此字符串中第一次呈现指定字符处的索引,否则返回 -1。 | 无 |
public int indexOf(String str) | 如果字符串参数作为一个子字符串在此对象中呈现,则返回第一个这种子字符串的第一个字符的索引;如果它不作为一个子字符串呈现,则返回 -1。 | 无 |
public int indexOf(String str,int fromIndex) | 从指定的索引开始,返回指定子字符串在此字符串中第一次呈现处的索引,否则返回 -1。 | 无 |
public boolean isEmpty() | 如果 length() 为 0,则返回 true;否则返回 false。 | 无 |
public int lastIndexOf(int ch) | 在此字符序列中最初一次呈现该字符的索引;如果未呈现该字符,则返回 -1。 | 无 |
public int lastIndexOf(int ch,int fromIndex) | 从指定的索引处开始进行反向搜寻,返回指定字符在此字符串中最初一次呈现处的索引。如果在该点之前未呈现该字符,则返回 -1。 | 无 |
public int lastIndexOf(String str) | 如果字符串参数作为一个子字符串在此对象中呈现一次或屡次,则返回最初一个这种子字符串的第一个字符。如果它不作为一个子字符串呈现,则返回 -1。 | 无 |
public int lastIndexOf(String str,int fromIndex) | 返回指定子字符串在此字符串中最初一次呈现处的索引,从指定的索引开始反向搜寻。如果在该点之前未呈现该字符串,则返回 -1。 | 无 |
public int length() | 返回此字符串的长度。 | 无 |
public String replace(char oldChar,char newChar) | 返回一个新的字符串,它是通过用 newChar 替换此字符串中呈现的所有 oldChar 失去的。 | 无 |
public String replace(CharSequence target,CharSequence replacement) | 应用指定的 replacement 替换此字符串所有匹配 target 的子字符串。该替换从字符串的结尾朝开端执行,例如,用 “b” 替换字符串 “aaa” 中的 “aa” 将生成 “ba” 而不是 “ab”。 | NullPointerException – 如果 target 或 replacement 为 null。。该异样不用捕捉。 |
public String substring(int beginIndex) | 返回一个新的字符串,它是此字符串的一个子字符串。该子字符串从指定索引处(含)的字符开始,直到此字符串开端。示例:“unhappy”.substring(2) 返回 “happy” | IndexOutOfBoundsException – 如果 beginIndex 为负或大于此 String 对象的长度。该异样不用捕捉。 |
public String substring(int beginIndex,int endIndex) | 返回一个新字符串,它是此字符串的一个子字符串。该子字符串从指定的 beginIndex 处开始,直到索引 endIndex – 1 处的字符。因而,该子字符串的长度为 endIndex-beginIndex。示例:“hamburger”.substring(4, 8) returns “urge” | IndexOutOfBoundsException – 如果 beginIndex 为负,或 endIndex 大于此 String 对象的长度,或 beginIndex 大于 endIndex。该异样不用捕捉。 |
public String toLowerCase() | 应用默认语言环境的规定将此 String 中的所有字符都转换为小写。 | 无 |
public String toUpperCase() | 应用默认语言环境的规定将此 String 中的所有字符都转换为大写。 | 无 |
public String trim() | 返回字符串的正本,疏忽前导空白和尾部空白。 | 无 |
public static String valueOf(boolean b) | 如果参数为 true,则返回一个等于 “true” 的字符串;否则,返回一个等于 “false” 的字符串。 | 无 |
public static String valueOf(char c) | 返回 char 参数的字符串示意模式。例如:String.valueOf(‘a’)的值为 ”a” | 无 |
public static String valueOf(char[] data) | 一个新调配的字符串,它示意蕴含在字符数组参数中的雷同字符序列。 | 无 |
public static String valueOf(char[] data,int offset,int count) | 返回由 data 数组中从 offset 开始的 count 个数组元素组成字符串 | IndexOutOfBoundsException – 如果 offset 为负,count 为负,或者 offset+count 大于 data.length。该异样能够不捕捉。 |
public static String valueOf(double d) | 返回 double 参数的字符串示意模式。同单参数的 Double.toString 办法返回的后果统一。 | 无 |
public static String valueOf(float f) | 返回 float 参数的字符串示意模式。同单参数的 Float.toString 办法返回的后果统一。 | 无 |
public static String valueOf(int i) | 返回 int 参数的字符串示意模式。同单参数的 Integer.toString 办法返回的后果统一。 | 无 |
public static String valueOf(long l) | 返回 long 参数的字符串示意模式。同单参数的 Long.toString 办法返回的后果统一。 | 无 |
public static String valueOf(Object obj) | 如果参数为 null,则字符串等于 “null”;否则,返回 obj.toString() 的值。 | 无 |
-
补充解释
- 从下面的办法列表,咱们看到有些办法名字雷同,然而参数不同的状况,这种状况为办法的重载(overload),比方
valueOf
办法。所谓重载,是在同一个类中,同名但参数表不同的办法的屡次定义,这些重载的办法在被调用时,Java 会依据实参的不同而决定调用不同的重载办法。Java 是依据什么辨别不同的参数的呢?是依据对应地位参数的类型来辨别的。 - 有些办法的后面带有 static 这个修饰词,那么这种办法,咱们称之为静态方法,这种办法是通过类名间接调用,而不用通过对象来调用。例如上表中
valueOf
这个办法,调用的时候,形如:String.valueOf(123)
。 - 前表中,咱们看到所有的办法后面都有个 public,类对外提供服务的办法,都是通过 public 这个修饰词进行标识的。咱们在定义类的办法时,不是所有的办法都是
public
的,有些办法只供类(或包内、或子类可用)外部应用,这就好比大家在超市结账的时候,只须要把货物和钱款交给收银员就行了,至于收银员在随后如何盘存,都是超市外部的机制,咱们无需关注一样。 - 有些办法,如:
charAt
可能会抛出异样,然而这些异样在程序中又不用捕捉,也不用申明,这是什么状况?咱们能够看看这些异样都继承自哪个类:java.lang.RuntimeException
。咱们这里说:凡继承自这个类的异样子类在你的程序中能够不进行捕捉,也不进行申明,然而一旦产生这种类型的异样,你的程序会被毫不犹豫的中断,由系统对该异样进行解决,而零碎解决的很简略,只是打印出出错栈信息,而后中断掉你的程序。所以,如果从你的程序的健壮性思考,咱们最好还是进行捕捉并进行解决。
- 从下面的办法列表,咱们看到有些办法名字雷同,然而参数不同的状况,这种状况为办法的重载(overload),比方
StringBuffer 和 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 语言一样指定数组的大小,咱们通过上面的这个例子,来进一步阐明它们之间的区别:
int[] a, b, c; 这里咱们能够晓得 a、b、c 这三个变量均为数组变量 int a[], b, c; 这里咱们晓得只有 a 是数组变量,而 b、c 均为个别变量,而非数组变量
- 数组变量的意义:数组变量是援用类型的变量,这意味着,数组变量中寄存的是数组的援用,而非数组自身,数组的存储空间是在初始化的时候在堆(所谓堆,大家能够了解做一个大仓库)中调配的,这一点同 C 语言有很大区别,这也成为 Java 数组的一个劣势,数组的大小能够在运行的时候确定,而不用在定义的时候就确定下来。
-
数组的初始化:数组的初始化像其余类型的变量一样,既能够在定义的同时初始化,也能够在定义当前,在第一次应用的应用初始化。初始化的模式用两种:
- int a[] = new int[10]; 这种模式,在堆中调配一段可能放下 10 个 int 类型数据的存储空间,并将其援用放在 a 这个数组变量中;
-
int a [] = { 1, 2, 3, 4, 5}; 这种模式其实是把数组 {1, 2, 3, 4, 5} 的援用放入了 a 中,而且这种模式只能在定义数组的同时进行。
-
如果数组元素为援用类型,有两种应用大括号的对数组初始化的模式:
public class ArrayInit {public static void main(String[] args) {Integer[] a = {new Integer(1), new Integer(2), new Integer(3), }; Integer[] b = new Integer[] {new Integer(1), new Integer(2), new Integer(3), }; } }
-
- 数组元素的援用:数组元素的援用也是通过下标进行的,下标能够是一个 int 类型的表达式,然而值的范畴必须在
0
至数组大小 -1
这个范畴内。数组元素的类型既是定义数组时所指定的类型。
多维数组
二维以上的数组就看作多维数组,数组在 Java 中的实现是采纳链式存储实现的,如图:
多维数组的定义和初始化准则同一维是一样的,如下:
-
第一种模式,
int[][] a1 = {{ 1, 2, 3}, {4, 5, 6}, {7, 8, 9} }; // 每个向量用大括号括起来。
-
应用 new 定义 a2 的大小:
int[][][] a2 = new int[2][2][4];
因为在 Java 中采纳链式存储数组,数组中向量的大小不用雷同,比方:
int[][] a1 = {{ 1, 2},
{3, 4, 5, 6},
{7, 8, 9}
};
甚至还能够如下例:
int b[][]; // 定义一个二维数组
b = new int[2][ ]; // b 援用一个具备两个子数组的数组
b[0] = new int[5]; // b[0]援用一个具备 5 个元素的数组
b[1] = new int[3]; // b[1]援用一个具备 3 个元素的数组
数组作为办法的参数
办法的参数能够是数组,在应用数组参数时须要留神以下事项:
- 在形参表中,数组名后的方括号不能省略,方括号个数和数组的维数相等
- 实参表中,数组名后不需括号
- 参数是数组时,形参和实参传递的是援用
示例:
class A{void f(int va[]){for(int i = 0; i < va.length; i++)//va.length 为 va 这个数组的大小
va[i]++;
}
public static void main(String args[]){int[] aa = new int[10];
A ta = new A();
for(int i = 0; i < aa.length; i++)
aa[i] = i;
System.out.println("执行 f()之前");
for(int i = 0; i < aa.length; i++)
System.out.print(aa[i] + " ");
// 把 aa 作为实参传递给 f 办法
ta.f(aa); // f 这个办法的调用必须应用对象,因为它是一个非静态方法
System.out.println("\n 执行 f()之后");
for(int i = 0; i < aa.length; i++)
System.out.print(aa[i] + " ");
}
}
数组的复制
把一个数组中的内容复制到另一个数组不能应用赋值语句 a = b
,这种模式使得a
援用和 b
雷同的数组。如果须要复制数组,咱们能够应用 System
类中的 arraycopy
办法,它的办法首部如下:
public static void arraycopy(Object src,
int srcPos,
Object dest,
int destPos,
int length)
从指定源数组 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 中字符数组不能当作字符串来对待,然而咱们能够应用字符数组作为模板来创立字符串,如下:
char data[] = {'a', 'b', 'c'}; // 这里 data 不能当作字符串
String str = new String(data); //str 援用的既是字符串 "abc"
对数组的操作
对数组遍历
所谓遍历(Traversal),是指依照某种形式,顺次对某种数据结构中的每个元素做一次且仅做一次的拜访。对数组进行遍历通常能够应用循环语句,这里咱们再介绍一个专门针对遍历的 foreach 语句,它的语法格局如下:
// 这里 type 为被遍历构造中元素的类型名,x 为构造中的元素,collection 为被遍历的构造对象
for(type x : collection){...// 循环体}
如下例:
int[] a = new int[10];
// 这里为个别的 for 循环
for(int i = 0; i < a.length; i++) a[i] = i;
// 这里为 foreach 语句
for(int x : a){//foreach 语句中无奈应用下标
System.out.print(x + " ");
}
对数组的排序
对数组的排序,咱们当然能够本人写出各种规范的排序算法,这里介绍一个工具类java.util.Arrays
(留神是复数)。此类蕴含用来操作数组(比方排序和搜寻)的各种办法。除非特地注明,否则如果该类中的办法的数组参数援用值为 null
,则会抛出 NullPointerException
。
升序排序
该类中有一系列对数组进行排序的办法,办法名为sort
,它的一系列重载实现,能够针对各种数组元素类型的数组进行升序排序。典型的,咱们看上面的办法首部:
public static void sort(int[] a)
该办法对传入的 int
型数组 a
按数字升序进行排序。该排序算法是一个通过调优的疾速排序算法。
咱们也能够只对数组中的某一部分进行排序,办法首部如下:
public static void sort(int[] a,
int fromIndex,
int toIndex)
该办法对传入的 int
型数组 a
中从 fromIndex
到toIndex-1
的元素按数字升序进行排序。同样,它也是一个通过调优的疾速排序算法。
该办法可能会抛出上面的异样:
IllegalArgumentException
– 如果fromIndex > toIndex
ArrayIndexOutOfBoundsException
– 如果fromIndex < 0
或toIndex > a.length
下面的两个办法,通过重载,第一个参数能够是其余各种类型,包含根本类型和援用类型。
大家可能留神到了,上述的 sort 只能进行升序的排序,如果是其余简单的排序形式,则就不实用了。
带有 Comparator 的排序
JDK 为咱们提供了弱小的排序反对,因为波及到一些咱们尚未接触的常识,这里我先只做理解。
public static <T> void sort(T[] a, Comparator<? super T> c)
与
public static <T> void sort(T[] a,
int fromIndex,
int toIndex,
Comparator<? super T> c)
这两个的区别在于第一个对整个数组进行排序,第二个能够抉择排序范畴。
数组元素的查找
对数组中元素进行查找,咱们最简略然而效率可能最低下的办法就是对数组进行遍历。同样工具类 java.util.Arrays
也为咱们提供了能够间接应用的查找办法 binarySearch
,该办法也有一系列的重载。应用该办法的前提,该数组必须是通过sort
进行过排序的。它的办法首部如下:
public static int binarySearch(int[] a, int key)
或者
public static int binarySearch(int[] a,
int fromIndex,
int toIndex,
int key)
这两个的区别在于第一个对整个数组进行排序,第二个能够抉择排序范畴。通过重载,第一个参数能够是其余各种类型,包含根本类型和援用类型。
办法中 a
为被查找数组,key
是须要在此数组中查找的键值,fromIndex
为起始地位,toIndex-1
为终止地位。
如果 key
值蕴含在数组中,则返回它的索引值;否则返回 (-(插入点) - 1
)。插入点
被定义为将键插入数组的那一点:即第一个大于此键的元素索引,如果数组中的所有元素都小于指定的键,则为 a.length
或者toIndex
, 这保障了当且仅当此键被找到时,返回的值将 >= 0,否则为负值。
同样,该办法也有二个带有 Comparator 的办法重载,这里不再赘述。
对于工具类 java.util.Arrays
中的其余办法,大家能够查看 JDK 说明书。
问题
用筛法求 1000 以内的素数,并按每行 10 个输入进去。
最初
本文章来自公众号【编程攻略】,更多 Java 学习材料见【编程攻略】