一看就会的java数组详解(全面版)
·
这里写自定义目录标题
数组
首先回顾Java数据类型
(1) 基本数据类型
- 数值型
- 整数类型:存放整数
byte(1字节)short(2字节)int(4字节)long(8字节)
- 浮点(小数)类型:
float(4字节)double(8字节)
- 整数类型:存放整数
- 字符型
char(2字节):存放单个字符,如'a'
- 布尔型
boolean(1字节):存放true或false
(2)引用数据类型
- 类 (
class) - 接口 (
interface)
[[ - 数组 ([]) ]] ---->数组也是一种数据类型(引用类型,数组型数据是对象(object))
(3)说明
- Java数据类型分为两大类:基本数据类型,引用类型
- 基本数据类型有8种:
- 数值型:
byte,short,int,long,float,double char,boolean
- 数值型:
- 引用类型:
类,接口,数组
1. 为什么需要数组?(Array)
当你需要同时管理多个相同类型的变量时,使用数组能让代码更简洁、逻辑更清晰。数组是存储多个相同类型数据的容器。
定义数组的语法:
- 声明数组并开辟空间
- 给数组各个元素赋值
- 使用数组
数据类型[] 数组名 = new 数据类型[长度];// 数据类型后加[],表示是该数据类型的数组
示例
- (动态初始化:只告诉 JVM 我要一个几位长的数组,值我后面再填):
int[] scores = new int[5];// 定义一个长度为5的int数组
//数据类型[] 数组名 / 数据类型 数组名[] = new 数据类型[大小]
(1)适合:需要用户输入、从接口拿数据、或初始化长度但不确定值的时候
(2)数组创建后,如果没有赋值,有默认值(不同的数据类型默认值如下):
int 0,short 0, byte 0, long 0, float 0.0,double 0.0,char \u0000,boolean false,String null
- 你也可以用静态初始化(定义数组的同时就把元素值也写上了,适合你已经知道内容时用):
int[] nums = {1, 2, 3, 4, 5};//好处:可以使用for遍历数组得到数组的所有元素的和
//第一个元素对应的下标是0 nums[0],第二个对应的下标是1 nums[1],下标是从 0~length-1,不能超,length就是数组里面数的个数
2 .数组快速入门
public class Main {
public static void main(String[] args) {
// 1. 定义并初始化数组
int[] arr = {10, 20, 30};
// 2. 输出数组第一个元素(索引为 0)
System.out.println(arr[0]); // 输出: 10
// 3. 修改数组第二个元素的值(索引为 1)
arr[1] = 99;
// 4. 遍历数组并输出每个元素
for (int i = 0; i < arr.length; i++) { //i表示数组的下标,可以通过数组名.length得到数组的大小/长度
System.out.println("元素" + i + ": " + arr[i]);
}
}
}
/*
创建一个char 类型的26 个元素的数组,分别放置'A'-'Z'。
使用for 循环访问所有元素并打印出来。
提示:char 类型数据运算'A'+1 -> 'B'
思路分析 :
1. 定义一个数组char[] chars = new char[26]
2. 因为'A' + 1 = 'B' 类推,所以老师使用for 来赋值
3. 使用for 循环访问所有元素
*/
public class ArrayDemo01 {
public static void main(String[] args) {
char[] character = new char[26]; //注意! character是char[]类型,而character[i]是char类型
for (int i = 0; i <= 25; i++) { //写成 i < character.length 挺好的 ^-^
character[i] = (char)('A' + i); //(char)('A' + i) :
//'A' 的 ASCII 编码是 65
//('A' + 1)是 66,强转成 char 就是 'B'
//所以 ('A' + i) 可以一步步生成 'A' 到 'Z'
System.out.print(character[i]+" ");
}
}
}
(‘A’+i)的数据类型是int,因此要加上(char)来强制转换,理由如下
补充:数据类型转换规则:
- 当java程序进行赋值/运算时,精度小的类型会自动转换为精度大的数据类型(自动类型转换)
- 数据类型按精度(容量)大小排序顺序如下:
- char ->int ->long ->float ->double
- byte ->short ->int ->long ->float ->double
初步了解JVM:Java Virtual Machine(Java虚拟机)
- JVM 帮你执行 Java 程序,也就是:把 .java 写的代码 → 编译成 .class 字节码
- JVM 读取 .class 文件 → 翻译成本地机器能懂的指令去跑
- 所以你写的代码根本不是给 CPU 的,是写给 JVM 的,JVM 再帮你翻译给 CPU 跑起来
- JVM 的作用:跨平台 — 因为只要每个平台装了对应的 JVM,不管你在哪,Java 都能“Write Once, Run Anywhere”。
- JVM 内存结构(重点)
JVM 把它管理的内存分为几个大块,每块干的事不一样,数组赋值就发生在其中一块叫“堆”的地方 :
🔧 1. 方法区(Method Area)
存放类的信息(比如类名、字段、方法、常量池)属于共享内存区域
🔧 2. 堆(Heap)
存放所有 new 出来的对象和数组,是 GC(垃圾回收)的主战场,所有线程共享的
你一写:int[] arr = new int[10]; 这个数组就是分配在“堆”上的。
🔧 3. 栈(Stack)
每个线程一个栈,里面存储方法调用时的局部变量表、操作数栈,基本数据类型(int、char 等)变量放这
引用变量也在这(注意是引用,不是对象本体)
所以你写 int[] arr = new int[3]; 变量 arr 是在栈中,指向的是堆中的数组。 - 数组在 JVM 中的创建与赋值过程(详细)
int[] arr = new int[3];
arr[0] = 10;
🔨 步骤分解:
- 编译器看你写了 new int[3],它就让 JVM 在堆中分配一个长度为 3 的 int 数组空间,所有 int 元素默认值为 0(Java 的规则)
- JVM 返回这个数组在堆中的地址/引用 ,并把这个引用存在栈帧中的局部变量表里,变量名 arr 存在栈中,但值其实是个“指针”去堆找数组
- 你执行 arr[0] = 10; JVM 通过 arr 找到堆里的数组 ,把第 0 个位置的值改成了 10
- 所以说: 数组本体(真实内存)是在堆中,引用(arr 变量)是在栈中,对数组赋值,其实就是通过“引用”操作“堆上的对象”
数组赋值方法
- 不同于基本数据类型赋值的值拷贝(n2的变化不会影响到n1的值)
int n1 = 10; int n2 = n1; n2 = 80;
先把n1 = 10放在栈里,再拷贝一个n2 = 10,再找到n2把值改成80,不会影响n1 - 数组是引用传递,赋的是地址,赋值方式为引用赋值
int[] arr1 = {1,2,3};
int[] arr2 = arr1; //arr2的变化会影响arr1的值(这个不是拷贝!)
arr2[0] = 10;
现在栈里面有一个arr1,arr1并不指向一个值,而是指向一个地址,这个地址又指向堆里面的一个数据空间,该数据空间(在内存里面每个数据空间都对应一个地址)里面的子空间数等于数组个数,一一对应
把arr1赋值给arr2时,在内存中相当于在栈里面拷贝了一个arr2指向同一个地址(同一个数据空间,同一个数组)
对于下标为0的元素(这里是1),他可以通过arr1[0]返回,也可以通过arr2[0]返回
因此通过arr2[0]改变了值,直接就改了堆上的同一个数组(类似共享文档)//这部分可以看一下赋值内存图
数组拷贝(解决此问题:怎么做到改变新数组不影响原数组,做到数据空间独立?)
int[] arr1 = {1, 2, 3};
// 要创建一个新的数组 arr2 --> 开辟新的数据空间,大小为 arr1.length
int[] arr2 = new int[arr1.length];
// 有 new,会在堆里面开一个新的数据空间,产生一个新地址,
// 再把这个地址拷贝给 arr2,此时新数据空间里面数组都为默认值 0
// 遍历 arr1,把每个元素拷贝到对应位置
for (int i = 0; i < arr1.length; i++) {
arr2[i] = arr1[i];
}
数组翻转
public class ArrayReverse {
//编写一个main 方法
public static void main(String[] args) {
//定义数组
int[] arr = {11, 22, 33, 44, 55, 66};
//规律
//1. 把arr[0] 和arr[5] 进行交换{66,22,33,44,55,11}
//2. 把arr[1] 和arr[4] 进行交换{66,55,33,44,22,11}
//3. 把arr[2] 和arr[3] 进行交换{66,55,44,33,22,11}
//4. 一共要交换3次= arr.length / 2
//5. 每次交换时,对应的下标是arr[i] 和arr[arr.length - 1 -i] 如0和5(0和6-1-0=5)
int temp = 0;
int len = arr.length; //计算数组的长度
for( int i = 0; i < len / 2; i++) {
temp = arr[len - 1 - i];//保存
arr[len - 1 - i] = arr[i];
arr[i] = temp;
}
System.out.println("===翻转后数组===");
for(int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + "\t");//66,55,44,33,22,11
}
}
}
数组添加(扩容):创建新数组 + 拷贝
int[] oldArr = {1, 2, 3};
int[] newArr = new int[6]; // 假设扩容2倍
for (int i = 0; i < oldArr.length; i++) { //遍历旧数组
newArr[i] = oldArr[i];
}
oldArr = newArr; //根据之前的知识,让oldArr的地址变为newArr的地址,原来那个空间就不被任何对象引用,这一步会把oldArr被GC清理删除掉
补充GC::Garbage Collection(垃圾回收)
上面例子最后一行出现的这个原来没用的数组被GC回收:
- GC 是 JVM 自动负责释放不再被使用对象的内存空间的一种机制,不需要你手动释放,就能防止内存泄露和爆炸。 你创建一个对象,JVM 会给它分配内存;当这个对象再也没人用,它就成了“垃圾”,GC 就会自动回收掉它占的内存,留给别的对象用。
- 被清理的对象 -没有“引用链”能访问到它,意思就是,它不再被任何变量、字段、参数、栈帧指着
更多推荐
所有评论(0)