3.1 数组的定义和使用
数组(Array)是用来存储一组相同数据类型数据的集合。数组中的每个数据称为一个元素(element),数组可以分为一维数组,二维数组和多维数组。我们 主要讲解一维数组和二维数组。
3.1.1一维数组的声明数组变量
Java中的数组必须先声明然后再使用,Java中声明数组的方式如下:
datatype[] arrayRefVar;
或者
datatype arrayRefVar[];
例如:
double[] array;
或者
double array[];
说明:我们建议使用第一种方式,第二种方式来自于C/C++。
注意:由于在Java中,数组是引用数据类型,所以上面的声明方式中只是声明了一个指向数组存储空间的一个引用,但是现在它还没有指向任何的内存空间,所以现在数组还不能使用。而且在声明的时候不能指定数组的大小。
3.1.2 创建数组
要使用数组,必须创建数组,即为数组分配存储空间,创建数组的方式如下:
arrayRefVar = new datatype[arraysize];
此语句做了两件事情:用new datatype[arraysize]创建了一个数组大小为arraysize数组;将此数组的引用赋给了变量arrayRefVar。
事实上,声明数组变量,创建数组和将数组的引用赋给数组变量可以合并到一个语句,格式如下:
datatype[] arrayRefVar = new datatype[arraysize];
或者
datatype arrayRefVar[] = new datatype[arraysize];
例如:
double[] array = new double[10];
下图说明了上例中数组创建之后部分内存状态:
3.1.3 数组元素的使用
数组中元素通过数组的索引即下标来引用:
arrayRefVar[index];
其中数组的下标从0开始,下标的范围是0~arraysize-1;在上面的例子中要使用下标为5的元素的方法:array[5]。
在Java中数组的长度,可以是arrayRefVar.length来得到,如上例中:array.length是10。
下面的程序演示了数组元素的使用:
public class ArrayDemo { public static void main(String[] args) { int[] array = new int[10]; for (int i = 0; i < array.length; i++) { System.out.print(array[i] + " "); } } }
0 0 0 0 0 0 0 0 0 0
说明:数组创建之后如果不给数组元素赋值,则Java自动给数组元素赋上个数据类型的默认值,具体见第2讲中数据类型
同样的二维数组也是如此:
package com_package1; public class Array5 { public static void main(String[]args) { int [][]array = new int[3][3]; System.out.print(array[1][2]); } }
输出的结果是0
3.1.4数组的静态初始化
数组的初始化格式如下:
datatype[] array = {value0, value1, value2, …, valuek};
例如:
double[] myArray = {1.0, 2.0, 3.0, 4.0, 5.0};
在这种情况下,数组的大小将由花括号中的元素个数来确定,而且这种情况下不需要使用new运算符。
注意:在初始化时,必须将数组变量的声明,数组的创建和为数组元素赋初值放在一个语句中,不能将其割裂开,例如,下面的方式就是错误的:
double[] myArray;
myArray = {1.0, 2.0, 3.0, 4.0, 5.0};
3.1.5 数组的复制
1、在Java中,数组的复制有多种方法:for、System.arraycopy、clone。下面分别进行讲解:
使用for循环是最常用的方法,就是利用for循环逐个访问数组中元素,将其复制到目标数组的对应位置即可。举例如下:
public class ArrayCopyFor { public static void main(String[] args) { int[] array1 = { 1, 2, 3, 4, 5 }; 数组的初始化 int[] array2 = new int[array1.length];// 声明目标数组 // 复制 for (int i = 0; i < array1.length; i++) { array2[i] = array1[i]; } // 输出array2结果 for (int i = 0; i < array2.length; i++) { System.out.print(array2[i] + ","); } } }
2、利用clone()方法复制
在Java中,Object类是所有类的父类,类中的clone()可用于创建并返回此对象的一个副本,在Java中认为“一切皆对象”,数组也是,所以使用该方法可以实现数组的复制,举例如下:
public class ArrayCopyClone { public static void main(String[] args) { int[] array1 = { 1, 2, 3, 4, 5 }; // 利用clone()方法复制 int[] array2 = array1.clone();//for (int i = 0; i < array1.length; i++) { array2[i] = array1[i]; } 比较 // 输出array2结果 for (int i = 0; i < array2.length; i++) { System.out.print(array2[i] + ",");
其中:
src - 源数组。
srcPos - 源数组中的起始位置,表示从源数组的srcPos位置处开始复制。
dest - 目标数组。
destPos - 目标数据中的起始位置,表示复制到目标数组的从destPos开始的数组部分。
length - 要复制的数组元素的数量。
System.arraycopy()方法举例如下:
public class ArrayCopy { public static void main(String[] args) { int[] array1 = { 1, 2, 3, 4, 5 }; int[] array2 = new int[array1.length]; // 利用Sysem.arraycopy()实现复制 System.arraycopy(array1, 0, array2, 0, array1.length); // 输出array2结果 for (int i = 0; i < array2.length; i++) { System.out.print(array2[i] + ","); } } }
3.1.6 二维数组
1、二维数组的创建
语法如下:
datatype[][] arrayName = new datatype[行数][列数];
注意:使用new来创建多维数组时,不必指定每一维的大小,只需要指定第一维的大小就可以了,例如:
int[][] array = new int[10][]。
这就意味着在二维数组中每一行的长度可以不同。
也可以使用静态初始化的方式来创建数组,例如:
int[][] array = {{1,2},{3,4},{5,6}};
二维数组举例如下:
public class Array2Demo { public static void main(String[] args) { int[][] score = { { 67, 71 }, { 78, 89, 93 }, { 99, 100, 66, 95 } }; for (int i = 0; i < score.length; i++) { for (int j = 0; j < score[i].length; j++) { System.out.print(score[i][j] + " "); } System.out.println(); } } }
67 71
78 89 93
99 100 66 95
1 package com_package1; 2 3 public class Double_dimensinal_array1 { 4 public static void main(String[]args) 5 { 6 int[][]array1 ={{1,2},{1,2,3},{1,2,3,4}}; 7 //注意,array1.length是行的长度 8 for(int i=0;i<array1.length;i++) 9 { 10 //array1.[i].length是每行列的长度 11 for(int j=0;j<array1[i].length;j++) 12 { 13 System.out.print(array1[i][j]+" "); 14 15 16 } 17 18 System.out.print(" "); 19 } 20 21 } 22 23 } 24 /*for(int i=0;i<3;i++) 25 for(int j=0;j<3;j++) 26 System.out.print(array1[i][j]);是不对的,这时候不能自动补0了。 27 28 * **/ 29
3.1.7 foreach循环
事实上,在JDK1.5之后,Java中还有一种更简洁的方式来访问数组和容器(后面的章节会讲到容器),那就是foreach,它的语法格式如下:
for(数据类型 变量名称 : 数组名称){
}
说明:这里的数据类型必须与数组的数据类型一致
举例如下:
public class ForEach { public static void main(String[] args) { int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; System.out.println("使用普通方式输出数组:"); for (int i = 0; i < array.length; i++) { System.out.print(array[i] + " "); } System.out.println(); System.out.println("使用foreach输出数组:"); for (int temp : array) { System.out.print(temp + " "); } } }
使用普通方式输出数组:
1 2 3 4 5 6 7 8 9
使用foreach输出数组:
1 2 3 4 5 6 7 8 9
foreach目前我只知道适用于一维数组
3.2 方法的声明与使用
在前面的章节中,我们学到了main()、System.out.println()、System.arraycopy()等方法,现在我们就来学习普通方法的声明与使用。
方法method就是组织在一起执行某个操作的一组语句的集合。
3.2.1 方法的定义
通常情况下,方法定义的语法格式如下:
[access] [modifier] <return_type> methodName([<parameter_list>]){
}
其中,access是访问权限控制,有public、private、protected和default,是可选的,详情见第4讲面向对象。
modifier是访问修饰符,有static、final和abstract等,是可选的,详情见后。
return_type是表示方法的返回值类型,是必选的。
methodName是方法的名称,方法名的命名请参见标识符的命名规则,需要特别强调的是,方法名的第一个单词要全部小写,之后的每一个单词的首字母要大写。
parameter_list是方法所需的参数列表,是可选的。
方法举例如下:
public static int max(int num1, int num2) { int result; if (num1 > num2) { result = num1; } else { result = num2; } return result; }
1 package com_package1; 2 3 import java.util.Scanner; 4 5 public class Compare { 6 public static int max(int n,int m) 7 { 8 int result; 9 if(n>=m) 10 return n; 11 else 12 return m; 13 14 } 15 public static void main(String[]args) 16 { 17 Scanner scanner = new Scanner(System.in); 18 int haha = scanner.nextInt(); 19 int haha2 = scanner.nextInt(); 20 System.out.print(max(haha,haha2)); 21 22 23 24 25 26 } 27 28 29 }
3.2.2 方法的调用
对于有明确返回值类型的方法,要将该方法当作一个值来处理,如上面定义的max方法的调用格式可以如下:
int large = max(3,4);
或者
System.out.println(max(3,5));
对于返回值类型是void类的方法,调用的时候要将其当做一个语句。例如:
System.out.println(“Hello World!!”);
println()方法的返回值就是void。
方法调用举例如下:
public class TestMax { public static void main(String[] args) { int num1 = 5; int num2 = 7; int k = max(num1, num2); System.out.println("The maximum between" + num1 + " and " + num2 + " is " + k); } public static int max(int num1, int num2) { int result; if (num1 > num2) { result = num1; } else { result = num2; } return result; } }
为方法的重载。所谓的方法重载就是:方法名相同,但是参数的类型和参数的个数不同。通过传递不同个数或不同类型的参数来完成不同方法的调用。
方法重载举例如下:
public class MethodOverload { public static void main(String[] args) { int one = add(10, 20); float two = add(1.2f, 3.4f); double three = add(4.5, 2.3); System.out.println(one); System.out.println(two); System.out.println(three); } public static int add(int x, int y) { System.out.print("两个整数相加: "); System.out.println(x + y); return x + y; } public static float add(float x, float y) { System.out.print("两个单精度浮点数相加:"); System.out.println(x + y); return x + y; } public static double add(double x, double y) { System.out.print("两个双精度浮点数相加:"); System.out.println(x + y); return x + y; }
两个单精度浮点数相加:4.6000004
两个双精度浮点数相加:6.8
30
4.6000004
注意:方法的重载一定是参数的个数或者是参数的类型不同才行,仅有返回值类型不同或者修饰符不同不构成重载。
3.2.4 方法中的参数传递
在Java中,有两种参数传递方式:按值传递和按引用传递。
所谓的按值传递(Call by Value)就是将传递参数的数值传递给被调方法,被调方法通过创建一份新的内存拷贝来存储传递过来的值,然后在内存拷贝上进行操作,所以他不会改变原始参数的值。在Java中,当
传递基本数据类型的时候,都是按值来传递的。
示例代码如下:
public class TestPassByValue { public static void main(String[] args) { int num1 = 1; int num2 = 2; System.out.println("Before invoking the swap method,num1 is " + num1 + " and num2 is " + num2); swap(num1, num2); System.out.println("After invoking the swap method,num1 is " + num1 + " and num2 is " + num2); } public static void swap(int num1, int num2) { System.out.println(" Inside the swap method"); System.out.println(" Before swapping ,num1 is " + num1 + " and num2 is " + num2); int temp = num1; num1 = num2; num2 = temp; System.out.println(" After swapping ,num1 is " + num1 + " and num2 is " + num2); } }
Before invoking the swap method,num1 is 1 and num2 is 2
Inside the swap method
Before swapping ,num1 is 1 and num2 is 2
After swapping ,num1 is 2 and num2 is 1
After invoking the swap method,num1 is 1 and num2 is 2
从执行结果看,num1和num2的值在交换前后没有发生变化
所谓的引用传递(call by reference)就是将参数的引用(内存地址)传递给被调方法,被调方法通过传递的引用值获取内存空间,从而在原始内存空间直接进行操作,这样会导致原始内存空间的值发生改变。在Java中传递引用类型对象的时候,是引用传递。
数组是引用类型,所有数组可以作为参数传递,举例如下:
public class TestPassByReference { public static void fun(int[] array) { array[0] = 7;//改变数组中元素的值 } public static void main(String[] args) { int[] array = { 1, 2, 3, 4, 5, 6 }; for (int temp : array) { System.out.print(temp + " "); } System.out.println(); fun(array); //调用fun方法,将数组array作为参数传递,是引用传递 for (int temp : array) { System.out.print(temp + " "); } } }
1 2 3 4 5 6
7 2 3 4 5 6
1 package com_package1; 2 3 public class Reference { 4 public static void fun(int[]array) 5 { 6 array[0] = 7; 7 8 9 } 10 public static void main(String[]args) 11 { 12 int[]array = {1,2,3,4,5,6}; 13 //int[]array2=new int[10]; 14 for(int temp : array) 15 { 16 System.out.print(temp+" "); 17 18 } 19 System.out.println(); 20 fun(array); 21 for(int temp : array) 22 { 23 System.out.print(temp+" "); 24 25 } 26 System.out.println(); 27 28 29 } 30 31 } 32 //数组都是引用传递,改变的是数组的值
1 package com_package1; 2 3 public class Reference2 { 4 5 public static void change(int x,int y) 6 { 7 int temp; 8 temp=x; 9 x=y; 10 y=temp; 11 System.out.println("a="+x+" "+"b="+y); 12 } 13 public static void main(String[]args) 14 { 15 int a = 3; 16 int b = 5; 17 System.out.println("a="+ a +" "+"b=" + b); 18 change(a,b); 19 System.out.println("a="+a+" "+"b="+b); 20 21 } 22 23 } 24 //值传递,a b 的值并不改变
可以看出将数组作为参数传递后,在被调方法中对数组元素进行了修改,原来数组的值也发生了改变。
注意:在Java中不允许程序员选择参数的传递方式,原生数据类型的参数都是按值传递,引用数据类型的参数都是引用传递。
Java的方法中还有一类特殊的方法,它没有返回值类型,这类方法称为类的构造方法,这种方法将在面向对象中进行讲解。