文章目录
1.数组的基本概念
1.1什么是数组
数组是可以存放相同类型的数据的一个集合,是连续的一块内存
1.2数组的创建和初始化
public static void main(String[] args) {
int[] arr1 = {1,2,3,4,5};//静态初始化,定义并同时初始化了一个数组,这个数组的长度是5,数据分别是1,2,3,4,5
//arr1 = {1,2,3,4};//错误
int[] arr2 = new int[]{1,2,3,4,5,6};//定义且同时初始化了一个数组,这个数组长度是5
arr2 = new int[]{1,2,34};
System.out.println(arr2.length);//计算数组的长度
System.out.println(arr1[0]);//访问零下标的数字
int[] arr3 = new int[5];//动态初始化,定义了一个数组,数组长度是5,没有初始化,默认值是0
arr3 = new int[]{1,2,4};
int[] arr4;
//arr4 = {1,2,4};//错误
}
相关事项及注意事项:
①new是Java中的关键字,实例化对象的,意味着Java当中的数组就是对象
②静态初始化就是整体赋值只有一次赋值的机会,就是在定义的时候
③动态初始化:在创建数组时,直接指定数组中元素的个数
④静态初始化:在创建数组时不直接指定数据元素个数,而直接将具体的数据内容进行指定
⑤静态初始化虽然没有指定数组的长度,编译器在编译时会根据{}中元素个数来确定数组的长度;静态初始化时, {}中数据类型必须与[]前数据类型一致;静态初始化可以简写,省去后面的new T[]
⑥如果数组中存储元素类型为引用类型,默认值为null
1.3数组的使用
1.数组中元素的访问不能越界访问
2.既可以通过下标读取数组的元素,也可以通过下标写入修改元素
3.遍历数组:
①使用for遍历数组(在牵扯到下标的时候建议使用普通的for循环)
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6};
for(int i = 0;i <array.length;i++){
System.out.println(array[i]);
}
}
②使用for-each遍历数组:遍历array中的每一个元素,把元素存放到x当中,然后打印,增强for循环,不是专门来遍历数组的
语法格式:
for(表达式1:表达式2){
}
//表达式1是当前数组当中的元素的数据类型定义的变量
//表达式2是当前数组的名称
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6};
for (int x:array) {
System.out.println(x);
}
}
③使用Arrays.toString(数组名)遍历数组
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6};
String ret = Arrays.toString(array);
System.out.println(ret);//[1, 2, 3, 4, 5, 6]
}
注意:Java针对数组这种类型,专门提供了一个操作数组的工具类,可以完成一些对数组的操作
2.数组是引用类型
2.1初识JVM的内存分布
1.JVM是由c\c++实现的软件
2.一般对象都是在堆上的,当对象不在有人使用的时候就会被回收,回收的前提是不在有人使用
3.程序计数器:是来保存下一条执行的指令的地址
4.虚拟机栈:与方法调用相关的一些信息,每个方法在执行时,都会先创建一个栈帧,栈帧中包含有:局部变量表、操作数栈、动态链接、返回地址以及其他的一些信息,保存的都是与方法执行时相关的一些信息,比如:局部变量。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了。
5.本地方法栈: 本地方法栈与虚拟机栈的作用类似,只不过保存的内容是Native方法(Java无法实现)的局部变量,在有些版本的 JVM 实现中(例如HotSpot),本地方法栈和虚拟机栈是一起的
6.堆:JVM所管理的最大内存区域, 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2, 3} ),堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销毁。
7.方法区: 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
2.2基本数据类型和引用数据类型的区别
1.引用数据类型和基本数据类型
public static void main(String[] args) {
int a = 10;
int b = 20;
int[] arr = new int[]{1,2,3};
}
绘图解释这段代码:
①引用类型变量,里面存储的就是对象的地址
②arr是引用类型变量–>引用,里面存储的是数组对象的地址
③arr是一个数组对象
④引用变量并不直接存储对象本身,可以简单理解成存储的是对象在堆中空间的起始地址。通过该地址,引用变量便可以去操作对象
2.再谈引用数据类型
public static void func() {
int[] array1 = new int[3];
array1[0] = 10;
array1[1] = 20;
array1[2] = 30;
int[] array2 = new int[]{1,2,3,4,5};
array2[0] = 100;
array2[1] = 200;
array1 = array2;
array1[2] = 300;
array1[3] = 400;
array2[4] = 500;
for (int i = 0; i < array2.length; i++) {
System.out.println(array2[i]);
}
}
public static void main(String[] args) {
func();//100 200 300 400 500
}
总结:
①int[] array1 = {1,2,3,4};
array1这个引用指向{1,2,3,4}这个数组对象
②int[] array = null;
array这个引用不指向任何对象
③array1=array2 引用不能指向引用
array1这个引用指向了array2这个引用指向的对象
2.3认识null~~
1.空指针异常说明某一个引用是空的
2. Java 中并没有约定 null 和 0 号地址的内存有任何关联,C语言中的NULL是指0地址,并且是受保护的
3.数组的应用场景
3.1保存数据
public static void main(String[] args) {
int[] arr = {1,23,4};
for(int i = 0 ;i <arr.length;i++){
System.out.println(arr[i]);
}
}
3.2作为函数的参数
1.参数传基本数据类型
public static void func1(int a){
a = 10;
}
public static void main(String[] args) {
int x = 99;
func1(x);
System.out.println(x);//99 传值传递
}
2.参数传数据类型(引用数据类型)
public static void func2(int[] array) {
array = new int[]{1,2,3,4};
}
public static void main(String[] args) {
int[] arr = {5,6,7};
func2(arr);
System.out.println(Arrays.toString(arr));//[5, 6, 7]
}
结论:不是传地址就一定能改变参数的值,传地址之后,是修改了指向(不改变),还是修改了内容(改变)
public static void func3(int[] array) {
array[0] = 10;
}
public static void main(String[] args) {
int[] arr = {5,6,7};
func3(arr);
System.out.println(Arrays.toString(arr));//[10, 6, 7]
}
结论:两个引用同时指向一块内存,通过其中的一个引用,修改对象的值,那么另一个引用去访问的时候也是发生了改变的
3.作为函数的返回值
public static int[] func4() {
int[] array = {1,2,3,4};
return array;
}
public static void main(String[] args) {
int[] ret = func4();
System.out.println(Arrays.toString(ret));//[1,2,3,4]
}
4.二维数组
4.1基本语法
数据类型[ ][ ] 数组名称 = new 数据类型[ ][ ]{初始化数据}
4.2理解
第一个图就解释了第二个图中的代码为什么要这样书写
4.3打印二维数组
public static void main(String[] args) {
//for循环
int[][] array = {{1,2,3},{4,5,6}};
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j]+" ");
}
System.out.println();
}
System.out.println("-----------------------");
//for-each
for (int[] tmp:array) {
for (int x:tmp) {
System.out.print(x+" ");
}
System.out.println();
}
}
for-each中完美的体现了一维数组是特殊的二维数组
public static void main(String[] args) {
int[][] array = {{1,2,3},{4,5,6}};
System.out.println(Arrays.toString(array));//[[I@1b6d3586, [I@4554617c]
//以上打印就说明了二维数组的第一个元素是一个地址
System.out.println(Arrays.deepToString(array));//[[1, 2, 3], [4, 5, 6]]
}
4.4不规则的二维数组
public static void main(String[] args) {
//int[][] array = new int[][3];//错误,不能省略行
int[][] array = new int[2][];//可以省略列
array[0] = new int[3];
array[1] = new int[7];
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.print(array[i][j]+" ");
}
System.out.println();
}
}