数组
1、概念:数组就是一个能放相同数据类型的有序集合(容器)
一、 数组创建
1、创建动态数组:
**语法一:**数据类型[] 数组名 = new 数据类型[数组长度];(建议使用第一种)
**语法二:**数据类型 数组名[] = new 数据类型[数组长度];
例如:
public static void main(String[] args) {
// 创建5个空间的int类型数组
int[] arr1 = new int[5];
// 创建6个空间的String类型数组
String[] arr2 = new String[6];
}
2、静态创建数组
**语法一:**数据类型[] 数组名 = new 数据类型[] {元素1,元素2,元素3,…}
**语法二:**数据类型[] 数组名 = {元素1,元素2,元素3,…}
**注意:**静态创建数组,数组的长度由元素个数来确定。
例如:
public static void main(String[] args) {
// 创建指定内容的int类型数组
int[] arr1 = new int[]{1, 2, 3, 4, 5};
// 创建指定内容的String类型数组
String[] arr2 = {"11", "22", "33", "44"};
}
注意:
1、数组类型可以是任何数据类型。
2、数组中存放的元素类型必须与创建数组时指定的数据类型保持一致。(目前所学范围)
3、创建一个数组时,必须指定数组的长度,创建成功后,数组长度大小是不可以改变的。
3、数组的基本操作
通过数组的索引或者下标来操作数组的元素。
索引的取值范围:[0,数组长度-1],如果超出了索引范围来操作数组元素,会抛出java.lang.ArrayIndexOutOfBoundsException异常。
数组能够实现快速寻址,使用“修改”和”查询“的效率非常高。
快速寻址公式:首地址 + 索引值 * 存储元素占用的字节数。
数组赋值操作:
public static void main(String[] args) {
// 初始化5个空间的int类型数组
int[] arr = new int[5];
// 添加元素
arr[0] = 11; // 给第一个元素赋值
arr[1] = 22; // 给第二个元素赋值
arr[2] = 22; // 给第三个元素赋值
// 修改第二个元素的值
arr[1] = 222;
}
数组取值操作:
public static void main(String[] args) {
// 创建指定内容的int类型数组
int[] arr = {1, 2, 3, 4, 5};
// 获取元素
int num1 = arr[0]; // 获取第一个元素
int num2 = arr[1]; // 获取第二个元素
int num3 = arr[2]; // 获取第三个元素
}
获取数组长度操作:
public static void main(String[] args) {
// 创建指定内容的int类型数组
int[] arr = {1, 2, 3, 4, 5};
// 通过length属性,来获取数组的长度
System.out.println(arr.length); // 输出:5
}
数组插入一个值:(效率非常低)
// 在数组{5, 12, 90, 18, 77, 76, 45, 28, 59, 72}索引为2的位置插入元素222,插入后:{5, 12, 222, 90, 18, 77, 76, 45, 28, 59, 72}。
/**
* 实现数组中插入一个元素
* @param arr 指定的数组
* @param index 指定的索引值
* @param value 插入元素的值
* @return 插入后的数组
*/
public static int[] insertArray(int[] arr,int index,int value) {
// 判断索引是否合法
if (index < 0 || index >= arr.length) {
System.out.println("索引不合法,抛出一个异常");
throw new IndexOutOfBoundsException();// 抛出索引异常
}
// 实际存放元素的个数
int size = arr.length;
if (size == arr.length) {// 证明需要扩容
// 定义一个扩容后的数组
int[] newArr =new int [arr.length+1];
// 把原数组的值拷贝到新数组中
for (int i = 0; i < arr.length; i++) {
newArr[i] = arr[i];
}
//
arr = newArr;// arr指向新创建出来数组的首地址
// 新数组中指定索引后的所有元素往后移动一位
for (int i = arr.length-2; i>=index; i--) {
arr[i+1]=arr[i];
}
}
arr[index] = value;// 插入索引位置进行赋值操作
return arr;
}
public static void main(String[] args) {
int[] arr = {5, 12, 90, 18, 77, 76, 45, 28, 59, 72};
int index = 2;
int value =222;
int[] newArr = insertArray(arr, index, value);
for (int i : newArr) {
System.out.print(i+" ");
}
}
数组删除一个值:(效率非常低)
// {5, 12, 90, 18, 77, 76, 45, 28, 59, 72}索引为2的元素,删除后:{5, 12, 18, 77, 76, 45, 28, 59, 72,0}。
/**
* 删除数组指定索引的元素
* @param arr 指定的数组
* @param index 指定的索引
*/
public static void deleArray(int[] arr,int index) {
// 判断传入的索引值是否合法
if (index <0 || index >=arr.length) {
System.out.println("超出索引值范围,抛出一个异常");
throw new IndexOutOfBoundsException();
}
// 运用循环把指定索引值元素后面的所有元素向前移动一位
for (int i = index; i < arr.length-1; i++) {
arr[i] = arr[i + 1];
}
// 把移动之后最后一位值赋值为0
arr[arr.length-1] = 0;
}
public static void main(String[] args) {
int[] arr = {5, 12, 90, 18, 77, 76, 45, 28, 59, 72};
int index = 2;
deleArray(arr, index);
for (int i : arr) {
System.out.print(i+" ");
}
}
4、数组的默认值
1、整数类型(byte、short、int、long)的基本类型变量的默认值为0。
2、浮点型(float、double)的基本类型变量的默认值为0.0。
3、字符型(char)的基本类型变量的默认为 “/u0000”。
4、布尔性的基本类型变量的默认值为 false。
5、引用类型的变量是默认值为 null(null就是空对象)。
5、通过循环来遍历数组
1、通过for循环来获取数组的值
int[] arr = {11, 22, 33, 44, 55, 66, 77};
for(int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
1、通过for-each循环来获取数组的值
语法:for(数据类型 变量名 : 数组|集合) {
// 循环体
}
优点:语法简洁,相对执行效率较高!
缺点:遍历过程中,无法获得数组或集合索引!
例如:
int[] arr = {11, 22, 33, 44, 55, 66, 77};
for(int element : arr) {
System.out.println(element);
}
二、二维数组
1、什么是二维数组?
二维数组中的每个元素就是一个数组。
2、二维数组的声明:
语法1:数据类型[][] 变量名; (建议使用)
语法2:数据类型[] 变量名[]; (不建议使用)
3、二维数组的创建
3.1创建等长的二维数组
语法:数据类型[][] 变量名 = new 数据类型[m][n];
m:代表二维数组的空间长度
n:代表二维数组中每个元素(一维数组)的空间长度
例如:
int[][] arr = new int[3][2];
3.2创建不等长的二维数组
语法:数据类型[][] 变量名 = new 数据类型[m][];
m:代表二维数组的空间长度
例如:
int[][] arr = new int[3][];
3.3通过静态的方式创建二维数组
语法1:数据类型[][] 变量名 = new int[][]{{数据1, 数据2, …}, {数据1, 数据2, …}, {数据1, 数据2, …}, …}
例如:
int[][] arr = new int[][]{{10, 11, 12}, {20, 21}, {30, 31, 31, 33}};
语法2:数据类型[][] 变量名 = {{数据1, 数据2, …}, {数据1, 数据2, …}, {数据1, 数据2, …}, …}
例如:
int[][] arr = {{10, 11, 12}, {20, 21}, {30, 31, 31, 33}};
**应用:**例题:有三个班级,第一个班级3个学生,第二个班级4个学生,第三个班级5个学生。要求通过键盘录入三个班级学生的成绩,并计算每个班级学生的的平均成绩和三个班级学生的总均成绩。
double[][] arr = new double[3][];
arr[0] = new double[3];// 用来保存第一个班三个学生成绩
arr[1] = new double[4];// 用来保存第二个班四个学生成绩
arr[2] = new double[5];// 用来保存第三个班五个学生成绩
Scanner input = new Scanner(System.in);
double sum = 0;// 用来保存总成绩
for (int i = 0; i < arr.length; i++) {
double num = 0;// 保存每个班的总成绩
for (int j = 0; j < arr[i].length; j++) {
System.out.println("请输入"+(i+1)+"班,第"+(j+1)+"个同学的成绩:");
double score = input.nextDouble();
arr[i][j]=score;// 循环录入学生成绩
num +=arr[i][j]; // 每个班的总成绩
}
sum+=num;
System.out.println((i+1)+"班平均成绩:"+(num/arr[i].length));
}
System.out.println("总成绩:"+sum);
1.栈内存
存放:局部变量(基本数据类型数据和引用数据类型的首地址)
特点:
a)栈内存特点:先进后出、后进先出
b)栈内存是一块连续的内存中间,由系统分配,速度快!
c)每个线程都有自己对应的栈内存,不同线程的数据不会相干扰!
d)栈内存有系统自己管理,无需程序员手动管理内存。
2.堆内存
存放:new出来的对象和数组
特点:
a)堆内存不连续的内存空间,分配灵活,速度慢。
b)一个进程中共享同一份堆内存,每个线程公用一个堆内存!
c)堆内存本质上需要程序员来手动管理内存,但是java有垃圾回收机制来帮程序管理内存。
例题:
int[] arr1 = {1, 2, 3, 4, 5};
int[] arr2 = arr1;
arr2[2] = 33;
System.out.println(arr1[2]); // 输出结果为???
int[] arr1 = {1, 2, 3};
int[] arr2 = arr1;
arr1 = null;
// System.out.println(arr1[2]); // 输出结果为???抛出了空指针异常,java.lang.NullPointerException
System.out.println(arr2[2]); // 输出结果为??? 3
Arrays工具类
用的时候需要调用java.util.Arrays工具类。
常见的方法介绍:
**1、sort:**实现对元素的排序(默认升序)
用法:
int[] arr = {3, 5, 1, 7, 6, 2, 4};
Arrays.sort(arr);// 调用 Arrays工具类
System.out.println("升序排序:");
for(int element : arr) {
System.out.print(element + " ");// 1 2 3 4 5 6 7
}
**2、binarySearch:**二分查找法,使用前提数组必须是有序的。
用法:
int[] arr = {3, 5, 1, 7, 6, 2, 4};
System.out.println("折半查找:");
int index = Arrays.binarySearch(arr, 5);
System.out.println("索引:" + index);// 1
**3、toString:**把数组中的元素转化为字符串输出!
用法:
int[] arr1 = {3, 5, 1, 7, 6, 2, 4};
System.out.println(Arrays.toString(arr1));// [3, 5, 1, 7, 6, 2, 4]
**4、equals:**判断两个数组中的元素是否相同
用法:
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3, 4};
System.out.println(Arrays.equals(arr1, arr2));// false
**5、copyOfRange:**拷贝数组中的元素,从指定位置开始,到指定位置结束。
用法:
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
// 第一个参数:被拷贝的数组,第二个参数:开始拷贝的起始位置(包含本身),第三个参数:拷贝结束的终点(不包含本身)
int[] copyArr = Arrays.copyOfRange(arr, 2, 5);
System.out.println(Arrays.toString(copyArr));// [3,4,5]
System类中的arraycopy方法
作用:就是用于实现数组元素的拷贝工作。
源码:
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
参数分析:
src:需要被拷贝的数组(源数组)。
srcPos:源数组开始拷贝的起点位置,传递的是一个索引。
dest:目标数组,放入拷贝元素的数组。
destPos:拷贝元素放在目标数组中位置,也是传递索引。
length:拷贝数组元素的个数。
用法:
int[] src = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int[] dest = new int[3];
// 完成拷贝之后,dest数组中的元素为:{3, 4, 5}
System.arraycopy(src, 2, dest, 0, 3);
System.out.println(Arrays.toString(dest));
(源数组)。
srcPos:源数组开始拷贝的起点位置,传递的是一个索引。
dest:目标数组,放入拷贝元素的数组。
destPos:拷贝元素放在目标数组中位置,也是传递索引。
length:拷贝数组元素的个数。
用法:
```java
int[] src = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int[] dest = new int[3];
// 完成拷贝之后,dest数组中的元素为:{3, 4, 5}
System.arraycopy(src, 2, dest, 0, 3);
System.out.println(Arrays.toString(dest));