Java入门day 04 - 数组
1. 数组
1.1 JVM内存模型
- 方法区: 线程共享的内存区域 , 存储被虚拟机加载的类信息、常量、静态变量被编译器编译后的代码数据等
- 栈: Java虚拟机栈 , 每个方法被运行的时候都会同时创建一个栈帧用于存储该方法的局部变量 、操作栈、动态链接、方法出口等信息. 每调用一个方法就创建一个栈帧 , 存放当前方法的局部变量 , 当方法调用完以后 , 该方法对应的栈帧也被销毁了.
- 堆:Java堆: 被所有线程共享的一块内存区域 , 在虚拟机启动时创建. 所有的对象实例以及数组都要在堆上分配.每使用一次new关键字 , 就在内存创建一个新的内存空间.
1.2 数组定义
- 数组的定义: 数组是把多个相同类型的常量有序(按索引顺序)的组织在一起的数据形式.
- 数组元素: 数组中的每一个常量值.
- 数组索引:数组中用来表示存放的元素的位置.索引从0开始.
1.2.1 数组定义语法
- 语法: 数组元素类型[] 数组名;
比如: int[ ] array;
可以把int[ ]看成是一种数据类型----int类型的数组类型.
1.3 数组初始化
数组在定义以后必须初始化以后才能使用.初始化:在堆内存中分配一个存储空间给数组,并为每一个元素赋值.
数组初始化的两种方式:
1.静态数组初始化
2.动态数组初始化
注意:数组一旦初始化完成,他的数组长度就固定了,不能改变,除非重新对数组初始化
1.3.1 静态数组初始化
-
语法: 数组元素类型[ ] 数组名 = new 数组元素类型[ ]{元素1,元素2,… };
简单写法: 数组元素类型[ ] 数组名 = {元素1,元素2,… };
//需求:定义数组和数组的静态初始化操作
public class ArrayDemo1 {
public static void main(String[] args) {
//先定义后初始化数组
int[] array = new int[]{1, 2, 3, 4, 5};
//打印数组长度
System.out.println("array长度=" + array.length);
//array = null;//数组赋值为空,并演示空指针错误
//重新初始化数组,给数组赋值
array = new int[]{9, 8, 7};
System.out.println("array长度=" + array.length);
}
}
- 注意点:如果存在一行代码,如下:
nums = null;
null表示不再引用堆中的内存空间,那么此时nums就好比是没有初始化的,不能使用。
1.3.2 静态数组初始化内存分析
1.3.3 动态数组初始化
-
语法:数组元素类型[ ] 数组名 = new 数组元素类型[length];
length: 数组要存多少个元素即数组长度.
//需求:数组的动态初始化
public class ArrayDemo2 {
/*
步骤:
(1)动态初始化数组,并打印数组长度
(2)重新初始化数组,并打印数组长度
*/
public static void main(String[] args) {
//动态初始化数组,并打印数组长度
int[] array = new int[5];
System.out.println("array长度=" + array.length);
//重新初始化数组,并打印数组长度
array = new int[2];
System.out.println("array长度=" + array.length);
}
}
- 不同数据类型的初始值:
1.3.4动态数组初始化内存分析
1.4 数组的操作
1.4.1 数组的基本操作
-
获取数组长度 , 语法: 元素类型 变量名 = 数组名.length;
-
获取元素值 , 语法: 元素类型 变量名 = 数组名[索引];
注意: 索引都是从0开始 , 最大索引是数组长度-1 , 所以索引范围是[0 , 数组名.length - 1].
-
设置元素值 , 语法: 数组名[索引] = 值;
-
遍历数组: 获取出数组中每一个元素
-
for - each (增强for循环)操作数组
//需求:数组的基本操作
public class ArrayDemo3 {
/*
步骤:
(1)定义一个数组nums,并静态初始化该数组
(2)定义一个变量size获取nums的数组长度
(3)获取数组元素
(4)设置数组元素
(5)遍历数组
(6)for -each
*/
public static void main(String[] args) {
//定义一个数组nums,并静态初始化该数组
int[] nums = new int[]{2, 3, 4};
System.out.println("size长度=" + nums.length);
System.out.println("-----------------------");
//获取数组元素
int size;
size = nums[0];
size = nums[1];
size = nums[2];
System.out.println("-----------------------");
//设置数组元素
nums[1] = 30;
System.out.println(nums[1]);
System.out.println("-----------------------");
//遍历数组
for (int i = 0; i < nums.length; i++) {
size = nums[i];
System.out.println(size);
}
System.out.println("-----------------------");
//for - each
for (int ele : nums){
System.out.println(ele);
}
}
}
-
在操作中常见的2个问题:
1. NullPointerException: 空指针异常: 操作了一个尚未初始化或者没有分配内存空间的数组. 2. ArrayIndexOutOfBoundsException:数组的索引越界异常操作的数组的索引不在[0,数组名.length-1]范围内.
1.4.2 循环操作数组
需求1:找出数组中元素22第一次出现的索引位置
//需求1:找出数组中元素22第一次出现的索引位置
public class ArrayDemo4{
public static void main(String[] args){
//定义一个数组nums,并初始化该数组
int[] nums = {11,22,33,44,55,22};
//定义一个变量key,表示被搜索的元素
int key = 22;
//遍历数组
for(int i = 0;i < nums.length;i++){
//判断如果当前元素和key相等,证明找到元素,打印并结束循环
if(key == nums[i]){
System.out.println(nums[i]);
System.out.println(i);
break;
}
}
}
}
需求2:求出int类型数组中最大元素值
//需求:求出int类型数组中最大元素值
public class ArrayDemo5{
public static void main(String[] args){
//定义并初始化数组nums
int[] nums = {11,22,33,44,55};
//定义一个变量max表示最大的元素,并假设nums的第一个元素为最大值
int max = nums[0];
//使用foreach循环遍历nums数组
for(int ele:nums){
//判断如果遍历的元素和max比较,遍历的元素比较大,就将当前元素赋值给max
if(max < ele){
max = ele;
}
}
//遍历完成打印max
System.out.println(max);
}
}
需求3:按照某种格式打印数组元素,数组元素放在方括号[]中,相邻元素使用逗号分隔开。如上述数组打印出来,效果如:[11, 22, 33, 44, 22, 55]
//需求:按照某种格式来打印出数组中的元素,打印效果为:[11,22,33,44,22,55]
public class ArrayDemo6{
public static void main(String[] args) {
//定义并初始化数组nums
int[] nums = {11, 22, 33, 44, 55};
//定义一个字符串类型的变量str,用于拼接字符串
String str = "[";
//遍历数组并拼接元素到str
for (int i = 0; i < nums.length; i++) {
str = str + nums[i];
//判断是否是最后一个元素如果不是拼接",",否则拼接"]"
if (i <= nums.length - 1) {
str = str + ",";
} else {
str = str + "]";
}
}
//打印str
System.out.println(str);
}
}
1.5 二维数组
二维数组, 就是数组中的每一个元素是另一个一维数组.
二维数组数组初始化的两种方式:
1.静态二维数组初始化
2.动态二维数组初始化
1.5.1 静态初始化二维数组
-
静态初始化二维数组的语法:
数组元素类型[][] 数组名 = new 数组元素类型[][]{数组1,数组2,数组 3,…};
-
注意: 二维数组中的元素类型是一维数组, 把数组元素类型[ ]看成一个整体 表示数据类型.
1.5.2 动态初始化二维数组
-
定义和动态初始化二维数组的语法:
数组元素类型[][] 数组名 = new 数组元素类型[ x ] [ y ];
x: 表示二维数组中有几个一维数组.
y: 表示每一个一维数组中有几个元素.
1.5.3 获取二维数组的元素
-
方法: 因为二维数组表示数组的中的数组, 如果要获取数组的每
一个元素值, 则需要两个循环嵌套.
1.5.4 演示二维数组的基本操作
//需求:演示二维数组的基本操作
public class ArrayInArrayDemo {
/*
步骤:
(1)定义一个二维数组
(2)静态初始化二维数组
(3)动态初始化二维数组
(4)获取二维数组的元素
(5)设置二维数组的元素
(6)for循环遍历并打印二维数组的元素
(7)foreach循环遍历并打印二维数组的元素
*/
public static void main(String[] args) {
//定义一个二维数组
int[] array1 = {1, 2, 3};
int[] array2 = {4, 5, 6};
//静态初始化二维数组
int[][] arrays = new int[][]{array1, array2};
//输出二维数组中的第一个一维数组的第一个元素
System.out.println(arrays[0][1]);
System.out.println("--------------");
//动态初始化二维数组
int[][] arrays2 = new int[3][5];
//for循环遍历并打印二维数组的元素
for (int i = 0; i < arrays.length; i++) {
int[] a = arrays[i];
for (int j = 0; j < a.length; j++) {
int ele = a[j];
System.out.println(ele);
}
}
System.out.println("--------------");
//foreach循环遍历并打印二维数组的元素
for (int[] i : arrays) {
for (int ele : i) {
System.out.println(ele);
}
}
}
}
2.总结
1. JVM中的内存区域
- 方法区: 线存共享的内存区域, 存储已被虚拟机加载的类信息、常量、静态变量即时编译器编译后的代码数据等.
- 栈: 每个方法被执行时都会创建一个栈帧用于存储该方法的局部变量、操作栈、动态链接、方法出口等信息.
- 堆: 被所有线程共享的一块内存区域, 在虚拟机启动时创建. 所有的对象实例已经数组都要在堆上分配.
- GC(垃圾回收器): Java的自动垃圾回收机制,当JVM虚拟机内存不够用时, 会自动清理掉堆中无用对象.
数组的作用
同类型: 元素的类型都是相同,比如:int就都是int,String就都是String
多个: 有很多的类型相同的元素.
有序: 索引: 按一定顺序排列的多个元素, 从0开始, 依次加1.
数组的定义语法
元素类型[] 变量名; int [ ] nums ;
元素类型 变量名[];(不推荐) int nums [ ];
不推荐的原因:把[ ] 放在后面有时候会省略掉忘记是个数组.
数组的初始化
静态初始化:当明确添加到数组的元素时
动态初始化:当明确数组元素的个数,但是不明确具体的元素时
语法:
new 元素类型[]{元素1,元素2,}//静态
int[ ] nums = new int[ ]{1,2,3,4 };
简单写法: int[ ] nums = {1,2,3,4};
new 元素类型[长度];//动态 int[ ] nums = new int[ 5 ];
数组的元素的操作
如何获取元素的个数
语法: 元素类型 变量名 = 数组名.length;
int size = array.length;
如何获取数组中的元素
语法: 元素类型 变量名 = 数组名[index]; index: 是索引
int nums = array[0];
注意事项: 索引越界:索引范围正常在[0, 数组名.length -1]
如何为数组中的指定索引位置设值
语法: 数组名[index] = 值; index: 是索引
array[ 0 ] = 20;
注意事项: 索引越界: 索引范围正常在[0, 数组名.length -1]
操作数组过程中可能存在的问题和原因
数组索引越界异常: 数组的索引越界异: 操作的数组的索引不在[0,数组名.length-1]范围内.
空指针异常: 当访问一个空引用变量中的成员时会发生空指针异常
int[] nums = null;//null表示空引用
int size = nums.length;//发生空指针异常
//排除空指针异常的最好的方式,做非空判断
if(nums != null) {
int size = nums.length;
}