Java数组的目录
- ⛳ Java数组
- 🎨 一,一维数组
- 👣 1.1,概念
- 📢 1.2,基本用法
- 1,语法格式
- 2,代码
- 💻 1.3,内存结构
- 📝 1.4,练习
- 🎁 二,二维数组
- 🏭 2.1,概念
- 1,语法格式
- 格式1:
- 格式2:
- 格式3:
- 🐾 2.2,二维数组的使用
- 🎉 2.3,内存结构
- 🏭 三,数组中常见的算法
- 📐 3.1,二分查找
- 💬 3.2,排序算法
- 💖 3.3,冒泡排序
- 🚜 3.4,Arrays工具类
⛳ Java数组
数组是一种数组结构,用于存储相同类型的多个元素。它提供了一个连续的内存块,用于存储数组元素。
数组的特点和数组结构:
- 连续内存:Java数组的元素在内存中是连续存储的。这意味着数组的每个元素在内存中占据相同大小的空间,并且可以通过索引进行快速访问。
- 零基索引:Java数组的索引是从0开始,即第一个元素的索引为0,第二次元素的索引为1,以此类推。通过索引,可以访问数组中的特定元素。
- 固定长度:在创建数组是,需要指定数组的长度。数组的长度在创建后是固定不变的,不饿能动态改变。如果需要存储更多或更少的元素,需要创建一个新的数组。
- 同一类型元素:Java数组要求所有元素具有相同的数据类型。例如,一个整数数组只能存储整数类型的元素。
- 随机访问:由于数组的元素在内存中连续存储,并且可以通过索引进行访问,所以可以在O(1)的时间复杂度内随机访问数组中的元素。
- 长度属性:每个Java数组都有一个
length
属性,用于表示数组的长度,即数组中元素的数量。这个属性实在拆高纳进数组时自动生成的,并且在数组的整个生命周期中保持不变。length
是一个存储在数组中的常量。总的来说,Java数组是一种简单而有效的数据结构,用于存储和访问多个相同类型的元素。它提供了快速的随机访问和固定长度的特性。然而,由于数组长度固定且连续存储,插入和删除操作相对较慢,需要重新分配内存和复制元素。如果需要频繁进行插入和删除操作,需要考虑其他数据结构,如ArrayList或LinkedList。
🎨 一,一维数组
👣 1.1,概念
数组(Array),是多个相同类型数据按一定顺序排列的集合, 并使用一-个名字命名,并通过编号的方式对这些数据进行统一管理。
变量:在内存中开辟一块空间。
数组:也是变量,在内存中开辟遗传连续的内存空间。数组长度一旦确定,就不能修改。
拓展:
- 局部变量
- 基本数据类型
- 如:int i = 1; char a = ‘a’; 存储在栈里边。
- 引用数据类型
- 如: int[] arr = new int[4]; 引用变量arr存储在栈里面,引用的对象存储在堆里面。
- 基本数据类型
数组的常见概念:
-
数组名
-
下标(或索引)
-
元素
-
数组的长度
📢 1.2,基本用法
1,语法格式
-
格式1:数据类型[]数组名,属于只创建了数组引用名,并未在内存创建数组空间
int[] arr1; //声明 arr1 = new int[4]; // 数组长度一旦确定,不可改变
-
格式2:数据类型[]数组名称= new数据类型[数组长度];
double[] arr2 = new double[5];
-
格式3:数据类型[]数组名称= {数组内容1,数组内容2,数组内容3…数组内容n};
int[] arr3 = {1,2,3,4};
-
格式4:数据类型[]数组名称= new数据类型[]{内容1,内容2,内容…内容n}
int[] arr4 = new int[]{1,2,3,4};
2,代码
public static void main(String[] args) {
// 1,声明数组
// 1.1,先声明,后开辟空间:数据类型 [] 数组名称;
int[] arr1; //声明
arr1 = new int[4]; // 开辟空间 , 数组长度一旦确定,不可以改变
// 1.2 声明数组的同时开辟空间
double[] arr2 = new double[5];
System.out.println(arr1);
System.out.println(arr2);
// 1.3 声明数组
String[] arr3; // 只有声明,没有在内存中开辟数组空间
// System.out.println(arr3);
// 1.4 声明数组的同时赋值
int[] arr4 = new int[]{1,2,3,4};
System.out.println(arr4);
// 1.5 声明数组的同时赋值
// 此时数组的长度由赋值的个数决定
double[] arr5 = {1,2,34,5,7};
}
💻 1.3,内存结构
JMM : JVM的内存结构
int[] arr1; 的内存状态
arr1 = new int[4]; 的内存状态
下列代码的内存结构
int[] arr1 = new int[5];
arr1[0] = 10;
arr1[2] = 20;
String[] arr2 = new String[3];
arr2[1] = "刘杰";
arr2 = new String[5];
拓展:
JMM(Java内存模型)是Java平台定义的一种规范,用于描述多线程并发访问共享内存时的行为。JMM定义了线程如何与主内存和工作内存进行交互,以及如何同步和协调共享数据的访问。
以下是JMM的一些关键概念:
- 主内存(Main Memory):主内存是Java程序中所有线程共享的内存区域。所有变量(包括实例变量,静态变量和数组元素)都是存储在主内存中。
- 工作区域(Working Memory):工作内存是每个线程独立拥有的内存区域。线程的工作内存包含了主内存中的部分变量副本,用于线程的实际操作和计算。
- 内存间的交互:线程对共享变量的操作必须在主内存和工作内存之间进行交互。当一个线程需要使用共享变量时,它首先将变量从内存复制到自己的工作内存中。在工作内存中对变量进行操作后,线程可以选择将变量的最新值刷新回主内存。
- 原子性,可见性和有序性:JMM定义了操作的原子性,可见性,有序性的规则。原子性指一个操作时不可分割的,要么全部执行成功,要么不执行。可见性指一个线程对共享变量的修改对其他线程是可见的。有序性指程序的执行循序必须符合一定的规则,不能出现乱序执行的情况。
- 同步操作:JMM提供了一些同步操作来确保线程之间的协调和共享数据的一致性,如synchronize关键字,volatile关键字,Lock接口等。
JMM的目标是提供一个统一的内存模型,使得程序在不同的平台和编译器上都能以一致的方式工作。通过JMM的规范,开发则可以编写正确且线程安全的多线程程序。了解JMM的规则和特性对于编写高效且正确的多线程代码非常重要。
📝 1.4,练习
从键盘读入学生成绩,找出最高分,并输出学生成绩等级。
- 成绩>=最高分-10等级为’A’
成绩>=最高分20等级为’B’
成绩>=最高分30等级为C’
其余等级为’D’
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入学生人数:");
int persons = scanner.nextInt();
int[] scores = new int[persons];
System.out.println("请输入" + persons + "个学生的分数");
// 定义一个最大值变量
int maxScore = 0;
for (int i = 0; i < scores.length; i++) {
scores[i] = scanner.nextInt();
if (scores[i] > maxScore){
maxScore = scores[i];
}
}
System.out.println("分数的最大值为:" + maxScore);
for (int i = 0; i < scores.length; i++) {
// switch (scores[i]){
// case scores[i] > maxScore - 10 :
//
// }
if (scores[i] >= maxScore - 10){
System.out.println("分数为" + scores[i] + "的等级为A");
} else if (scores[i] >= maxScore - 20) {
System.out.println("分数为" + scores[i] + "的等级为B");
}else if (scores[i] >= maxScore - 30) {
System.out.println("分数为" + scores[i] + "的等级为C");
}else {
System.out.println("分数为" + scores[i] + "的等级为D");
}
}
}
🎁 二,二维数组
🏭 2.1,概念
对于二维数组的理解,我们可以看成是一维数组array1又作为另一个一维数组array2的元素而存在。其实,从数组底层的运行机制来看,没有多维数组的存在。
1,语法格式
格式1:
int[][] arr = new int[3][2];
- 定义了名称为arr的二维数组
- 二维数组中有3个以为数组
- 每个一维数组中有2个元素
- 一维数组的名称分别为arr[0],arr[1],arr[2]
- 给第一个一维数组1脚标位赋值为78写法是:
arr[0][1] = 78
格式2:
int[][] arr = new int[3][];
- 二维数组中有3个一维数组。
- 每个一维数组都是默认初始化值null(注意:区别于格式1)
- 可以对这三个一维数组分别进行初始化
arr[0] = new int[3]; arr[i] = new int[i]; arr[2] = new int[2];
注:int[][] arr = new int[][3]
是非法的
格式3:
int[][] arr = new int[][]{{3,4,2},{3,4},{9,0,3,4}}
- 定义一个名称为arr的二维数组,二维数组中有三个以为数组
- 每个一个数组中具体元素也都已初始化
- 第一个一维数组arr[0] = {3,4,2};
- 第二个一维数组arr[0] = {3,4};
- 第三个一维数组arr[0] = {9,0,3,4};
- 第三个一维数组的长度表示方式:arr[2].length;
🐾 2.2,二维数组的使用
public static void main(String[] args) {
//1、声明二维数组
//1.1声明数组的同时开辟空间:数据类型[门][]数组名称=new 数据类型[行] [列] ;
int[][] nns = new
int[3][4];
//列的值:可以有:所有的行的列的个数相同,相当于矩形
//可以省略, 每一-行都是nu11,需要自己去开辟空间--了解
//1.2先声明数组再开辟空间
int[][] nns2;
nns = new int[3][4];
//1.3声明数组的同时赋初值:行列的长度由赋值的个数决定了
int[][] nns3 = new int[][]{{1, 2}, {3, 4}, {5, 6}};
//1.4
int[][] nns4 = new int[3][];
nns4[0] = new int[]{1, 2};
System.out.println(Arrays.toString(nns4));
System.out.println(Arrays.toString(nns4[0]));
//2、赋值
//使用循环赋值
for (int i = 0; i < nns.length; i++) {
for (int j = 0; j < nns[i].length; j++) {
nns[i][j] = i + j + 4;
}
}
//3、取值
for (int i = 0; i < nns3.length; i++) {
for (int j = 0; j < nns3[i].length; j++) {
System.out.print(nns3[i][j] + " ");
}
System.out.println();
}
}
🎉 2.3,内存结构
🏭 三,数组中常见的算法
📐 3.1,二分查找
数组的复制,反转,查找(线性查找,二分查找)
public static void main(String[] args) {
String[] arr = new String[]{"JJ","DD","MM","BB","GG","AA"};
// 数组的复制(区别于数组变量的赋值:arr1 = arr)
String[] arr1 = new String[arr.length];
for (int i = 0; i < arr.length; i++) {
arr1[i] = arr[i];
}
// 遍历
for (int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);
}
System.out.println("=======================");
// 数组的反转
for (int i = 0,j = arr.length-1; i < j; i++,j--) {
String temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
// 遍历
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
System.out.println("=======================");
// 查找(或搜索)
// 线性查找
String dest = "BB";
boolean isFlag = true;
for (int i = 0; i < arr.length; i++) {
if (dest.equals(arr[i])){
System.out.println("找到了指定元素" + dest + "下标为:" + i);
isFlag = true;
break;
}
}
if (isFlag){
System.out.println("没有找到目标元素");
}
System.out.println("=======================");
// 二分查找
// 前提:所要查找的数组必须有序
int [] arr2 = new int[]{-98,-34,2,34, 54,66,79,105,210 ,333};
// 目标值
int dest1 = 34;
int start = 0; // 开始下标
int end = arr2.length-1; //结束下标
boolean isFlage1 = true; // 是否找到的标识
while (start <= end) {
int min = (start + end)/2;
if (arr2[min] == dest1){
System.out.println("找到了目标元素:" + dest1 + "下标为:" + min);
isFlage1 = false;
break;
} else if (dest1 > arr2[min]) {
start = min + 1;
} else {
end = min - 1;
}
}
if (isFlage1){
System.out.println("没有找到目标元素");
}
}
💬 3.2,排序算法
衡量排序算法的优劣:
- 时间复杂度:分析关键字的比较次数和记录的移动次数。
- 空间复杂度:分析排序算法中需要多少辅助内存
- 稳定性:若两个记录A和B的关键字值相等,但排序后A,B的先后次序保持不变,则称这种排序算法是稳定的。
💖 3.3,冒泡排序
public static void main(String[] args) {
int[] arr = new int[]{43,32,76,-98,0, 64,33,-21,32,99};
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length -1 - i; j++) {
if (arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");
}
}
🚜 3.4,Arrays工具类
public static void main(String[] args) {
// 1,boolean equals(int[] a,int[] b) :判断两个数组是否相等
int[] arr1 = {1, 2, 3, 4};
int[] arr2 = {1, 3, 2, 4};
boolean isEquals = Arrays.equals(arr1, arr2);
System.out.println(isEquals);
// 2, String toString(int[] a) : 数除数组信息。
System.out.println(Arrays.toString(arr1));
// 3, void fill(int[] a,int val) : 将指定值填充到数组之中
// 将指定的int值赋给指定的int数组的每个元素。
Arrays.fill(arr1,10);
System.out.println(Arrays.toString(arr1));
// 4, void sort(int[] a) : 对数组进行排序
Arrays.sort(arr2);
System.out.println(Arrays.toString(arr2));
// 5, int binarySearch(int[] a, int key)
int[] arr3 = new int[]{43,32,76,-98,0, 64,33,-21,32,99};
int index = Arrays.binarySearch(arr3, 0);
if (index >= 0){
System.out.println("找到了目标值" + "下标为:" + index);
} else {
System.out.println("未找到");
}
}