第五部分 数组和String类
第五部分 数组和String类
5.1 数组
数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同。
Java 语言中提供的数组是用来存储固定大小的同类型元素。
你可以声明一个数组变量,如 numbers[100]
来代替直接声明 100
个独立变量 number0,number1,....,number99
。
5.1.1 声明数组变量
首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:
dataType[] arrayRefVar; // 首选的方法或dataType arrayRefVar[]; // 效果相同,但不是首选方法
注意: 建议使用 dataType[] arrayRefVar
的声明风格声明数组变量。 dataType arrayRefVar[]
风格是来自 C/C++ 语言 ,在Java中采用是为了让 C/C++ 程序员能够快速理解java语言。
下面是这两种语法的代码示例:
double[] myList; // 首选的方法或double myList[]; // 效果相同,但不是首选方法
5.1.2 创建数组
Java语言使用new
操作符来创建数组,语法如下:
arrayRefVar = new dataType[arraySize];
上面的语法语句做了两件事:
- 一、使用
dataType[arraySize]
创建了一个数组。 - 二、把新创建的数组的引用赋值给变量
arrayRefVar
。
数组变量的声明,和创建数组可以用一条语句完成,如下所示:
dataType[] arrayRefVar = new dataType[arraySize];
另外,你还可以使用如下的方式创建数组。
dataType[] arrayRefVar = {value0, value1, ..., valuek};
数组的元素是通过索引访问的。数组索引从 0 开始,所以索引值从 0 到 arrayRefVar.length-1
。
下面的语句首先声明了一个数组变量 myList
,接着创建了一个包含 10 个 double
类型元素的数组,并且把它的引用赋值给 myList
变量。
public class TestArray {public static void main(String[] args) {// 数组大小int size = 10;// 定义数组double[] myList = new double[size];myList[0] = 5.6;myList[1] = 4.5;myList[2] = 3.3;myList[3] = 13.2;myList[4] = 4.0;myList[5] = 34.33;myList[6] = 34.0;myList[7] = 45.45;myList[8] = 99.993;myList[9] = 11123;// 计算所有元素的总和double total = 0;for (int i = 0; i < size; i++) {total += myList[i];}System.out.println("总和为: " + total);}
}
以上实例输出结果为:
总和为: 11367.473
下面的图片描绘了数组 myList
。这里 myList
数组里有 10 个 double
元素,它的下标从 0 到 9。
5.1.3 处理数组
数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本循环或者 For-Each 循环。
该实例完整地展示了如何创建、初始化和操纵数组:
public class TestArray {public static void main(String[] args) {double[] myList = {1.9, 2.9, 3.4, 3.5};// 打印所有数组元素for (int i = 0; i < myList.length; i++) {System.out.println(myList[i] + " ");}// 计算所有元素的总和double total = 0;for (int i = 0; i < myList.length; i++) {total += myList[i];}System.out.println("Total is " + total);// 查找最大元素double max = myList[0];for (int i = 1; i < myList.length; i++) {if (myList[i] > max) max = myList[i];}System.out.println("Max is " + max);}
}
以上实例编译运行结果如下:
1.9
2.9
3.4
3.5
Total is 11.7
Max is 3.5
5.1.4 For-Each 循环
JDK 1.5 引进了一种新的循环类型,被称为 For-Each
循环或者加强型循环,它能在不使用下标的情况下遍历数组。
语法格式如下:
for(type element: array)
{System.out.println(element);
}
该实例用来显示数组 myList
中的所有元素:
public class TestArray {public static void main(String[] args) {double[] myList = {1.9, 2.9, 3.4, 3.5};// 打印所有数组元素for (double element: myList) {System.out.println(element);}}
}
以上实例编译运行结果如下:
1.9
2.9
3.4
3.5
5.1.5 数组作为函数的参数
数组可以作为参数传递给方法。
例如,下面的例子就是一个打印 int 数组中元素的方法:
public static void printArray(int[] array) {for (int i = 0; i < array.length; i++) {System.out.print(array[i] + " ");}
}
下面例子调用 printArray
方法打印出 3,1,2,6,4 和 2:
printArray(new int[]{3, 1, 2, 6, 4, 2});
5.1.6 数组作为函数的返回值
public static int[] reverse(int[] list) {int[] result = new int[list.length];for (int i = 0, j = result.length - 1; i < list.length; i++, j--) {result[j] = list[i];}return result;
}
以上实例中 result
数组作为函数的返回值。
5.1.7 多维数组
多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组,例如:
String[][] str = new String[3][4];
5.1.7.2 多维数组的动态初始化(以二维数组为例)
-
直接为每一维分配空间,格式如下:
type[][] typeName = new type[typeLength1][typeLength2];
type
可以为基本数据类型和复合数据类型,typeLength1
和typeLength2
必须为正整数,typeLength1
为行数,typeLength2
为列数。例如:
int[][] a = new int[2][3];
解析:
二维数组 a 可以看成一个两行三列的数组。
-
从最高维开始,分别为每一维分配空间,例如:
String[][] s = new String[2][]; s[0] = new String[2]; s[1] = new String[3]; s[0][0] = new String("Good"); s[0][1] = new String("Luck"); s[1][0] = new String("to"); s[1][1] = new String("you"); s[1][2] = new String("!");
解析:
s[0]=new String[2]
和s[1]=new String[3]
是为最高维分配引用空间,也就是为最高维限制其能保存数据的最长的长度,然后再为其每个数组元素单独分配空间s0=new String("Good")
等操作。
5.1.7.3 多维数组的引用(以二维数组为例)
对二维数组中的每个元素,引用方式为 arrayName[index1][index2]
,例如:
num[1][0];
5.1.8 Arrays 类
java.util.Arrays 类能方便地操作数组,它提供的所有方法都是静态的。
具有以下功能:
- 给数组赋值:通过 fill 方法。
- 对数组排序:通过 sort 方法,按升序。
- 比较数组:通过 equals 方法比较数组中元素值是否相等。
- 查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作。
具体说明请查看下表:
序号 | 方法和说明 |
---|---|
1 | public static int binarySearch(Object[] a, Object key) 用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)。数组在调用前必须排序好的。如果查找值包含在数组中,则返回搜索键的索引;否则返回 (-(插入点) - 1)。 |
2 | public static boolean equals(long[] a, long[] a2) 如果两个指定的 long 型数组彼此相等,则返回 true。如果两个数组包含相同数量的元素,并且两个数组中的所有相应元素对都是相等的,则认为这两个数组是相等的。换句话说,如果两个数组以相同顺序包含相同的元素,则两个数组是相等的。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
3 | public static void fill(int[] a, int val) 将指定的 int 值分配给指定 int 型数组指定范围中的每个元素。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
4 | public static void sort(Object[] a) 对指定对象数组根据其元素的自然顺序进行升序排列。同样的方法适用于所有的其他基本数据类型(Byte,short,Int等)。 |
5.2 String类
5.2.1 String
字符串广泛应用 在 Java 编程中,在 Java 中字符串属于对象,Java 提供了 String
类来创建和操作字符串。
5.2.1.1 创建字符串
创建字符串最简单的方式如下:
String str = "Guangy";
在代码中遇到字符串常量时,这里的值是 “Guangy”,编译器会使用该值创建一个 String
对象。
和其它对象一样,可以使用关键字和构造方法来创建 String
对象。
用构造函数创建字符串:
String str2=new String("Guangy");
String
创建的字符串存储在公共池中,而 new
创建的字符串对象在堆上:
String s1 = "Guangy"; // String 直接创建
String s2 = "Guangy"; // String 直接创建
String s3 = s1; // 相同引用
String s4 = new String("Guangy"); // String 对象创建
String s5 = new String("Guangy"); // String 对象创建
String
类有 11 种构造方法,这些方法提供不同的参数来初始化字符串,比如提供一个字符数组参数:
public class StringDemo{public static void main(String args[]){char[] helloArray = { 'g', 'u', 'a', 'n', 'g', 'y'};String helloString = new String(helloArray); System.out.println( helloString );}
}
以上实例编译运行结果如下:
Guangy
注意:String
类是不可改变的,所以你一旦创建了 String
对象,那它的值就无法改变了。
如果需要对字符串做很多修改,那么应该选择使用 [StringBuffer & StringBuilder 类]
。
5.2.1.2 字符串长度
用于获取有关对象的信息的方法称为访问器方法。
String
类的一个访问器方法是 length()
方法,它返回字符串对象包含的字符数。
下面的代码执行后,len
变量等于 14:
public class StringDemo {public static void main(String args[]) {String site = "www.Guangy.com";int len = site.length();System.out.println( "光熠教程网址长度 : " + len );}
}
以上实例编译运行结果如下:
光熠教程网址长度 : 14
5.2.1.3 连接字符串
String
类提供了连接两个字符串的方法:
string1.concat(string2);
返回 string2 连接 string1 的新字符串。也可以对字符串常量使用 concat() 方法,如:
"我的名字是 ".concat("Runoob");
更常用的是使用’+'操作符来连接字符串,如:
"Hello," + " runoob" + "!"
结果如下:
"Hello, runoob!"
下面是一个例子:
public class StringDemo {public static void main(String args[]) { String string1 = "菜鸟教程网址:"; System.out.println("1、" + string1 + "www.runoob.com"); }
}
以上实例编译运行结果如下:
1、菜鸟教程网址:www.runoob.com
5.2.1.4 创建格式化字符串
我们知道输出格式化数字可以使用 printf()
和 format()
方法。
String
类使用静态方法 format()
返回一个String
对象而不是 PrintStream
对象。
String
类的静态方法 format()
能用来创建可复用的格式化字符串,而不仅仅是用于一次打印输出。
如下所示:
System.out.printf("浮点型变量的值为 " +"%f, 整型变量的值为 " +" %d, 字符串变量的值为 " +"is %s", floatVar, intVar, stringVar);
你也可以这样写
String fs;
fs = String.format("浮点型变量的值为 " +"%f, 整型变量的值为 " +" %d, 字符串变量的值为 " +" %s", floatVar, intVar, stringVar);
5.2.1.5 判断两字符串是否相等
- equals是object类中的方法,只能用于判断引用类型。
- equals方法默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如String和Integer类中的equals源代码。
具体用法为:
String str1 = "abc";
String str2 = "abc";
str1.equals(str2);
5.2.1.6 String 方法
下面是 String 类支持的方法,更多详细,参看 Java String API 文档:
SN(序号) | 方法描述 |
---|---|
1 | char charAt(int index) 返回指定索引处的 char 值。 |
2 | int compareTo(Object o) 把这个字符串和另一个对象比较。 |
3 | int compareTo(String anotherString) 按字典顺序比较两个字符串。 |
4 | int compareToIgnoreCase(String str) 按字典顺序比较两个字符串,不考虑大小写。 |
5 | String concat(String str) 将指定字符串连接到此字符串的结尾。 |
6 | boolean contentEquals(StringBuffer sb) 当且仅当字符串与指定的StringBuffer有相同顺序的字符时候返回真。 |
7 | [static String copyValueOf(char] data) 返回指定数组中表示该字符序列的 String。 |
8 | [static String copyValueOf(char] data, int offset, int count) 返回指定数组中表示该字符序列的 String。 |
9 | boolean endsWith(String suffix) 测试此字符串是否以指定的后缀结束。 |
10 | boolean equals(Object anObject) 将此字符串与指定的对象比较。 |
11 | boolean equalsIgnoreCase(String anotherString) 将此 String 与另一个 String 比较,不考虑大小写。 |
12 | [byte] getBytes() 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 |
13 | [byte] getBytes(String charsetName) 使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。 |
14 | [void getChars(int srcBegin, int srcEnd, char] dst, int dstBegin) 将字符从此字符串复制到目标字符数组。 |
15 | int hashCode() 返回此字符串的哈希码。 |
16 | int indexOf(int ch) 返回指定字符在此字符串中第一次出现处的索引。 |
17 | int indexOf(int ch, int fromIndex) 返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。 |
18 | int indexOf(String str) 返回指定子字符串在此字符串中第一次出现处的索引。 |
19 | int indexOf(String str, int fromIndex) 返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。 |
20 | String intern() 返回字符串对象的规范化表示形式。 |
21 | int lastIndexOf(int ch) 返回指定字符在此字符串中最后一次出现处的索引。 |
22 | int lastIndexOf(int ch, int fromIndex) 返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。 |
23 | int lastIndexOf(String str) 返回指定子字符串在此字符串中最右边出现处的索引。 |
24 | int lastIndexOf(String str, int fromIndex) 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。 |
25 | int length() 返回此字符串的长度。 |
26 | boolean matches(String regex) 告知此字符串是否匹配给定的正则表达式。 |
27 | boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) 测试两个字符串区域是否相等。 |
28 | boolean regionMatches(int toffset, String other, int ooffset, int len) 测试两个字符串区域是否相等。 |
29 | String replace(char oldChar, char newChar) 返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。 |
30 | String replaceAll(String regex, String replacement) 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。 |
31 | String replaceFirst(String regex, String replacement) 使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。 |
32 | [String] split(String regex) 根据给定正则表达式的匹配拆分此字符串。 |
33 | [String] split(String regex, int limit) 根据匹配给定的正则表达式来拆分此字符串。 |
34 | boolean startsWith(String prefix) 测试此字符串是否以指定的前缀开始。 |
35 | boolean startsWith(String prefix, int toffset) 测试此字符串从指定索引开始的子字符串是否以指定前缀开始。 |
36 | CharSequence subSequence(int beginIndex, int endIndex) 返回一个新的字符序列,它是此序列的一个子序列。 |
37 | String substring(int beginIndex) 返回一个新的字符串,它是此字符串的一个子字符串。 |
38 | String substring(int beginIndex, int endIndex) 返回一个新字符串,它是此字符串的一个子字符串。 |
39 | [char] toCharArray() 将此字符串转换为一个新的字符数组。 |
40 | String toLowerCase() 使用默认语言环境的规则将此 String 中的所有字符都转换为小写。 |
41 | String toLowerCase(Locale locale) 使用给定 Locale 的规则将此 String 中的所有字符都转换为小写。 |
42 | String toString() 返回此对象本身(它已经是一个字符串!)。 |
43 | String toUpperCase() 使用默认语言环境的规则将此 String 中的所有字符都转换为大写。 |
44 | String toUpperCase(Locale locale) 使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。 |
45 | String trim() 返回字符串的副本,忽略前导空白和尾部空白。 |
46 | static String valueOf(primitive data type x) 返回给定data type类型x参数的字符串表示形式。 |
47 | contains(CharSequence chars) 判断是否包含指定的字符系列。 |
48 | isEmpty() 判断字符串是否为空。 |
5.2.2 StringBuilder
StringBuilder 可以看成是一个容器,创建之后里面的内容是可变的。
当我们在拼接字符串和反转字符串的时候会使用到
5.2.2.1 基本使用
public class StringBuilderDemo3 {public static void main(String[] args) {//1.创建对象StringBuilder sb = new StringBuilder("abc");//2.添加元素/*sb.append(1);sb.append(2.3);sb.append(true);*///反转sb.reverse();//获取长度int len = sb.length();System.out.println(len);//打印//普及://因为StringBuilder是Java已经写好的类//java在底层对他做了一些特殊处理。//打印对象不是地址值而是属性值。System.out.println(sb);}
}
5.2.2.2 链式编程
public class StringBuilderDemo4 {public static void main(String[] args) {//1.创建对象StringBuilder sb = new StringBuilder();//2.添加字符串sb.append("aaa").append("bbb").append("ccc").append("ddd");System.out.println(sb);//aaabbbcccddd//3.再把StringBuilder变回字符串String str = sb.toString();System.out.println(str);//aaabbbcccddd}
}
5.2.2.3 练习1:对称字符串
需求:
键盘接受一个字符串,程序判断出该字符串是否是对称字符串,并在控制台打印是或不是
对称字符串:123321、111非对称字符串:123123
代码示例:
public class StringBuilderDemo6 {//使用StringBuilder的场景://1.字符串的拼接//2.字符串的反转public static void main(String[] args) {//1.键盘录入一个字符串Scanner sc = new Scanner(System.in);System.out.println("请输入一个字符串");String str = sc.next();//2.反转键盘录入的字符串String result = new StringBuilder().append(str).reverse().toString();//3.比较if(str.equals(result)){System.out.println("当前字符串是对称字符串");}else{System.out.println("当前字符串不是对称字符串");}}
}
5.2.2.4 练习2:拼接字符串
需求:定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回。
调用该方法,并在控制台输出结果。
例如:数组为int[] arr = {1,2,3};
执行方法后的输出结果为:[1, 2, 3]
代码示例:
package com.itheima.stringbuilderdemo;public class StringBuilderDemo7 {public static void main(String[] args) {//1.定义数组int[] arr = {1,2,3};//2.调用方法把数组变成字符串String str = arrToString(arr);System.out.println(str);}public static String arrToString(int[] arr){StringBuilder sb = new StringBuilder();sb.append("[");for (int i = 0; i < arr.length; i++) {if(i == arr.length - 1){sb.append(arr[i]);}else{sb.append(arr[i]).append(", ");}}sb.append("]");return sb.toString();}
}
5.2.3 StringJoiner
- StringJoiner跟StringBuilder一样,也可以看成是一个容器,创建之后里面的内容是可变的。
- 作用:提高字符串的操作效率,而且代码编写特别简洁,但是目前市场上很少有人用。
- JDK8出现的
基本使用:
//1.创建一个对象,并指定中间的间隔符号
StringJoiner sj = new StringJoiner("---");
//2.添加元素
sj.add("aaa").add("bbb").add("ccc");
//3.打印结果
System.out.println(sj);//aaa---bbb---ccc
//1.创建对象
StringJoiner sj = new StringJoiner(", ","[","]");
//2.添加元素
sj.add("aaa").add("bbb").add("ccc");
int len = sj.length();
System.out.println(len);//15
//3.打印
System.out.println(sj);//[aaa, bbb, ccc]
String str = sj.toString();
System.out.println(str);//[aaa, bbb, ccc]
5.3 关于字符串的小扩展:
-
字符串存储的内存原理
String s = “abc”;直接赋值
特点:
此时字符串abc是存在字符串常量池中的。
先检查字符串常量池中有没有字符串abc,如果有,不会创建新的,而是直接复用。如果没有abc,才会创建一个新的。
所以,直接赋值的方式,代码简单,而且节约内存。
-
new出来的字符串
看到new关键字,一定是在堆里面开辟了一个小空间。
String s1 = new String(“abc”);
String s2 = “abc”;
s1记录的是new出来的,在堆里面的地址值。
s2是直接赋值的,所以记录的是字符串常量池中的地址值。
-
==号比较的到底是什么?
如果比较的是基本数据类型:比的是具体的数值是否相等。
如果比较的是引用数据类型:比的是地址值是否相等。
结论:==只能用于比较基本数据类型。不能比较引用数据类型。
元素
sj.add(“aaa”).add(“bbb”).add(“ccc”);
int len = sj.length();
System.out.println(len);//15
//3.打印
System.out.println(sj);//[aaa, bbb, ccc]
String str = sj.toString();
System.out.println(str);//[aaa, bbb, ccc]