1、数组的基本定义
数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同。Java 语言中提供的数组是用来存储固定大小的同类型元素。
声明一个数组变量,如 numbers[100] 来代替直接声明 100 个独立变量 number0,number1,....,number99。
数组的本质是一组相关变量的集合,但在Java里面将数组定义为了引用数据类型,所以数组的使用会和内存产生联系,而内存的关键字又与new相关。
数组的定义格式:
类型 | 格式 | 特征 | |
动态初始化 | 1)数组类型 数组名称 [] = new 数据类型[长度] 2)数组类型 [] 数组名称 = new 数据类型[长度] | 动态初始化之后数组每一个元素的保存内容为其对应数据类型的默认值 | |
静态初始化 | 简化格式 | 数据类型 数组名称 [] = {数据1,数据2,数据3,...} ; | 数组定义的时候就为其设置好了里面的内容 |
完整格式 | 数据类型 数组名称 [] =new 数据类型[] {数据1,数据2,数据3,...} ; |
当创建了一个数组之后就可以按照如下的方式进行使用:
1)数组里面可以通过角标进行每一个元素的访问,脚标从0开始,而脚标范围是:0~数组长度-1;若脚标长度大于数组长度,则会出现数组越界异常;
2)使用数组是为了其可以进行方便的变量管理,所以在进行数组操作的时候会利用for循环来完成;
3)对于数组的长度也可以使用“数组名称.length”属性进行获得;
范例:定义数组
代码 | 结果 | 分析 | |
动态化数组 | package cn.demos; public class Demo2 { public static void main(String arg[]) { | 1 2 3 | 动态初始化之后,数组之中的每一个元素的内容都是其对应数据类型的默认值,随后可以通过下标为数组进行内容的设置。 |
静态化数组 | package cn.demos; public class Demo2 { public static void main(String arg[]) { | 11 22 33 | 在进行数组初始化的时候就进行赋值 |
2、数组的引用传递分析
通过数组的基本定义可以发现,在数组使用的过程之中依然需要关键词new进行内存空间的开辟,所以数组也存在有内存引用的问题。
范例:定义一个简单代码
package cn.demos; public class Demo2 { public static void main(String arg[]) { for (int x = 0; x < data.length; x++) { |
针对上面的代码进行数组内存分析:
但是数组本身属于引用数据类型,所以,会发生引用数据传递,按传统方式分析:一个堆内存可以被多个栈内存所指向。
范例:观察数组引用
代码 | 结果 |
package cn.demos; public class Demo2 { public static void main(String arg[]) { | 99 20 30 |
通过对上面程序进行内存分析,如下图:
注意:数组属于引用类型,所以一定要为其开辟堆内存空间之后才可以使用,如果使用了未开辟堆内存空间的数组则一定会出现“NullPointerException”异常;且要先提供实例化对象才可以使用下标对数组进行操作。
3、foreach输出
对于数组的输出,一般使用for循环实现。而传统的for循环在输出时采用的都是通过下标进行数组的输出。而为了避免在程序中操作不当出现数组越界异常,在JDK1.5之后,出现了增强版的for循环——foreach,利用foreach的语法结构可以直接自动获取数组中的每个元素,避免下标的访问。
代码 | 结果 | 特点 | ||
for循环 | package cn.demos; public class Demo2 { public static void main(String arg[]) { | 1 2 3 4 5 | 通过下标取数据 | |
foreach | 语法 | package cn.demos; public class Demo2 { public static void main(String arg[]) { for (int temp : data) { } | 可以自动将数组中的每一个元素的内容取出保存在变量里面,这样就可以直接通过变量获取数组内容,而非通过下标访问 | |
for(数据类型 变量 : 数组 | 集合){} |
4、二维数组
传统的数据相当于一行数据,而二维数据则相当于行列式,即一维数组只需要通过一个下标就可以访问数组,而二维数组则需要通过两个下标进行数据访问(可根据表的结构进行类比,或者行列式)。
二维数组定义语法:
分类 | 定义 |
数组的动态初始化 | 数组类型 数组名称 [][] = new 数据类型[行个数][列个数] |
数组的静态初始化 | 数据类型 数组名称[][] = new 数据类型[][] {{数据1},{数据2},...} |
范例:定义二维数组
代码 | 结果 |
package cn.demos; public class Demo2 { public static void main(String arg[]) { } | data【0】【0】=1 data【1】【0】=6 data【2】【0】=11 1、2、3、4、5、 |
通过上面的程序代码,观察foreach的输出格式,可以得知二维数组就是数组的嵌套使用。
5、数组与方法
对于引用数据类型而言,主要的特点是可以与方法进行引用传递,而数组也属于引用数据类型,所以,数组也可以通过方法实现引用传递的操作。
范例:实现一个数组的引用传递
代码 | 结果 |
package cn.demos; public class Demo2 { public static void main(String arg[]) { // 写一个打印方法;需要接收一个int型的数组 | 1 2 3 4 5 |
上述程序是定义一个方法接收数组类型的参数,所以,既然可以接收数组类型,那么就可以返回一个数组类型。
范例:定义方法返回数组类型
代码 | 结果 |
package cn.demos; public class Demo2 { public static void main(String arg[]) { public static int[] initArray() { // 写一个打印方法;需要接收一个int型的数组 | 1 2 3 4 5 |
范例:通过方法修改内容
代码 | 结果 |
package cn.demos; public class Demo2 { public static void main(String arg[]) { public static void changeArray(int[] arr) { // 写一个打印方法;需要接收一个int型的数组 | 2 4 6 8 10 |
范例:定义一个数组,要求可以计算出这个数组元素的总和、最大值、最小值以及平均值。
代码 | 结果 |
package cn.demos; class ArrayUtil { public ArrayUtil(int data[]) { public int getSum() { public void setSum(int sum) { public double getAvg() { public void setAvg(double avg) { public int getMax() { public void setMax(int max) { public int getMin() { public void setMin(int min) { } public class Demo2 { public static void main(String arg[]) { } } | 数组总和【10】 数组平均值【2.0】 数组最大值【5】 数组最小值【1】 |
6、数组排序案例分析
数组排序指的是无序数组变成升序或降序排序。
范例:按升序排序数组
代码 | 结果 |
package cn.demos; class ArrayUtil { public class Demo2 { public static void main(String arg[]) { int data[] = new int[] { 7, 9, 3, 4, 1, 8, 2, 5, 6 }; public static void printArray(int temp[]) { } | 1、2、3、4、5、6、7、8、9、 |
7、数组转置案例分析
数组的转置操作指的是前后转置处理,即:收尾交换。
范例:数组转置
转置前 | 1,2,3,4,5,6,7,8 |
转置后 | 8,7,6,5,4,3,2,1 |
对于数组的转置,有两种思路,第一种则是定义一个新的数组,而后按照逆序的方式保存;第二种做法则是在一个数组上进行转置。
代码 | 结果 | |
做法一 | package cn.demos; class ArrayUtil { public class Demo2 { public static void main(String arg[]) { int data[] = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; } | 8、7、6、5、4、3、2、1、 |
做法二 | package cn.demos; class ArrayUtil { public class Demo2 { public static void main(String arg[]) { int data[] = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; } | 8、7、6、5、4、3、2、1、 |
通过对上面两种做法的对比,可以发现第一种处理方式循环次数较多,且会产生垃圾;第二种的循环次数降低,具有if判断,增加了时间复杂度,但可以减少无用对象的产生。
8、数组相关类库
1)数组排序:
数组排序 | java.util.Arrays.sort(数组) |
2)数组拷贝
数组拷贝 | system.arraycopy(源数组,源数组开始点,目标数组,目标数组开始点,拷贝长度) |
范例:实现数组拷贝
假设目前有两个数组:
数组一 | 1,2,3,4,5,6,7,8 |
数组二 | 11,22,33,44,55,66,77,88 |
拷贝之后的结果:
结果数组 | 11,22,33,4,5,6,77,88 |
代码 | 结构 |
package cn.demos; class ArrayUtil { public class Demo2 { public static void main(String arg[]) { int dataA[] = new int[] { 1, 2, 3, 4, 5, 6, 7, 8 }; } | 11、22、33、4、5、6、77、88、 |
这些操作都是系统本身提供的,即可在开发中直接使用。
9、方法可变参数
范例:观察可变参数
代码 | 结果 |
package cn.demos; class ArrayUtil { public class Demo2 { public static void main(String arg[]) { } | 6 9 |
可变参数的最大作用在于,在以后进行一些程序类设计或者开发者调用时,利用可变参数就可以避免数组的传递操作,而可变参数的本质依然是数组。
10、对象数组
在之前所接触的都是基本数据类型定义的数组,但是在Java程序本身各种数据类型都可以称为数组类型,所以类也可以成为数组类型,而这样的数组就称为对象数组。
对象数组的定义格式:
定义 | |
静态初始化 | 类 对象数组[] = new 类[]{实例化对象1,实例化对象2,...} |
动态初始化 | 类 对象数组[] = new 类[长度] |
范例:使用动态初始化
代码 | 结果 |
package cn.demos; class Person { public Person(String name, int age) { @Override public String getName() { public void setName(String name) { public int getAge() { public void setAge(int age) { } public class Demo2 { public static void main(String arg[]) { } | Person [name=张三, age=13] Person [name=lisi, age=14] Person [name=王五, age=15] |
范例:使用静态初始化
代码 | 结果 |
package cn.demos; class Person { public Person(String name, int age) { @Override public String getName() { public void setName(String name) { public int getAge() { public void setAge(int age) { } public class Demo2 { public static void main(String arg[]) { } | Person [name=张三, age=13] Person [name=lisi, age=14] Person [name=王五, age=15] |