数组的定义与使用

数组的基本定义

所有的项目开发之中都一定会存在有数组的使用,但是本次所讲解的只是数组的基本概念,而基本形式的数组出现的几率会有,但是不高,并且也不会涉及到过多复杂的操作,这只是针对于你自己编写的程序代码而言。
数组的基本概念:
如果说现在要定义100个整型变量,那么按照传统的做法,现在的实现如下:
int i1,i2,i3…i100;
这种方式的确是可以进行定义,但是如果说着100个变量属于关联的一组变量,则按照此种模式定义出来的变量就不适合于程序维护了(没有任何的参考规律),所以在程序开发之中考虑到一组变量的整体维护,专门提供有数组的概念,数组的本质在于:一组相关变量的集合,但是需要注意的一点是:在Java里面将数组定义为了引用数据类型,所以数组的使用一定要牵扯到内存分配,那么首先就一定可以想到使用关键字new来处理,数组的定义格式:
数组的动态初始化,初始化之后数组每一个元素的保存内容为其对应数据类型的默认值;
-声明并初始化数组:
数据类型 数组名称 [ ] = new 数据类型 [ 长度] ;
数据类型 [ ] 数组名称 = new 数据类型 [ 长度] ;
数组的静态初始化:在数组定义的时候就为其设置好了里面的内容;
简化格式:数据类型 数组名称 [ ] = {数据1,数据2,数据3…}
完整格式:数据类型 数组名称 [ ] = new 数据类型 [ ] {数据1,数据2,数据3…};
当我们创建了一个数组之后就可以按照如下的方式进行使用:
数组里面可以通过脚标进行每一个元素的访问,脚标从0开始定义,所以可以使用的脚标范围:“0~数组长度-1”,同时一定要注意,如果使用的时候超过了数组脚标的范围则会出现“.ArrayIndexOutOfBoundsException”(超过范围)
使用数组是为了其可以进行方便的变量管理,所以在进行数组操作的时候往往会利用for循环来完成;
对于数组的长度也可以使用“数组名称.length”来获得

public class ArrayDemo {
	public static void main(String args[]){
		// 使用数组的动态初始化实现了数组的定义
		int data [] = new int [3] ;
		data[0] = 11;
		data[1] = 23;
		data[2] = 56;
		for (int x = 0; x < data.length ; x ++){
		System.out.println(data[x]) ;

		}
	}
}

在你们以后进行项目的开发过程之中,见到最多的数组使用形式:进行数组的循环处理
数组本身分为动态初始化与静态初始化,动态初始化之后会发现数组之中的每一个元素的内容都是其对应数据类型的默认值,随后可以通过下标为数组进行内容的设置,如果现在不希望这么复杂,而是希望数组定义的时候就已经可以提供内容,则可以采用静态初始化的方式完成
范例:使用静态初始化定义数组

public class ArrayDemo {
	public static void main(String args[]){
		// 使用数组的静态初始化实现了数组的定义
		int data [] = new int [] {11,23,56};
		for (int x = 0; x < data.length ; x ++){
		System.out.println(data[x]) ;

		}
	}
}

对于数组的操作而言,基本是哪个都是拿到数据后循环控制。建议使用完成的静态初始化形式

数组引用传递分析

通过数组的基本定义可以发现,在数组使用的过程之中依然需要关键字new进行内存空间的开辟,同理,那么这里面也一定存在有内存的关系匹配。
范例:定义一个简单的代码

public ArrayDemo {
	public static void main(String args[]){
		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 [] = new int [] {10,20,30} ;
		int temp [] = data ;
		temp [0] = 99 ;
		for (int x = 0 ; x < data.length ; x ++){
			System.out.println(data[x]) ;
		}
	}
}

在这里插入图片描述
下面通过此程序进行内存分析
在这里插入图片描述
由于数组属于引用类型,所以一定要为其开辟堆内存空间之后才可以使用,如果现在使用了未开辟内存空间数组会出现“NullPointerException”异常。
必须提供有实例化对象才可以使用数组的操作形式进行数组的操作。

foreach迭代输出

对于数组而言,一般都会使用for循环进行输出,但是在使用传统for循环输出的时候往往都采用了下标的形式进行数组元素的访问
范例:传统形式

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]) ;
		}
	}
}

而从JDK1.5之后为了减轻下标对程序的影响(如果下标处理不当则会出现数组越界异常),所以参考了.NET中的设计,引入了一个增强型的for循环(foreach),利用foreach的语法结构可以直接自动获取数组中的每一个元素,避免下标访问。语法如下:

for (数据类型 变量 : 数组 | 集合){}

最大的特点在于可以自动将数组中的每一个元素的内容取出保存在变量里面,这样就可以直接通过变量获取数组内容,而避免下标的方式来获取了。
范例:使用foreach语法输出

public class ArrayDemo {
	public static void main(String args[]){
		int data [] = new int [] {1,2,3,4,5} ;
		for (int temp : data){  //自动循环,将data数组每一个内容交给temp
			System.out.println(temp) ;
		}
	}
}

在这里插入图片描述
这种语法的好处可以避免下标的操作。

二维数组

在之前所定义的数组里面会发现只有一个“[ ]”,所以这个时候的数组就好像一行数据一样可以利用下标进行行数据的访问
传统的数据就好比一行数据,如果要找一个数据,只需要确定一个下标
在这里插入图片描述
如果说现在你需要的是一个多行多列的结构(表),则就需要通过两个下标才可以确定一个数据
在这里插入图片描述
对于维维数组可以使用的定义语法如下:
数组的动态初始化
——数据类型 数据名称[ ] [ ] = new 数据类型 [行个数][列个数]
数组的静态初始化
——数据类型 数据名称 [ ] [ ] = new 数据类型 [ ] [ ]{ { 数据,数据,数据…},{数据,数据…},{数据,数据,数据…}…}
范例:定义二维数组

public class ArrayDemo {
	public static void main(String args[]){
		int data [][] = new int [][] {
			{1,2,3,4,5}, {1,2,3}, {5,6,7,8}
		} ;
		for (int x = 0; x < data.length ; x ++){
			for (int y = 0; y < data[x].length ; y ++){
				System.out.println("data[" + x + "][" + y + "] = " + data[x][y]) ;
			}
			System.out.println() ;	//换行
		}
	}
}

在这里插入图片描述
如果这个时候要求使用foreach使用

public class ArrayDemo {
	public static void main(String args[]){
		int data [][] = new int [][] {
			{1,2,3,4,5}, {1,2,3}, {5,6,7,8}
		} ;
		for (int temp [] : data){
			for (int num : temp){
				System.out.print(num + " ") ;
			}
			System.out.println() ;	//换行
		}
	}
}

通过foreach的输出格式可以清楚的观察到,二维数组救赎数组的嵌套使用。随着开发技术的发展,如果要进行一些应用层的程序开发,那么很少会涉及到二维数组,更不用说更高级的多维数组。

数组与方法

对于引用数据类型而言,主要的特点是可以与方法进行引用传递,而数组本身也属于引用数据类型,所以也可以通过方法实现引用传递的作用。
传递:实现一个数组的引用传递

public class ArrayDemo {
	public static void main(String args[]){
		int data [] = new int [] {1,2,3,4,5} ;
		printArray(data) ; 
	}
	public static void printArray(int temp []) {
		for (int x = 0; x < temp.length ; x ++) {
			System.out.println(temp[x]) ;
		}
	}
}

对于此时的引用传递具体的内存关系如下。
在这里插入图片描述
既然可以通过方法来接收一个数组,那么也就可以通过方法返回一个数组对象,那么此时只需要在方法的返回值类型上进行控制即可。
范例:定义方法返回数组

public class ArrayDemo {
	public static void main(String args[]){
		int data [] = initArray() ;
		printArray(data) ; 
	}
	public static int [] initArray(){
		int arr [] = new int [] {1,2,3,4,5} ;
		return arr ;
	}
	public static void printArray(int temp []) {
		for (int x = 0; x < temp.length ; x ++) {
			System.out.println(temp[x]) ;
		}
	}
}

下面来针对于此程序进行内存关系分析。、
在这里插入图片描述
范例:通过方法修改数组内容

public class ArrayDemo {
	public static void main(String args[]){
		int data [] = new int [] {1,2,3,4,5} ;
		changeArray(data) ;
		printArray(data) ; 
	}
	public static void changeArray(int arr[]){
		for (int x = 0; x < arr.length ; x ++)
			arr[x] *= 2 ;
	}
	public static void printArray(int temp []) {
		for (int x = 0; x < temp.length ; x ++) {
			System.out.println(temp[x]) ;
		}
	}
}

本程序的内存关系图如下:
在这里插入图片描述
案例:随意定义一个数字,要求可以计算出这个数组元素的综合、最大值、最小值、平均值。

public class ArrayDemo {
	public static void main(String args[]){
		int data [] = new int [] {1,2,3,4,5} ;
		int sum = 0 ;
		double avg = 0.0 ;
		int max = data[0] ;
		for (int x = 0; x < data.length ; x ++){
			sum += data[x] ;
			if (max < data[x])
				max = data[x] ;
		}
		avg = sum / data.length ;
		System.out.println("数组内容总和:" + sum) ;
		System.out.println("数组内容平均值:" + avg) ;
		System.out.println("数组内容最大值:" + max) ;
	}

	public static void printArray(int temp []) {
		for (int x = 0; x < temp.length ; x ++) {
			System.out.println(temp[x]) ;
		}
	}
}

主方法所在的类往往被称为主类,那么既然是主类肯定不希望涉及到过于复杂的功能。在进行开发的过程之中,主方法本身就相当于是一个客户端,而对于客户端的代码应该尽量简单一些,所以这个时候最好的做法是将这一系列的计算过程交给单独的程序类去完成。

class ArrayUtil {
	private int sum ;
	private double avg ;
	private int max ;
	private int min ;
	public ArrayUtil(int data[]){
		this.max = data[0] ;
		for (int x = 0; x < data.length ; x ++){
			this.sum += data[x] ;
		if (this.max < data[x])
				this.max = data[x] ;
		}
		this.avg = this.sum / data.length ;
	}
	public int getSum(){
		return this.sum ;
	}
	public double getAvg(){
		return this.avg ;
	}
	public int getMax(){
		return this.max ;
	}
	public int getMin(){
		return this.min ;
	}
}
public class ArrayDemo {
	public static void main(String args[]){
		int data [] = new int [] {1,2,3,4,5} ;
		ArrayUtil uti = new ArrayUtil(data) ;
		System.out.println("数组内容总和:" + uti.getSum()) ;
		System.out.println("数组内容平均值:" + uti.getAvg()) ;
		System.out.println("数组内容最大值:" + uti.getMax()) ;
	}
}

此时的主类就好比我们使用电脑一样,只关心如何操作,而具体的操作过程被类进行。

数组排序案例分析

数组排序指的是可以将一个杂乱的数组按照顺序进行码放,但是对于数组排序总是通过一个基础的模型完成的,例如:先通过升序排序的方式来观察排序的处理
范例:数组排序分析
在这里插入图片描述

public class ArrayDemo {
	public static void main(String args[]){
		int data [] = new int [] {8,9,0,2,3,5,10,7,6,1} ;
		for (int x = 0 ; x < data.length ; x ++){
					for (int y = 0; y < data.length - x - 1 ; y ++){
			if (data[y] > data[y + 1]){
				int temp = data[y] ;
				data[y] = data[y + 1];
				data[y + 1] = temp ;
			}
		}
		}
		printArray(data);
	}
	public static void printArray(int temp []){
		for (int x = 0 ; x < temp.length ; x ++){
			System.out.println(temp[x] + "、") ;
		}
		System.out.println() ;
	}
}

以上的程序代码都是通过主方法完成的,不符合面向对象的设计结构,那么最好的对象的设计结构,最好的做法是将这个排序处理的操作交给一个类进行处理完成。
在以后进行类设计的时候,如果发现类中没有属性存在的意义,那么定义的方法就没有必要使用普通方法了,因为普通方法需要在有实例化对象产生的情况才调用,从而可以选择其他的static 定义,直接调用类中的方法。

class ArrayUtil{
	public static void sort(int data []){
			for (int x = 0 ; x < data.length ; x ++){
				for (int y = 0; y < data.length - x - 1 ; y ++){
					if (data[y] > data[y + 1]){
					int temp = data[y] ;
					data[y] = data[y + 1];
					data[y + 1] = temp ;
					}
				}
			}	
	}
		public static void printArray(int temp []){
		for (int x = 0 ; x < temp.length ; x ++){
			System.out.println(temp[x] + "、") ;
		}
		System.out.println() ;
	}
}
public class ArrayDemo {
	public static void main(String args[]){
		int data [] = new int [] {8,9,0,2,3,5,10,7,6,1} ;
		ArrayUtil.sort(data) ;
		ArrayUtil.printArray(data) ;
	}

}

数组转置案例分析

数组的反转操作指的是进行前后转置处理,即:首尾交换,例如,现在有一个数组,其内容如下:
数组内容:1、2、3、4、5、6、7、8、9:
交换后的内容:9、8、7、6、5、4、3、2、1:
对于数组的前后交换有两种做法:
做法一:定义一个新的数组而后按照逆序的方式保存(会产生没用的垃圾)

class ArrayUtil{
	public static void sort(int data []){
			for (int x = 0 ; x < data.length ; x ++){
				for (int y = 0; y < data.length - x - 1 ; y ++){
					if (data[y] > data[y + 1]){
					int temp = data[y] ;
					data[y] = data[y + 1];
					data[y + 1] = temp ;
					}
				}
			}	
	}
		public static void printArray(int temp []){
		for (int x = 0 ; x < temp.length ; x ++){
			System.out.println(temp[x] + "、") ;
		}
		System.out.println() ;
	}
}
public class ArrayDemo {
	public static void main(String args[]){
		int data [] = new int [] {1,2,3,4,5,6,7,8,9} ;
		int temp [] = new int [data.length] ;
		int foot = temp.length - 1 ;
		for (int x = 0; x < data.length ; x ++){
			temp[foot --] = data[x] ;
		}
		data = temp ;
		ArrayUtil.printArray(data) ;
	}
}

下面进行内存分析:
在这里插入图片描述
做法二:在一个数组上转置
在这里插入图片描述
现在如果要想实现这种转置最需要确定的就是数组转换的次数,次数的计算:“数组长度除以2”,实际是哪个不用考虑是奇数还是偶数的个数。

class ArrayUtil{
	public static void sort(int data []){
			for (int x = 0 ; x < data.length ; x ++){
				for (int y = 0; y < data.length - x - 1 ; y ++){
					if (data[y] > data[y + 1]){
					int temp = data[y] ;
					data[y] = data[y + 1];
					data[y + 1] = temp ;
					}
				}
			}	
	}
		public static void printArray(int temp []){
		for (int x = 0 ; x < temp.length ; x ++){
			System.out.println(temp[x] + "、") ;
		}
		System.out.println() ;
	}
}
public class ArrayDemo {
	public static void main(String args[]){
		int data [] = new int [] {1,2,3,4,5,6,7,8,9} ;
		int center = data.length / 2 ;
		int head = 0 ;
		int tail = data.length - 1 ;
		for (int x = 0; x < center ; x ++){
			int temp = data [head] ;
			data [head] = data [tail] ;
			data [tail] = temp ;
			head ++ ;
			tail -- ;
		}
		ArrayUtil.printArray(data) ;
	}
}

两种实现如要进行比较可以发现,第一种处理方式循环次数较多,并且还会产生垃圾,而第二种实现循环次数降低但存在if判断增加了时间复杂度,可是可以减少无用对象的产生,以提升性能。
范例:将转换功能变为类定义;

class ArrayUtil{
	public static void reverse(int data []){
		int center = data.length / 2 ;
		int head = 0 ;
		int tail = data.length - 1 ;
		for (int x = 0; x < center ; x ++){
			int temp = data [head] ;
			data [head] = data [tail] ;
			data [tail] = temp ;
			head ++ ;
			tail -- ;
		}
	}
		public static void printArray(int temp []){
		for (int x = 0 ; x < temp.length ; x ++){
			System.out.println(temp[x] + "、") ;
		}
		System.out.println() ;
	}
}
public class ArrayDemo {
	public static void main(String args[]){
		int data [] = new int [] {1,2,3,4,5,6,7,8,9} ;
		ArrayUtil.reverse(data) ;
		ArrayUtil.printArray(data) ;
	}
}

可以发现数组由于可以通过脚标进行元素的控制,所以相应的循环逻辑使用的比较多。

数组相关类库

由于数组是一个重要的概念,所以在Java语言本身也提供有数组的相关支持处理,这些处理是在开发中使用的。
1、数组排序:java.util.Arrays.sort(数组名称)

class ArrayUtil{
		public static void printArray(int temp []){
		for (int x = 0 ; x < temp.length ; x ++){
			System.out.println(temp[x] + "、") ;
		}
		System.out.println() ;
	}
}
public class ArrayDemo {
	public static void main(String args[]){
		int data [] = new int [] {12,21,36,42,58,63,17,38,69} ;
		java.util.Arrays.sort(data) ;
		ArrayUtil.printArray(data) ;
	}
}

2、数组拷贝(把方法做了一些变形):
System.arraycopy(源数组,源数组开始点,目标数组,目标数组开始点,拷贝长度)
范例:实现数组拷贝
现在假设两个数组:
数组一:1 2 3 4 5 6 7 8 9
数组二:11 22 33 44 55 66 77 88 99:
要求拷贝之后的数组二内容为:11 22 33 6 7 8 77 88 99

class ArrayUtil{
		public static void printArray(int temp []){
		for (int x = 0 ; x < temp.length ; x ++){
			System.out.println(temp[x] + "、") ;
		}
		System.out.println() ;
	}
}
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,5,dataB,3,3) ;
		ArrayUtil.printArray(dataB) ;
	}
}

这些操作的支持都是系统本身提供的,即:都是可以在开发中使用的,实际上如果要自己实现:

class ArrayUtil{
		public static void printArray(int temp []){
		for (int x = 0 ; x < temp.length ; x ++){
			System.out.println(temp[x] + "、") ;
		}
		System.out.println() ;
	}
	public static void arraycopy(int [] src, int sindex, int dsc[], int dindex, int len){
		for (int x = 0; x < len ; x ++){
			dsc [dindex ++] = src[sindex ++] ;
		}
	}
}
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} ;
		ArrayUtil.arraycopy(dataA,5,dataB,3,3) ;
		ArrayUtil.printArray(dataB) ;
	}
}

如果要是自己去定义这种拷贝或者排序的方法就需要考虑所有的数据类型。

方法可变参数

如果说现在要求定义一个方法,这个方法可以实现任意多个整型数据的相加处理。这样的情况下最早的时候只能够通过数组进行处理。

class ArrayUtil{
		public static int sum(int data []){
			int sum = 0 ;
			for (int temp : data){
				sum += temp ;
			}
			return sum ;
		}
}
public class ArrayDemo {
	public static void main(String args[]){
		System.out.println(ArrayUtil.sum(new int [] {1,2,3})) ;
	}
}

虽然以上的程序可以实现任意多个数组的参数内容传递,但是与实际的要求并不符合,实际要求的是介意传递任意多个参数而不是一个数组。从JDK1.5开始为了方便开发者进行可变参数的定义,对于方法的参数提供有新的支持。
范例:采用可变参数

class ArrayUtil{
		public static int sum(int ... data){
			int sum = 0 ;
			for (int temp : data){
				sum += temp ;
			}
			return sum ;
		}
}
public class ArrayDemo {
	public static void main(String args[]){
		System.out.println(ArrayUtil.sum(1,2,3)) ;
		System.out.println(ArrayUtil.sum(new int [] {1,2,3})) ;
	}
}

可变参数的最大作用在于,在以后进行一些程序类设计或者开发者调用的时候,利用此种形式就可以避免数组的传递操作,可变参数的本质需要清除的是:依然属于数组。

对象数组

在之前所接触到的都是基本数据定义的数组,但是在Java程序本身各种数据类型都可以称为数组类型,所以类也可以称为数组类型,而这样的数组就称为对象数组,对象数组的定义格式如下:
动态初始化:类 对象数组名称 [ ] = new 类 [长度],每一个元素的内容都是null:
静态初始化: 类 对象数组名称 [ ] = new 类 [ ] {实例化对象,实例化对象…} ;
范例:使用动态初始化定义对象数组

class Person {
	private String name ;
	private int age ;
	public Person(String name, int age){
		this.name = name ;
		this.age = age ;
	}
	public String getInfo(){
		return "姓名" + this.name + "、年龄:" + this.age ;
	}
}
public class ArrayDemo {
	public static void main(String args[]){
		Person per [] = new Person[3] ;
		per[0] = new Person("张三", 20) ;
		per[1] = new Person("李四", 15) ;
		per[2] = new Person("王五", 10) ;
		for (int x = 0; x < per.length ; x ++){
			System.out.println(per[x].getInfo()) ;
		}
	}
}

范例:对象数组静态初始化

class Person {
	private String name ;
	private int age ;
	public Person(String name, int age){
		this.name = name ;
		this.age = age ;
	}
	public String getInfo(){
		return "姓名" + this.name + "、年龄:" + this.age ;
	}
}
public class ArrayDemo {
	public static void main(String args[]){
		Person per [] = new Person [] {
			new Person("张三", 20) ,
			new Person("李四", 15) ,
			new Person("王五", 10) ,
		} ;
		for (int x = 0; x < per.length ; x ++){
			System.out.println(per[x].getInfo()) ;
		}
	}
}

对于对象数组而言,本身知识更换了一种所谓的数组定义的类型,但是这个时候内存图就比较麻烦。
在这里插入图片描述
所有的开发都不可能离开对象数组,但是通过一系列的分析也应该知道一个数组中的最大缺陷:长度是固定的。优势:数据线性保存,根据索引访问,速度较快(时间复杂度为1)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值