数组是一种容器,用来存储( 同种数据类型 )多个值
容器:是将多个数据存储到一起,每个数据称为该容器的元素
数组:数组就是存储数据 长度固定 的容器,保证多个数据的数据类型要一致
第一种格式(推荐):
数据类型[] 数组名;
int[] arr;
double[] arr;
char[] arr;
第二种格式:
数据类型 数组名[];
int arr[];
double arr[];
char arr[];
在创建数组时,直接将元素确定 ,系统还会自动计算出该数组的长度
完整版格式
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3...};
int[] arr = new int[]{1,2,3,4,5};
简化版格式
数据类型[] 数组名 = {元素1,元素2,元素3...};
int[] arr = {1,2,3,4,5};
❗️ 注意:
- 数组有 定长 特性,长度一旦指定,不可更改
- 什么类型的数组存放什么类型的数据,否则报错
数组动态初始化就是只给定数组的类型和长度,由系统给出默认初始化值,之后再存入具体数据
数据类型[] 数组名 = new 数据类型[数组长度];
int[] arr = new int[3];// 系统默认给出数组元素的初始值为0
System.out.println(arr); // [I@1b6d3586
❗️注意:
- 数组变量名中存储的是数组在内存中的地址,打印数组变量名时会输出数组的内存地址
- 例如:
[I@10f87f48
@
: 分隔符[
: 当前的空间是一个数组类型I
: 当前数组容器中所存储的数据类型10f87f48
: 十六进制内存地址
在初始化的时候,手动指定数组的长度,系统会为数组容器分配默认初始值:
❗️注意:
- 引用数据类型:引用、记录了地址值的变量,其所对应的数据类型就是引用数据类型。例如
int[] arr = new int[3];
- null,空值,引用数据类型的默认值,表示不指向任何有效对象。当
arr=null;
打印该数组名称会出现空指针异常。
索引: 每一个存储到数组的元素,都会自动的拥有一个编号,从0开始,这个自动编号称为数组索引 (index),可以通过数组的索引访问到数组中的元素。
数组名[索引]
数组的长度属性: 每个数组都具有长度,而且是固定的,Java中赋予了数组的一个属性,可以获取到数组的长度,
数组名.length
属性length
的执行结果是数组的长度,int
类型结果。由次可以推断出,数组的最大索引值为 数组名.length-1
。
内存是计算机中的重要原件,临时存储区域,作用是运行程序。
我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。
Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。
Java中的内存分配
❗️注意:
- 每
new
一次就会在堆中开辟出一片新的空间,堆内存的空间地址不会出现重复的现象。- 如果数组变量中没有存储数组的地址,而是
null
,如令arr=null;
在访问数组信息的时候会报空指针异常
数组遍历: 就是将数组中的每个元素分别获取出来,就是遍历。遍历也是数组操作中的基石。
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
键盘录入5个整数,存储到数组中,并对数组求和
import java.util.Scanner;
public class Test{
public static void main(String[] args) {
// 1.创建键盘录入对象,准备键盘录入
Scanner sc = new Scanner(System.in);
// 2.定义一个求和变量,准备记录累加后的结果
int sum = 0;
// 3.动态初始化一个长度为5的int数组,准备存储键盘录入的数值
int[] arr = new int[5];
// 4.将键盘录入的数值存储到数组中
for(int i = 0; i < arr.length; i++){
System.out.println("请输入第" + (i+1) + "个整数:");
//arr[i] = 10;
arr[i] = sc.nextInt();
}
// 5.遍历数组,取出每一个元素,并求和
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
// 6.输出总和
System.out.println("sum:" + sum);
}
}
最大值获取:从数组的所有元素中找出最大值
✨ 实现思路:
- 定义变量,保存数组0索引上的元素
- 遍历数组,获取出数组中的每个元素
- 将遍历到的元素和保存数组0索引上值的变量进行比较
- 如果数组元素的值大于了变量的值,变量记录住新的值
- 数组循环遍历结束,变量保存的就是数组中的最大值
public static void main(String[] args) {
int[] arr = {5, 15, 2000, 10000, 100, 4000};
//定义变量,保存数组中0索引的元素
int max = arr[0];
// 遍历数组,取出每个元素
for (int i = 1; i < arr.length; i++) {
//遍历到的元素和变量max比较
// 如果数组元素大于max
if (arr[i] > max) {
//max记录住大值
max = arr[i];
}
}
System.out.println("数组最大值是: " + max);
}
数组的反转: 数组中的元素颠倒顺序,例如原始数组为1,2,3,4,5
,反转后的数组为5,4,3,2,1
实现思想:数组最远端的元素互换位置。
- 实现反转,就需要将数组最远端元素位置交换
- 定义两个变量,保存数组的最小索引和最大索引
- 两个索引上的元素交换位置
- 最小索引++,最大索引–,再次交换位置
- 最小索引超过了最大索引,数组反转操作结束
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
/*循环中定义变量min=0最小索引 max=arr.length‐1最大索引 min++,max‐‐ */
for (int min = 0, max = arr.length-1; min < max; min++, max--) {
int temp = arr[min];
arr[min] = arr[max];
arr[max] = temp;
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
已知一个数组 arr = {19, 28, 37, 46, 50};
键盘录入一个数据,查找该数据在数组中的索引,并在控制台输出找到的索引值。
public static void main(String[] args) {
// 1.定义一个数组,用静态初始化完成数组元素的初始化
int[] arr = {19, 28, 37, 46, 50};
// 2.键盘录入要查找的数据,用一个变量接收
Scanner sc = new Scanner(System.in);
System.out.println("请输入您要查找的元素:");
int num = sc.nextInt();
// 3.定义一个索引变量,初始值为-1
// 假设要查找的数据, 在数组中就是不存在的
int index = -1;
// 4.遍历数组,获取到数组中的每一个元素
for (int i = 0; i < arr.length; i++) {
// 5.拿键盘录入的数据和数组中的每一个元素进行比较,如果值相同,就把该值对应的索引赋值给索引变量,并结束循环
if(num == arr[i]){
// 如果值相同,就把该值对应的索引赋值给索引变量,并结束循环
index = i;
break;
}
}
// 6.输出索引变量
System.out.println(index);
}
}
需求:在编程竞赛中,有6个评委为参赛的选手打分,分数为0-100的整数分。选手的最后得分为:去掉一个最高分和一个最低分后 的4个评委平均值 (不考虑小数部分)。
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
// 1.定义一个数组,用动态初始化完成数组元素的初始化,长度为6
int[] arr = new int[6];
// 2.键盘录入评委分数
Scanner sc = new Scanner(System.in);
// 3.由于是6个评委打分,所以,接收评委分数的操作,用循环
for (int i = 0; i < arr.length; i++) {
System.out.println("请输入第" + (i+1) + "个评委的打分:");
int score = sc.nextInt();
if(score >= 0 && score <= 100){
// 合法的分值
arr[i] = score;
}else{
// 非法的分值
System.out.println("您的打分输入有误, 请检查是否是0-100之间的");
i--; // 如果输入错误的数据,则会赋默认值0,接着输入下一个值,i--;意思是如果输入错误,就让再输入一遍
}
}
// 4.求出数组最大值
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if(max < arr[i]){
max = arr[i];
}
}
// 5.求出数组最小值
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if(min > arr[i]){
min = arr[i];
}
}
// 6.求出数组总和
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
// 7.按照计算规则进行计算得到平均分
int avg = (sum - max - min ) / 4;
// 8.输出平均分
System.out.println(avg);
}
}
进一步的数据相关操作:
- 数组排序技术
- 冒泡排序
- 选择排序
- 快速排序
- 插入排序
- ……
- 数组搜索技术
- 二分查找
- 分块查找
- 哈希表查找
- ……
可参考 Java SE 学习笔记(十二)—— 数据结构与算法
二维数组也是一种容器,不同于一维数组,该容器存储的都是一维数组容器
第一种格式(推荐):
数据类型[][] 变量名;
int[][] arr;
第二种格式:
数据类型 变量名[][];
int arr[][];
第三种格式:
数据类型[] 变量名[];
int[] arr[];
数据类型[][] 变量名 = new 数据类型[m][n];
// m表示这个二维数据可以存放多少个一维数组
// n表示每一个一维数组可以存放多少个元素
int[][] arr = new int[2][3];
注意: 二维数组中存储的是一维数组的 内存地址
问:二维数组中存储的是一维数组, 那能不能存入 【提前创建好的一维数组】呢 ?
答 : 可以的
public static void main(String[] args) {
int[] arr1 = {11,22,33};
int[] arr2 = {44,55,66};
int[] arr3 = {77,88,99,100};
int[][] arr = new int[3][3];
// arr[2][3] = 100; 索引越界,会报错!
arr[0] = arr1;
arr[1] = arr2;
arr[2] = arr3;
System.out.println(arr[1][2]); // 66
System.out.println(arr[2][3]); // 100 索引好像是“越界”,但不会报错!
}
问:为什么提前创建好一维数组去访问不会报错,而直接访问数组存入数据却会报错?
这种动态初始化在创建时就会把这三个一维数组创建好,并且里面的索引也是固定的,用 arr[0][3]
去访问一个不存在的索引必然会报错。
提前创建一维数组再往里面赋值的方式,只是做了 内存地址的替换,跟原来一维数组的长度已经没有关系了。
完整格式
数据类型[][] 变量名 = new 数据类型[][]{ {元素1, 元素2...} , {元素1, 元素2...};
简化格式
数据类型[][] 变量名 = { {元素1, 元素2...} , {元素1, 元素2...} ...};
(1)数组的遍历
public static void main(String[] args) {
int[][] arr = {{11, 22, 33}, {33, 44, 55}};
// 1. 遍历二维数组,取出里面每一个一维数组
for (int i = 0; i < arr.length; i++) {
//System.out.println(arr[i]);
// 2. 在遍历的过程中,对每一个一维数组继续完成遍历,获取内部存储的每一个元素
//int[] temp = arr[i];
for (int j = 0; j < arr[i].length; j++) {
System.out.println(arr[i][j]);
}
}
}
(2)数组元素求和
public static void main(String[] args) {
// 1. 定义求和变量,准备记录最终累加结果
int sum = 0;
// 2. 使用二维数组来存储数据,再将4个一维数组装起来
int[][] arr = { {22,66,44} , {77,33,88} , {25,45,65} , {11,66,99}};
// 3. 遍历二维数组,获取所有元素,累加求和
for (int i = 0; i < arr.length; i++) {
for(int j = 0; j < arr[i].length; j++){
sum += arr[i][j];
}
}
// 4. 输出最终结果
System.out.println(sum); // 641
}
Arrays类是操作数组的工具类,包含用来操作数组的各种方法,比如排序和搜索等。其所有方法均为静态方法,调用起来非常简单。
常用方法如下:
举个栗子:
public static void main(String[] args) {
int[] intArray = {10, 20, 30};
// 将int[]数组按照默认格式变成字符串
String intStr = Arrays.toString(intArray);
System.out.println(intStr); // [10, 20, 30]
// 排序
int[] array1 = {2, 1, 3, 10, 6};
Arrays.sort(array1); // 底层使用快速排序算法
System.out.println(array1); // [I@1b6d3586
System.out.println(Arrays.toString(array1)); // [1, 2, 3, 6, 10]
String[] array2 = {"bbb", "aaa", "ccc"};
Arrays.sort(array2);
System.out.println(array2); // [Ljava.lang.String;@4554617c
System.out.println(Arrays.toString(array2)); // [aaa, bbb, ccc]
// 二分搜索
int [] arr = {1,2,3,4,5,6,7,8,9,10};
int index = Arrays.binarySearch(arr, 0);
System.out.println(index);
//1,数组必须有序
//2.如果要查找的元素存在,那么返回的是这个元素实际的索引
//3.如果要查找的元素不存在,那么返回的是 (-插入点索引-1)
//插入点索引:如果这个元素在数组中,他应该在哪个索引上.
❗️ 注意:
- 如果是数值,
sort
默认按照升序从小到大- 如果是字符串,
sort
默认按照字母升序
案例:倒序打印字符串
请使用 Arrays 相关的API,将一个随机字符串中的所有字符升序排列,并倒序打印。
public static void main(String[] args) {
String str = "asv76agfjh";
// 如何进行升序排列:sort
// 必须是一个数组,才能用Arrays.sort方法
// String --> 数组,用toCharArray
char[] chars = str.toCharArray();
Arrays.sort(chars); // 对字符数组进行升序排列
// 需要倒序遍历
for (int i = chars.length - 1; i >= 0; i--) {
System.out.print(chars[i]+" "); // v s j h g f a a 7 6
}
}
Arrays
类对于 Comparator
比较器的支持
自定义排序规则
Comparator
接口对应的比较器对象,来定制比较规则
举个栗子:
import java.util.Arrays;
import java.util.Comparator;
public class Demo {
public static void main(String[] args) {
// Arrays的sort方法对于有值特性的数组默认是升序排序
int [] arr = {9,2,31,4,5,16,7,10};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); // [2, 4, 5, 7, 9, 10, 16, 31]
// 现在需要对arr降序排序(自定义比较器对象,只能支持应用类型的排序)
Integer[] arr1= {9,2,31,4,5,16,7,10};
Arrays.sort(arr1, new Comparator<Integer>() {
/**
* 参数一:被排序的数组,必须是引用类型的元素
* 参数二:匿名内部类对象,代表了一个比较器对象
*/
@Override
public int compare(Integer o1, Integer o2) {
// 制定比较规则(默认升序)
// 方式1
// if(o1>o2){
// return 1;
// } else if (o1
// return -1;
// }
// return 0;
// 方式2
// return o1-o2;
// 改成降序
return o2-o1;
}
});
System.out.println(Arrays.toString(arr1)); // [31, 16, 10, 9, 7, 5, 4, 2]
}
}
对于自定义对象的排序
Student类
public class Student {
private String name;
private int age;
private double height;
public Student() {
}
public Student(String name, int age, double height) {
this.name = name;
this.age = age;
this.height = height;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
'}';
}
}
Demo类
import java.util.Arrays;
import java.util.Comparator;
public class Demo {
public static void main(String[] args) {
Student s1 = new Student("张三", 26, 173.2);
Student s2 = new Student("李四", 19, 163.9);
Student s3 = new Student("王五", 23, 183.9);
Student[] ss = new Student[3];
ss[0] = s1;
ss[1] = s2;
ss[2] = s3;
System.out.println(Arrays.toString(ss)); // 记得重写Student类中的toString方法
// Arrays.sort(ss); // 直接报错,Java不知道按照什么规则排序
Arrays.sort(ss, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// 整型比较
// return o1.getAge()-o2.getAge(); // 按照年龄升序排序
// return o2.getAge()-o1.getAge(); // 按照年龄降序排序
// 浮点型比较
// return Double.compare(o1.getHeight(),o2.getHeight());// 按照身高升序排序
return Double.compare(o2.getHeight(),o1.getHeight());// 按照身高降序排序
}
});
System.out.println(Arrays.toString(ss));
}
}