JAVA中的数组

前言

李刚老师《JAVA疯狂讲义》第5版,第4章学习笔记。

1.什么是数组

JAVA中的数组也是一种数据类型,一种引用类型。

在JAVA中,要求所有的数组元素具有相同的数据类型,可以是基本数据类型,也可以是引用数据类型。一旦数组初始化完成,该数组在内存中的空间将被固定,其数组长度将不可变。

2.JAVA数组的定义

JAVA支持两种定义数组的语法:

type[] arrayName;
type arrayName[];

推荐使用第一种,语意更清晰,可读性更好。

注意:

  1. 由于JAVA中的数组为引用类型,因此上方的初始化仅仅是定义了一个引用变量,也就是定义了一个指针。但是,并未明确指向的内存,因此此时数组无法使用,必须在初始化之后才可以使用。
  2. 在定义数组时,不能指明数组长度。
  3. 不能只为数组分配内存空间,而不给数组赋初值。只要给数组分配内存空间,数组中的数组元素就有了值,即使内存是空的,也是null值。

3.JAVA数组的初始化

JAVA数组的初始化就是为数组的数组元素分配内存空间,并且为每个数组元素赋初值。JAVA中共有两种为数组初始化的方法:静态初始化、动态初始化。

3.1 静态初始化

人为指定数组中每个元素的初始值,数组长度可由系统自动获得。具体静态初始化方式如下:

//定义一个int类型数组
int[] intArr;
//静态初始化,只指定初值,不指定长度
intArr = new int[]{1,2,3,4,5};
//定义一个Object类型数组
Object[] objArr1;
//静态初始化1
objArr1 = new String[]{"good","good","study"};
//定义一个Object类型数组
Object[] objArr2;
//静态初始化2
objArr2 = new Object[]{"day","day","up"};
//借助var来静态初始化数组,编译器会自动推断变量类型
var a = new int[]{1,2,3,4,5};
//简化的静态初始化写法,定义和初始化可以同时完成
int[] a = {1,2,3,4,5}

通过以上代码可以看到:

  1. 静态初始化方法无需指明数组长度。
  2. Object类型数组的元素可以是String,也就是可以为其子类,并且,在静态初始化时,可以指明是new String,也可以不指明,依旧采用new Object进行赋值。因为,JAVA中,子类实例就是特殊的父类实例。

注意
借助简化的静态初始化写法,同时定义和初始化数组时,不可以用var定义数组变量。

3.2 动态初始化

人为指定数组长度,数组元素由系统分配初值。具体如下:

//定义一个int类型数组
int[] intArr;
//动态初始化
intArr = new int[5];
//定义和动态初始化同时完成1
int[] intArr = new int[5];
//定义和动态初始化同时完成2
Object[] objArr = new String[5];

针对不同类型数组,系统按以下规则分配初值:

  1. 数组元素的类型为byte、short、int和long时,系统分配初值为0
  2. 数组元素的类型为float、double时,系统分配初值为0.0
  3. 数组元素的类型为char时,系统分配初值为’\u0000’
  4. 数组元素的类型为boolean时,系统分配初值为false
  5. 数组元素的类型为引用类型时,系统分配初值为null

注意:
不要同时使用静态初始化和动态初始化,也就是在进行数组初始化时,不要即指定数组的长度,也为每个数组元素分配初值。

4.JAVA数组的存储方式

想要真正掌握数组的相关内容,就必须理解JAVA中的数组在内存中的存储方式。

JAVA程序中的方法在执行时,每个方法都会建立自己的内存栈,在方法内部定义的局部变量,会一个一个放入这块栈内存中,当方法执行完毕,这块栈内存就会被销毁。

JAVA程序在执行时,会建立自己的内存堆,在程序中创建一个对象时,这个对象会被保存到这个内存堆中,以便反复利用,堆内存中的对象不会随着某一个方法的结束而销毁。只有当对象没有任何引用变量引用它的时候,系统垃圾回收器才会在合适的时候回收该对象。

综上,JAVA运行时占用的内存空间可分为栈内存堆内存两部分,栈内存储存引用变量,堆内存储存对象。简单来说,变量就像快捷方式,而对象才是真正安装的软件(在JAVA中就是真正存储数据的部分)。

在理解了JAVA中的栈内存和堆内存后,就可以分析数组在内存中的存储方式了。具体如下:

public class demo{
	public static void main(String args[]){
		//1.定义并初始化数组
		int[] a = {1,2,3};
		int[] b = new int[4];
		//2.赋值操作
		b = a;
	}
}

上述代码中,经过1.定义并初始化数组后,a,b在内存中的储存形式为:
JAVA数组内存存储形式
可以看到,a,b两个引用变量在栈内存中存储,由于a先定义,因此a先入栈,b后入栈。两个数组内部的元素存储在堆内存中。

上述代码中,经过2.赋值操作后,内存中的存储形式变为:
JAVA数组在内存中的存储
可见,b和a均指向堆内存中同一块区域,对b的修改会同时影响到a。同时,原始的堆内存中的b数组处于没有引用变量指向的状态,等待系统垃圾回收机制回收。

综上,在看待数组时,一定要把数组看成两部分,一部分是数组的引用,存储在栈内存中;另一部分是实际的数组对象,存储在堆内存中。

对于引用类型数组的内存分析与基础类型数组的内存分析基本相同,只不过,引用类型数组的每个数组元素也是一个引用,具体如下:

public class demo{
	public static void main(String args[]){
		//1.定义一个引用类型数组并动态初始化(假定Person类已经定义过)
		Person[] students;
		students = new Person[2];
		//2.创建两个Person实例,并赋值
		Person zhang = new Person();
		Person li = new Person();
		zhang.age = 18;
		zhang.height = 172;
		li.age = 60;
		li.height = 180;
		//3.把zhang和li两个实例赋值给students这个引用数组
		students[0] = zhang;
		students[1] = li;
	}
}

上述代码中,经过1.引用数组的定义与动态初始化后,内存中状态为:
JAVA引用数组存储形式
Person的两个实例zhang和li也是两个引用类型,在经过2.创建两个Person实例,并赋值后,内存形式为:
JAVA引用对象存储形式
在经过3.把zhang和li两个实例赋值给students这个引用数组后,内存中存储形式为:
JAVA引用对象存储形式
可以想到JAVA中,多维数组本质上也是引用类型数组,只不过数组元素指向的引用对象又指向了一个数组。其在内存中的存储过程基本与上述类似,不再赘述。

5.JAVA数组的使用

5.1 JAVA数组的简单使用

数组最常用的使用方法就是访问数组元素,包括取出数组中元素值和对数组中元素进行赋值,与大多数编程语言相同,JAVA中的索引从0开始,具体如下:

public class demo{
	public static void main(String args[]){
		//定义并初始化数组
		int[] a = {1,2,3,4,5};
		//取出数组中某个元素
		System.out.println(a[1]);
		//对数组中的某个元素赋值
		a[2] = 7;
	}
}

当访问数组元素时,指定的索引值小于0,或者大于数组长度-1,则会抛出java.lang.ArrayIndexOutOfBoundsException:N(数组越界异常)。可以使用数组的length属性来查看某个数组的长度。

通过循环的方法可以遍历数组中的元素,例如:

int[] a = {1,2,3,4,5};
for(int i = 0 ; i < a.lenght; i++){
	System.out.println(a[i]);
}

JAVA中也可以使用foreach循环来更为简洁的遍历数组中的所有元素,如下:

int[] a = {1,2,3,4,5};
for(int num : a){
	System.out.println(num);
}

5.2 借助Arrays工具类操作数组

JAVA提供的Arrays类可以用于操作数组,使用时需要首先导入Arrays包(import java.utils.Arrays)具体如下:

  1. int binarySearch(type[] a,type key):使用二分法查询key元素值在a数组中出现的索引,若a不包含key,则返回负时(注意:调用该方法要求数组元素已经按升序排列)
  2. int binarySearch(type[] ,int fromIndex,int toIndex,type key):与1基本类似,但只寻找数组从fromIndex到toIndex索引的元素
  3. type[] copyOf(type[] original, int length):将original数组复制成一个新数组,length是新数组长度。若length>original.length,则新数组前面的元素就是original的元素,后面补0;若length<original.length,则新数组就是原数组前length个元素。
  4. type[] copyOfRange(type[] original, int length,int from,int to):与3基本类似,但是只复制original中索引从from到to的元素
  5. boolean equals(type[] a1, type [] a2):如果a1和a2完全相同,长度相等且元素也相同,则返回true,否则false
  6. void fill(type[] a , type val):该方法把数组a的所有元素赋值为val
  7. void fill(type[] a , int fromIndex, int toIndex, type val):与6类似,但仅将a中索引从fromIndex到toIndex的部分赋值为val
  8. void sort(type[] a):对a数组进行排序
  9. void sort(type[] a ,int fromIndex, int toIndex):与8类似,但是只对fromIndex到toIndex的部分排序
  10. String toString(type[] a):将数组转化为一个字符串,按顺序把多个数组元素连接,多个数组元素使用英文逗号,和空格隔开
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值