【阿里云】Java面向对象开发课程笔记(二)——数组的定义与使用
1. 数组的定义与使用
1.1 数组基本概念
数组指的就是一组相关类型的变量集合,并且这些变量可以按照统一的方式进行操作。数组本身属于引用数据类型,因此牵扯到内存分配,数组定义语法有如下两类:
- 数组动态初始化:
- 声明并开辟数组:
1.数据类型 [] 数组名称 = new 数据类型 [长度];
2.数据类型 数组名称 [] = new 数据类型 [长度]; - 分步进行数组空间开辟(实例化):
- 声明数组:1.数据类型 数组名称 [] = null;
2.数据类型 [] 数组名称 = null; - 开辟数组空间:数组名称 = new 数据类型 [长度];
- 声明数组:1.数据类型 数组名称 [] = null;
- 声明并开辟数组:
当数组开辟空间之后,就可以采用如下的方式进行操作:
- 数组的访问通过索引完成,即:“数组名称[索引]”,数组的索引由0开始。可使用的索引范围为0~数组长度-1。
- 当数组采用动态初始化开辟空间之后,该数组每个元素都是该数组对应数据类型的默认值。
- 如果此时数组访问的时候超过了数组的索引范围,则会产生“ArrayIndexOutOfBoundsException”。
- 数组本身是一个有序的集合操作,所以对于数组的内容操作往往采用循环的模式完成。数组是一个有限的集合,应使用for循环。
- 在Java中提供有一种动态取得数组长度的方法:数组名称.length。
范例:定义一个int型数组
代码
public class ArrayDemo {
public static void main (String args[]){
int a [] = new int [3]; // 开辟了一个长度为3数组空间
System.out.println(a[0]);
System.out.println(a[1]);
System.out.println(a[2]);
// System.out.println(a[3]);
// 超出索引范围,程序报错,数组越界异常:Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
}
}/* 输出结果:
0
0
0 */
范例:循环输出数组内容
代码
public class ArrayDemo {
public static void main (String args[]){
int a [] = new int [3]; // 开辟了一个数组空间
a [0] = 10; // 第一个元素
a [1] = 20; // 第二个元素
a [2] = 30; // 第三个元素
System.out.println(a.length);
for (int i = 0 ; i < a.length ; i++){
System.out.println(a[i]); // 通过循环控制索引
}
}
} /* 输出结果:
3
10
20
30 */
范例:采用分步模式开辟数组空间
代码
public class ArrayDemo {
public static void main (String args[]){
int a [] = null;
a = new int [3]; // 开辟了一个数组空间
for (int i = 0 ; i < a.length ; i++){
System.out.print(a[i] + " ");
}
}
}// 输出结果:0 0 0
在数组使用之前一定要开辟空间(实例化),如果使用了没有开辟空间的数组,一定会出现“NullPointerException”异常信息。
1.2 数组引用传递
范例:观察一道程序
代码
public class ArrayDemo {
public static void main (String args[]){
int data [] = null;
data = new int [3]; // 开辟了一个数组空间
data [0] = 10; // 第一个元素
data [1] = 20; // 第二个元素
data [2] = 30; // 第三个元素
}
}
内存分析如下:
引用数据类型,就一定能发生引用传递,本质:同一块堆内存可以被不同的栈内存所指向。
范例:观察一道程序
代码
public class ArrayDemo {
public static void main (String args[]){
int data [] = new int [3]; // 开辟了一个数组空间
int temp [] = null; // 声明
data [0] = 10; // 第一个元素
data [1] = 20; // 第二个元素
data [2] = 30; // 第三个元素
// 如果要发生引用传递,不要出现[]
temp = data; // int temp [] = data;
temp [0] = 99;
for (int i = 0 ; i < data.length ; i++){
System.out.print(data[i] + " ");
}
}
} // 输出结果:99 20 30
内存分析如下:
1.3 数组静态初始化
之前定义数组的特点:数组首先开辟内存空间,而后在使用索引进行内容的设置,这属于数组动态初始化,如果希望数组在定义的时候可以同时设置内容,就可以采用静态初始化完成。
数组的静态初始化分为以下两种:
简化格式 | 完整格式(建议使用) |
---|---|
数据类型 数组名称 [] = {值,值,···,值}; | 数据类型 数组名称 [] = new 数据类型 [] {值,值,···,值}; |
范例:静态初始化数组
代码
public class ArrayDemo {
public static void main (String args[]){
int data [] = {1,2,23,4,56,34,123,1234,346,54};
for (int i = 0 ; i < data.length ; i++){
System.out.print(data[i] + " ");
}
}
} // 输出结果:1 2 23 4 56 34 123 1234 346 54
范例:完整格式静态初始化数组并使用匿名对象
代码
public class ArrayDemo {
public static void main (String args[]){
System.out.print(new int [] {1,2,23,4,56,34,123,1234,346,54}.length);
}
} // 输出结果:10
数组最大的缺陷:长度固定
1.4 二维数组
二维数组本质上指的是一个行列集合,如果需要确定某一个·数据需要行索引和列索引来进行定位。确定一个数据要所要使用的结构:“数组名称[行索引][列索引]”,这样的结构就是一个表。
二维数组的定义有两种方式:
- 动态初始化:
- 数据类型 数组名称 [] [] = new 数据类型 [行个数] [列个数];
- 静态初始化:
- 数据类型 数组名称 [] []= new 数据类型 [] [] {{值,···,值},{值,···,值},···,{值,···,值}};
数组的数组就是二维数组。
范例:二维数组
代码
public class ArrayDemo {
public static void main (String args[]){
// 此时的数组并不是一个等列数组
int data [] [] = new int [] [] {{1,2,3},{4,5},{6,7,8,9}}
};
// 在输出的时候一定要使用双重循环,外部循环控制行,内部循环控制列
for (int i = 0 ; i < data.length ; i++){
for ( int j = 0 ; j < data [i].length ; j++){
System.out.print(data[i][j] + " ");
}
System.out.print("\n");
}
}
}
- 输出结果:
1 2 3
4 5
6 7 8 9
1.5 数组与方法调用
范例:使用方法接收数组
代码
public class ArrayDemo{
public static void main(String args[]){
int data [] = new int [] {1,2,3,4,5};
printArray(data); // int temp [] = data;
}
// 定义一个专门进行数组输出的方法
public static void printArray(int temp []){
for (int x = 0 ; x < temp.length ; x++ ){
System.out.print(temp[x] + ",");
}
}
}
- 输出结果:
1,2,3,4,5
范例:方法返回数组
代码
public class ArrayDemo{
public static void main(String args[]){
int data [] = inIt(); // 接收数组
printArray(data);
}
public static int[] inIt(){
return new int [] {1,2,3,4,5};
}
public static void printArray(int temp[]){
for ( int x = 0 ; x < temp.length ; x++){
System.out.print(temp[x] + " ");
}
}
}
- 输出结果:
1 2 3 4 5
发生了引用传递,方法接收数组之后也可以对数组内容进行修改。
范例:方法实现数组内容乘2
代码
public class ArrayDemo{
public static void main(String args[]){
int data [] = inIt(); // 接收数组
inc(data); // 扩大数组中内容
printArray(data);
}
public static void inc(int arry[]){ // 没有返回值
for(int x = 0 ; x < arry.length ; x++){
arry[x] *= 2;
}
}
public static int[] inIt(){
return new int [] {1,2,3,4,5};
}
public static void printArray(int temp[]){
for ( int x = 0 ; x < temp.length ; x++){
System.out.print(temp[x] + " ");
}
}
}
- 输出结果:
2 4 6 8 10
内存分析如下:
1.6 Java对数组的支持
1.数组排序:java.util.Arrays.sort(数组名称);
范例:实现数组排序操作
代码
public class ArrayDemo{
public static void main(String args[]){
int data [] = new int [] {6,12,3,1,34};
char arr [] = new char [] {'A','a','Z','z'};
java.util.Arrays.sort(data);
java.util.Arrays.sort(arr);
printArray(data);
printArray(arr);
}
public static void printArray(int temp[]){
for ( int x = 0 ; x < temp.length ; x++){
System.out.print(temp[x] + " ");
}
}
public static void printArray(char arr[]){
for ( int x = 0 ; x < arr.length ; x++){
System.out.print(arr[x] + " ");
}
}
}
- 输出结果:
1 3 6 12 34 A Z a z
只要是基本数据类型的数组,Arrays.sort()都可以实现排序。
2.数组拷贝是指讲一个数组的部分内容替换掉另外一个数组的部分内容。
- 方法(加工后的):System.arraycopy(源数组名称,源数组开始点,目标数组名称,目标数组开始点,拷贝长度);
范例:实现数组排序操作
源数组A:1,2,3,4,5,6,7,8,9
源数组B:11,22,33,44,55,66,77,88,99
替换后A:1,55,66,77,5,6,7,8,9
代码
public class ArrayDemo{
public static void main(String args[]){
int data [] = new int [] {1,2,3,4,5,6,7,8,9};
int arr [] = new int [] {11,22,33,44,55,66,77,88,99};
System.arraycopy(arr,4,data,1,3);
printArray(data);
}
public static void printArray(int temp[]){
for ( int x = 0 ; x < temp.length ; x++){
System.out.print(temp[x] + " ");
}
}
}
- 输出结果:
1 55 66 77 5 6 7 8 9
1.7 数组案例:数组数据统计
统计一个数组的最大值、最小值、总和和平均值。通过循环操作完成。
代码
public class ArrayDemo{
public static void main(String args[]){
int data [] = new int [] {1,2,3,4,5,6,7,8,9};
int max = data[0]; // 假设第一个元素为最大值
int min = data[0]; //假设第一个元素为最小值
int sum = data[0];
for (int i = 1 ; i < data.length ; i++){
sum += data[i];
if (max < data[i]){
max = data [i];
}
if (min > data[i]){
min = data [i];
}
}
System.out.println("max = " + max);
System.out.println("min = " + min);
System.out.println("sum = " + sum);
System.out.println("ave = " + (double)sum/data.length);
}
}
- 输出结果:
max = 9
min = 1
sum = 45
ave = 5.0
主方法中代码太多。
修改如下:
代码
public class ArrayDemo{
public static void main(String args[]){
int data [] = new int [] {1,2,3,4,5,6,7,8,9};
double result [] = stac(data);
System.out.println("max = " + result[0]);
System.out.println("min = " + result[1]);
System.out.println("sum = " + result[2]);
System.out.println("ave = " + result[3]);
}
public static double[] stac(int data[]){
double retData [] = new double [4];
retData [0] = data [0]; // max
retData [1] = data [0]; // min
retData [2] = data [0]; // sum
for (int i = 1 ; i < data.length ; i++){
retData [2] += data[i];
if (retData [0] < data[i]){
retData [0] = data [i];
}
if (retData [1] > data[i]){
retData [1] = data [i];
}
}
retData [3] = retData [2] / data.length;
return retData;
}
}
- 输出结果:
max = 9.0
min = 1.0
sum = 45.0
ave = 5.0
在整个进行程序开发的时候,主方法不要涉及过于复杂的程序逻辑,只需关注结果。
1.8 数组案例:数组排序
不要写Arrays.sort();
一般以升序为主,共有7种排序算法。
范例:冒泡排序
代码
public class ArrayDemo{
public static void main(String args[]){
int data [] = new int [] {9,8,5,6,4,2,1,3,0,7};
sort(data);
printArray(data);
}
public static void sort (int arr[]){
for (int x = 0 ; x < arr.length - 1 ; x++){
for (int y = 0 ; y < arr.length - x - 1 ; y++){
if (arr[y] > arr[y+1]){
int temp = arr[y];
arr[y] = arr[y+1];
arr[y+1] = temp;
}
}
}
}
public static void printArray(int temp[]){
for ( int x = 0 ; x < temp.length ; x++){
System.out.print(temp[x] + " ");
}
}
}
- 输出结果:
0 1 2 3 4 5 6 7 8 9
1.9 数组案例:数组转置
- 思路一:两个数组
范例:一维数组反转
代码
public class ArrayDemo{
public static void main(String args[]){
int data [] = new int [] {9,8,7,6,5,4,3,2,1,0};
data = reverse(data);
printArray(data);
}
public static int[] reverse(int arr[]){
int temp [] = new int [arr.length] ;
int foot = 0;
for (int x = arr.length - 1 ; x > = 0 ; x--){
temp [foot ++] = arr[x];
}
return temp;
}
public static void printArray(int temp[]){
for ( int x = 0 ; x < temp.length ; x++){
System.out.print(temp[x] + " ");
}
}
}
- 输出结果:
0 1 2 3 4 5 6 7 8 9
内存分析:
此类模式最大问题就是:开辟了两块相同的对内存空间,造成空间浪费。
- 思路二:一个数组上完成
代码
public class ArrayDemo{
public static void main(String args[]){
int data [] = new int [] {9,8,7,6,5,4,3,2,1,0};
reverse(data);
printArray(data);
}
public static void reverse(int arr[]){
int temp = 0;
for (int x = 0 , y = arr.length-1 ; x < arr.length/2 ; x++,y--){
temp = arr[x];
arr[x] = arr[y];
arr[y] = temp;
}
}
public static void printArray(int temp[]){
for ( int x = 0 ; x < temp.length ; x++){
System.out.print(temp[x] + " ");
}
}
}
- 输出结果:
0 1 2 3 4 5 6 7 8 9
原地转置二维数组前提:行列相等
代码
public class ArrayDemo{
public static void main(String args[]){
int data [][] = new int [][] {{9,8,7},{6,5,4},{3,2,1}};
reverse(data);
printArray(data);
}
public static void reverse(int arr[][]){
int temp = 0;
for (int i = 0 ; i < arr.length ; i++){
for (int j = i ; j < arr[i].length ; j++ ){
if ( i != j){
temp = arr[i][j];
arr[i][j] = arr[j][i];
arr[j][i] = temp;
}
}
}
}
public static void printArray(int temp[][]){
for ( int x = 0 ; x < temp.length ; x++){
for (int y = 0 ; y < temp[x].length ; y++ ){
System.out.print(temp[x][y] + " ");
}
System.out.print("\n");
}
}
}
- 输出结果:
9 6 3
8 5 2
7 4 1
1.10 数组案例:二分查找(前提:数组排序)
范例:实现二分查找(递归完成)
代码
public class ArrayDemo{
public static void main(String args[]){
int data [] = new int [] {1,2,3,4,5,6,7,8};
int search = 6;
System.out.println(binarySearch(data,1,data.length-1,6));
}
public static int binarySearch(int arr[],int from,int to,int key){
int mid = (from/2) + (to/2);
if (from < to){
if (key == arr[mid]){
return mid;
}else if (key < arr[mid]){
return binarySearch(arr,from,mid-1,key);
}else if (key > arr[mid]){
return binarySearch(arr,mid+1,to,key);
}}
return -1;
}
}
- 输出结果:
5
1.11 对象数组(核心)
之前定义的数组都属于基本数据类型的数组,那么对象也可以将其定义为数组,这样的操作叫对象数组。对象数组往往是以引用数据类型为主的定义,例如:类、接口。对象数组分为两种定义格式:
- 对象数组动态初始化:类名称 对象数组名称 [] = new 类名称 [长度];
- 对象数组动态初始化:类名称 对象数组名称 [] = new 类名称 [] {实例化对象,…};
范例:对象数组的动态初始化
.> 代码
class Person{
private String name;
private int age;
public Person(String n,int a){
name = n;
age = a;
}
public void setName(String n){
name = n;
}
public void setAge(int a){
age = a;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public String getInfo(){
return "name = " + name + " " + "age = " + age;
}
}
public class ArrayDemo{
public static void main(String args[]){
// 动态初始化之后对象数组中的每一个元素都是其对应数据类型的默认值
Person per [] = new Person [3]; // 动态初始化
per[0] = new Person("Jack",20);
per[1] = new Person("Rose",20);
per[2] = new Person("Sara",20);
for (int x =0 ;x < per.length ; x++){
System.out.println(per[x].getInfo());
}
}
}
- 输出结果:
name = Jack age = 20
name = Rose age = 20
name = Sara age = 20
范例:对象数组的静态初始化
.> 代码
class Person{
private String name;
private int age;
public Person(String n,int a){
name = n;
age = a;
}
public void setName(String n){
name = n;
}
public void setAge(int a){
age = a;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public String getInfo(){
return "name = " + name + " " + "age = " + age;
}
}
public class ArrayDemo{
public static void main(String args[]){
Person per [] = new Person [] {new Person("Jack",20),new Person("Rose",20),new Person("Sara",20)};
for (int x =0 ;x < per.length ; x++){
System.out.println(per[x].getInfo());
}
}
}
- 输出结果:
name = Jack age = 20
name = Rose age = 20
name = Sara age = 20
每一个对象可以保存更多的属性,所以对象数组可以保存的内容要比基本数据更多,应用的也更多。
上一篇: Fragment 基本使用