1、 本次预计讲解的知识点
1、 数组的基本作用与定义语法;
2、 二维数组的使用;
3、 数组的方法的互相操作;
4、 与数组有关的类库方法使用;
5、 对象数组。
2、 具体内容
在所有的的开发之中,数组是一个非常重要的概念,所有的项目都有数组,但是它使用的数组的本次讲解有出入的,后面更换数组的使用的形式,但是其基本概念不会被改变。
2.1、数组的基本概念
数组实质一组相关变量的集合,例如:如果说现在要想定义100个整型变量,按照传统的思路,可能这样定义的:
Int i1,i2,…i100一共希望我100个变量。
以上的形式的的确满足技术要求,但是这里有一个问题,这100变量没有任何的逻辑控制关系,完全独立。那么就会出现对象不方便管理的情况。那么在这种情况下就可以利用数组来解决此类问题,而数组本身也属于引用数据类型,所以数组定义语法如下:
l 声明并开辟数组:数据类型 数组名称[]=new数据类型[长度];
l 分布完成:
n 声明数组:数组类型 数组名称[]=null;
n 开辟数组:数组名称 =new 数据类型[长度]。
当数组来开辟空间之后,那么可以采用“数组名称[下标|索引]”的形式进行访问但是所有的下标对后世从
0下开始的。即:如果是3个长度的数组,那么下标的范围:0~2(0、1、2一共三个内容)如果访问的时候超过了数组允许下标的长度,那么会出现数组越界异常(ArrayIndexOutOfBoundsException)
以上给出的数组定义结构使用的是动态初始化的方式,即:数组会首先开辟内存空间,但数组中的的都是其对应数据类型的默认值。
由于数组是一种顺序的结构,并且数组额长度都是固定的 ,那么可以使用循环的方式输出,很明显需要知道for循环,而在java里面为方便数组的输出提供有一个“数组名称.length”,可以取得数组长度
范例:定义数组
public class ArrayDemo { public static void main(String[] args) { //声明并开辟了一个3个长度的数组 int data[] = new int[3]; data[0] = 10; data[1] = 20; data[2] = 30; for(int x =0; x< data.length; x++) { System.out.println(data[x]); } }
} |
虽然数组的操作比较简单,但是麻烦的问题在于,他也属于引用数组类型,所以以上代码依然需要牵制到
内存分配,与对象保存唯一的区别在于:对象中对内存保存的是一组信息。
以上使用的是第一种数组定义的语法,那么下面更换第二种:
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; for(int x =0; x< data.length; x++) { System.out.println(data[x]); } }
} |
既然数组属于引用数据类型,那么数组一定可以发生引用传递。
范例:数组的引用传递
public class ArrayDemo { public static void main(String[] args) { //声明并开辟了一个3个长度的数组 int data[] = new int[3]; data[0] = 10; data[1] = 20; data[2] = 30; int temp[] = data; temp[0] = 99; for(int x =0; x< data.length; x++) { System.out.println(data[x]); } } |
以上数组的定义格式严格来讲属于动态初始化,它的操作特点:先开辟数组空间,而后为数组中的内容进行赋值。那么在数组定义之中提供静态初始化的操作,即:数组定义的同时就设置好了相应的数据内容,格式如下:
l 格式一:简化格式
数据类型 数组名称 [] = {值,值,….}; |
l 格式二:完整格式:
数据类型 数组名称 [] = new 数据类型{值,值,….}; |
范例:数组的静态初始化
public class ArrayDemo { public static void main(String[] args) { int data[] = new int[]{1,2,3,4,5}; for(int x =0; x< data.length; x++) { System.out.println(data[x]); } }
} |
在实际的工作中,数组得会存在的,但是它的内容大部分情况下都是通过传递的数据而动态生成的,很少出现这种开辟数组后去使用的情况。
虽然数组支持顺序的数据访问操作,但是数组有一个最大的的缺点 —— 长度不能够改变,所以正因为如此,在我们的开发之中,才不会直接应用数组,但是会使用到数组的概念。
2.2、二维数组(了解)
在之前的数组只有一个“[]”,所以此类数组就是普通的数组,或者再麻烦一点可以把它称为一维数组,如果现在想描述更多的数据,可以使用二位数组,后有两个“[]”
一维数组严格来讲,类似于如下形式:
索引 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
数据 | 90 | 342 | 423 | 435 | 243 | 532 | 45 | 54 | 23 |
如果一维数组里面要找到一个数据,只需要确定一个索引就够了。
二维数组就是一张数据表,有行有列,类似于如下形式:
索引 | 列:0 | 列:1 | 列:2 | 列:3 | 列:4 | 列:5 | 列:6 | 列:7 | 列:8 |
行:0 | 90 | 342 | 423 | 435 | 243 | 532 | 45 | 54 | 23 |
行:1 | 58 | 78 | 78 | 77 | 85 | 875 | 85 | 76 | 867 |
行:2 | 57 | 578 | 5 | 6 | 857 | 87 | 78 | 86 | 75 |
如果现在想在二维数组里面确定一个数据,需要行和列一起定位,例如:数字77的索引位置:行1列3“[1][3]”而对于二维数组的定义有如下的两类:
l 动态初始化:数据类型 数组名称[][] = new 数据类型[行的个数][列的个数]
l 静态初始化;数据类型 数组名称[][] = 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 x = 0; x < data.length; x++) { //内层循环是控制数组的数据列内容 for (int y = 0; y < data[x].length; y++) { System.out.print(data[x][y]+"\t"); } System.out.println(); } } } |
随着开发的发展,直接编写的代码里面很少再出现二维数组的概念。
2.3、数组的方法参数的传递(难点)
在之前所有方法发现传递的数据几乎都是用的基本数据类型,那么除了基本数据类型之外,也可以传递数组,但是传递的数组,请千万记住,观察内存分配图。
范例:一个传递的程序
public class ArrayDemo { public static void main(String[] args) { int data[] = new int [] {1,2,3}; change(data);//int temp[] = data; for (int i = 0;i < data.length; i++) { System.out.println(data[i]); } } //此方法定在主类中,并且有主方法直接调用 public static void change(int temp[]) { for (int i = 0;i < temp.length; i++) { temp[i] *= 2; //将数组的内容乘2保存 } } } public class ArrayDemo { public static void main(String[] args) { int data[] = new int [] {1,2,3}; int temp[] = data; for (int i = 0;i < temp.length; i++) { temp[i] *= 2; } for (int i = 0;i < temp.length; i++) { System.out.println(data[i]); } } } |
在进行引用传递的过程之中,如果方法对数组对数组的修改一定会影响到原始数据。
范例:实现一个数组排序
数组排序需操作在笔试中经常被问到,下面给出(升序)排序的基本原理:
l 原始数据:2、1、9、0、5、3、7、6、8;
l 第一次排序:1、2、0、5、3、7、6、8、9;
l 第二次排序:1、0、2、3、5、6、7、8、9;
l 第三次排序:0、1、2、3、5、6、7、8、9。
以上只是给出了排序的基础原理过程,但是会根据的不同会出现不同的排序次数,但是不管如何排序有多少的数据,总的排序次数不会超过数组的长度。所以只要排序的次数达到了“长度*长度”,那么所以的数据一定可以排序成功。
l 基础排序
public class ArrayDemo { public static void main(String[] args) { int data[] = new int [] {2,1,9,0,5,3,7,6,8}; print(data); //外层控制排序的次数 for (int i=0; i<data.length-1; i++) { //内层控制每次的排序控制 for(int y = 0; y < data.length-1; y++ ) { if (data[y] > data[y+1]) {//需要交换 int temp = data[y]; data[y] = data[y+1]; data[y+1] = temp; } } } print(data); } //专门定义一个输出功能的方法 public static void print(int temp[]) { for (int i=0; i<temp.length; i++) { System.out.print(temp[i] + "、"); } System.out.println(); } } |
l 改善设计:主方法设计上是作为程序的起点存在,那么所有的程序起点都可以称为客户端既然是客户端,所有的代码编写编写一定要简单,那么可以采用封装方法
public class ArrayDemo { public static void main(String[] args) { int data[] = new int [] {2,1,9,0,5,3,7,6,8}; print(data); sort(data);//实现排序 print(data); } //这个方法专门负责排序 public static void sort(int arr[]) { //外层控制排序的次数 for (int i=0; i<arr.length-1; i++) { //内层控制每次的排序控制 for(int y = 0; y < arr.length-1; y++ ) { if (arr[y] > arr[y+1]) {//需要交换 int temp = arr[y]; arr[y] = arr[y+1]; arr[y+1] = temp; } } } } //专门定义一个输出功能的方法 public static void print(int temp[]) { for (int i=0; i<temp.length; i++) { System.out.print(temp[i] + "、"); } System.out.println(); } }
|
面试题:请编写一个数组排序操作
答案入上
范例:实现数组的转置
下面首先解释一下转置的概念(一维数组实现):
原始数组: 1、2、3、4、5、6、7、8;
转置后的数组: 8、7、6、5、4、3、2、1;
如果转置的操作,有两个思路:
l 定义一个新的数组,而后将原始数组按照倒序的方式插入到新的数组之中,随后改变原始数组引用;
public class ArrayDemo { public static void main(String[] args) { int data[] = new int [] {1,2,3,4,5,6,7,8}; print(data); sort(data);//实现排序 print(data); } //这个方法专门负责排序 public static void sort(int arr[]) { //外层控制排序的次数 for (int i=0; i<arr.length-1; i++) { //内层控制每次的排序控制 for(int y = 0; y < arr.length-1; y++ ) { if (arr[y] > arr[y+1]) {//需要交换 int temp = arr[y]; arr[y] = arr[y+1]; arr[y+1] = temp; } } } } //专门定义一个输出功能的方法 public static void print(int temp[]) { for (int i=0; i<temp.length; i++) { System.out.print(temp[i] + "、"); } System.out.println(); } } |
虽然以上的代码实现了转置的操作的,但是遗憾的是,代码会产生垃圾
l 利用算法在一个数组上完成转置操作:
n 原始数组: 1、2、3、4、5、6、7、8;转置次数:数组长度/ 2
n 第一次转置 8、2、3、4、5、6、7、1;
n 第二次转置 8、7、3、4、5、6、2、1;
n 第三次转置 8、7、6、4、5、3、2、1;
n 第四次转置 8、7、6、5、4、3、2、1;
但是以上给出的数组长度是一个偶数,如果是一个奇数呢?
n 原始数组: 1、2、3、4、5、6、7;转置次数:数组长度/ 2
n 第一次转置 7、2、3、4、5、6、1;
n 第二次转置 7、6、3、4、5、2、1;
n 第三次转置 7、6、5、4、3、2、1;
也就是说不管是奇数的个数还是偶数的个数,转置的次数计算的方式是完全一样的。
public class ArrayDemo { public static void main(String[] args) { int data[] = new int [] {1,2,3,4,5,6,7,8}; reverse(data); print(data); } //此方法专门实现数组的转置操作 public static void reverse(int arr[]) { int len = arr.length / 2;//转置次数 int head = 0;//头部索引 int tail = arr.length - 1;//尾部索引 for (int x = 0; x<len; x++) { int temp = arr[head]; arr[head] = arr[tail]; arr[tail] = temp; head++; tail--; } } //专门定义一个输出功能的方法 public static void print(int temp[]) { for (int i=0; i<temp.length; i++) { System.out.print(temp[i] + "、"); } System.out.println(); } } |
以上实现的是一维数组的转置,那么如果是二维数组呢?
前提:是行与列完全相同的数组;
1 2 3
4 5 6
7 8 9
第一次转置:4的索引[0][1]、2的索引[1][0],行数和列数相同
1 4 3
2 5 6
7 8 9
第二次转置:
1 4 7
2 5 6
3 8 9
第三次转置:
1 4 7
2 5 8
3 6 9
只有行和列相同的时候才会发生交换的操作。
1[x=0][y=0] 2[x=0][y=1] 3[x=0][y=2]
4[x=1][y=0] 5[x=1][y=1] 6[x=1][y=2]
7[x=2][y=0] 8[x=2][y=1] 9[x=2][y=2]
第一次转换(x = 0,y = x = 0; 循环3次)
第二次转换(x = 1,y = x = 1; 循环2次)
第三次转换(x = 2,y = x =2; 循环1次)
以上给出的是一个等行列的数组,但是如果不一样呢?
1 2 3
4 5 6
开辟一个新的数组,数组的行数是原始数组的列数,数组的列数是原始数组的行数
需要改变原始数组的引用,会产生垃圾。
以上实现了方法接受数组的操作情况,同样方法也可以返回数组。
范例:方法返回数组
public class ArrayDemo { public static void main(String[] args) { int[] data = init();//接受数组 print(data); //init()方法返回的是一个数组 //数组可以直接使用length取得长度 System.out.println(init().length); } public static int[] init() { //方法返回数组 return new int[] {1,2,3,4,5,6,7,8,9}; } public static void print(int temp[]) { for (int i=0; i<temp.length; i++) { System.out.print(temp[i] + "、"); } System.out.println(); } } |
重点关注方法的返回值即可。
2.4数组操作方法
Java本身对于数组是有提供类库的支持的,下面来说两个数组有关的操作。
1、数组的拷贝:可以将一个数组的内容拷贝到另外一个数组之中;
语法:System.arraycopy(源数组名称,源数组拷贝开始索引,目标数组名称,目标数组拷贝开始索引,长度)
范例:实现数组拷贝
l 数组A:1、2、3、4、5、6、7、8
l 数组B:11、22、33、44、55、66、77、88
l 要求拷贝后的数组B:11、22、5、6、7、66、77、88。
public class ArrayDemo { public static void main(String[] args) { int[] dataA = new int[]{1,2,3,4,5,6,7,8,9}; int[] dataB = new int[]{11,22,33,44,55,66,77,88,99}; System.arraycopy(dataA,4,dataB,2,3); print(dataB);
}
public static void print(int temp[]) { for (int i=0; i<temp.length; i++) { System.out.print(temp[i] + "、"); } System.out.println(); } } |
2、数组排序:之前排序的基本操作,但是在开发中如果进行排序只需要使用如下代码即可
l 语法:Arrays.sort(数组名称)
范例:实现排序
import java.util.Arrays;
public class ArrayDemo { public static void main(String[] args) { int[] data = new int[]{3,6,2,4,5,1,8,7,9}; Arrays.sort(data);//排序 print(data);
}
public static void print(int temp[]) { for (int i=0; i<temp.length; i++) { System.out.print(temp[i] + "、"); } System.out.println(); } } |
2.5对象数组
数组是引用类型,而类也是同样是引用类型,所以如果是对象数组的话表示引用类型里面嵌套其他的引用类型。
在之前使用的数组都属于基本数据类型的数组,但是所有引用数据类型也同样可以定义数组,这样的数组称为对象数组。如果想定义对象数组(以类为例),可以采如下形式完成:
l 动态初始化:开辟之后对象数组的内容都是null值。
n 声明并初始化对象数组:类名称 对象数组名称 [] = new 类名称[长度];
n 分布完成:
u 声明对象数组:类名称 对象数组名称 [] = null;
u 开辟对象数组:对象数组名称 = new 类名称[长度];
l 静态初始化:类名称 对象数组名称[] = new类名称[] {实例化对象,实例化对象,...}
范例:对象数组动态初始化
class Book{ private String title; private double price; public Book(String t,double p){ title = t; price = p; } public String getInfo(){ return "书名:" + title + "价格:" + price; } } public class ArrayDemo { public static void main(String[] args) { //开辟了一个三个长度的对象数组 Book books [] = new Book[3]; //对象数组中的每一个数据都需要分别实例化 books[0] = new Book("Java",78.8); books[1] = new Book("jsp",68.8); books[2] = new Book("abdroid",88.8);
for (int x=0;x<books.length; x++) { System.out.println(books[x].getInfo()); } }
} |
对象数组实际就是将多个对象数组同意管理
范例:静态初始化
class Book{ private String title; private double price; public Book(String t,double p){ title = t; price = p; } public String getInfo(){ return "书名:" + title + "价格:" + price; } } public class ArrayDemo { public static void main(String[] args) { //开辟了一个三个长度的对象数组 Book books [] = new Book[]{ new Book("Java",78.8), new Book("jsp",68.8), new Book("abdroid",88.8) }; for (int x=0;x<books.length; x++) { System.out.println(books[x].getInfo()); } } } |
一般而言,使用对象数组的时候只会定义成一维。
3、总结
1、数组用很少,但是一定会用,而且数组的相关的逻辑关系比较麻烦;
l 数组的排序与转置要明白;
2、一切以一维数组为主要明白数组的定义语法与内存关系(对象一致);
3、对象数组的定义语法,对象数组=多个对象;
4、数组有一个最大的天生短板:长度胡定,所以这就限制了数组在开发中出现
5、数组的排序:Arrays.sort(数组名称)。