文章目录
- 数组概念
- 数组的创建和初始化
-
- 数组的创建
- 数组的定义
- 数组的使用
-
- 数组中元素访问
- 遍历数组
- 数组拷贝
- 引用类型->数组
-
- 初始JVM内存布局
- 基本类型变量与引用类型变量的区别
- null
- 二维数组
-
- 基本语法
- 二维数组的创建
- 二维数组的访问
- 不规则数组
数组概念 概念: 数组是相同类型元素的集合。
内存布局: 在内存中是一段连续的空间。
注:
- 数组中存放的元素类型是相同的
- 在空间上是连续存放的
- 每个空间都有对应的编号,起始位置下标为0。
T[] 数组名 = new T[N]
T:数组元素类型数组的定义 数组的定义有2种方式
N: 元素个数
1.动态初始化:在创建数组时,直接指定数组元素的个数
int[] arr = new int[10]
- 静态初始化:在创建数组的同时初始化其数据
int[] arr1 = new int[]{0,1,2,3,4,5,6,7,8,9};
double[] arr2 = new double[]{1.0, 2.0, 3.0, 4.0, 5.0};
String[] arr3 = new String[]{"hello", "Java", "!!!"};
注:
- 静态初始化虽然没有指定数组的长度,编译器在编译时会根据{}中元素个数来确定数组的长度。
- 静态初始化时, {}中数据类型必须与[]前数据类型一致。
- 静态初始化可以简写,省去后面的new T[]。
// 注意:虽然省去了new T[], 但是编译器编译代码时还是会还原
int[] array1 = {0,1,2,3,4,5,6,7,8,9};
double[] array2 = {1.0, 2.0, 3.0, 4.0, 5.0};
String[] array3 = {"hello", "Java", "!!!"};
- 静态和动态初始化也可以分为两步,但是省略格式不可以
int[] arr;
arr = new int[]{1,2,3};
int[] arr1;
arr1 = new int[13];
//error
int[] arr2;
arr2 = {1,2,3};
- 如果没有对数组初始化,那么数组其默认值根据数组类型来初始化(引用类型默认为null)
类型 | 默认值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0 |
float | 0.0f |
double | 0.0 |
char | /u0000 |
boolean | false |
int[]array = new int[]{10, 20, 30, 40, 50};
System.out.println(array[0]);
System.out.println(array[1]);
System.out.println(array[2]);
System.out.println(array[3]);
System.out.println(array[4]);
// 也可以通过[]对数组中的元素进行修改
array[0] = 100;
System.out.println(array[0])
注:
- 数组是一段连续的内存空间,所以支持随机访问,通过下标访问快速访问数组中任意位置的元素
- 下标从0开始,介于[0, N)之间不包含N,N为元素个数,不能越界,否则会报出下标越界异常。
打印有三种方法:
- 知道数组元素个数,利用循环打印
int arr[] = new int[]{1,2,3,4,5,6};
for (int i = 0;
i < 6 ;
i++) {
System.out.print(arr[i] + " ");
}
- 利用数组对象.length 直接获取数组长度
int arr[] = new int[]{1,2,3,4,5,6};
for (int i = 0;
i < arr.length ;
i++) {
System.out.print(arr[i] + " ");
}
- 使用for - each遍历数组
Java有一种功能很强的循环结构,可以用来依次处理数组中的每个元素(其他类型的元素集合亦可)而不必为指定下标值而分心。
语句格式:for (variable : collection) statement
collection这一集合表达式必须是一个数组或者是一个实现了Iterable接口的类对象(例如ArrayList).variable代表的是每个元素类型
int arr[] = new int[]{1,2,3,4,5,6};
for (int x : arr){
System.out.print(x + " ");
}
这个循环叫做循环arr中的每一个元素,可以使语句更加简洁,更不容易出错(我们不必关系下标值和终止条件)
- 利用 Arrays类的toString方法
public static void main(String[] args) {
int[] arr = new int[] {1,2,3,4};
System.out.println(Arrays.toString(arr));
}
文章图片
数组拷贝
- 在Java中,允许将一个数组变量拷贝给另一个数组变量。这时,两个变量将引用同一个数组:
int[] arr1 = new int[] {1, 2, 3, 4};
int[] arr2 = arr1;
注:由于arr1和arr2都指向同一对象,所以修改二者中任意一个元素,另一个也会改变。
- 如果我们希望把一个数组中所有元素拷贝到一个新数组中,这时候我们就需要使用Arrays类的copyof方法;
public static void main(String[] args) {
int[] arr1 = new int[] {1, 3, 5, 7, 9};
int[] arr2 = Arrays.copyOf(arr1,arr1.length);
}
第2个参数是新数组的长度。这个方法通常用来增加数组的大小:
int[] arr2 = Arrays.copyof(arr1,arr.length * 2);
如果数组元素是数值型,那么多余的元素将被赋值为0;
如果数组元素是布尔型,则将赋值为false。相反,如果长度小于原始数组的长度,则只拷贝最前面的数据元素。- 使用
System.arraycopy(Object src, int srcPos,Object dest, int destPos,int length);
这个copy十分强大,可以copy任何类型的数据。
public static void main(String[] args) {
int[] arr = {1,2,3,4};
/**
* public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length)
* src - 源数组。
* srcPos - 源数组中的起始位置。
* dest - 目标数组。
* destPos - 目的地数据中的起始位置。
* length - 要复制的数组元素的数量。
*/
int[] arr1 = new int[10];
System.arraycopy(arr,0,arr1,1,arr.length - 1);
System.out.println(Arrays.toString(arr1));
//[0, 1, 2, 3, 0, 0, 0, 0, 0, 0]
}
引用类型->数组 初始JVM内存布局
内存是一段连续的存储空间,主要用来存储程序运行时数据的
在程序运行时代码,数据,常量等需要加载到内存中,一些方法运行结束时需要销毁,如果我们不对数据加以区分管理,那么对内存管理将会十分麻烦,所以在JVM中,按照不同的功能对内存进行划分:
【JavaSE|【JavaSE】数组】
文章图片
- 程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址
- 虚拟机栈( JVM Stack): 与方法调用相关的一些信息,每个方法在执行时,都会先创建一个栈帧 ,栈帧中包含有:局部变量表、操作数栈、动态链接、返回地址以及其他的一些信息,保存的都是与方法执行时相关的一些信息。比如:局部变量。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了。
- 本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部变量. 在有些版本的 JVM 实现中(例如HotSpot), 本地方法栈和虚拟机栈是一起的
- 堆( Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2,
3} ),堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销毁。 - 方法区(Method Area): 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据. 方法编译出的的字节码就是保存在这个区域
基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值;
而引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址。
public static void func() {
int a = 10;
int b = 20;
int[] arr = new int[]{1,2,3};
}
文章图片
注:引用变量并不直接存储对象本身,可以简单理解成存储的是对象在堆中空间的起始地址。通过该地址,引用变量便可以去操作对象
null
null 在 Java 中表示 "空引用" , 也就是一个不指向对象的引用
int[] arr = null;
System.out.println(arr[0]);
// 执行结果
Exception in thread "main" java.lang.NullPointerException
at Test.main(Test.java:6)
null 的作用类似于 C 语言中的 NULL (空指针), 都是表示一个无效的内存位置. 因此不能对这个内存进行任何读写操作.一旦尝试读写, 就会抛出 NullPointerException.
注意: Java 中并没有约定 null 和 0 号地址的内存有任何关联
二维数组 二维数组本质上是一个一维数组,不同于C,Java中二维数组在空间上不是连续的。
基本语法
数据类型[][] 数组名称 = new [行数][列数] {初始化数据};
二维数组的创建 同一维数组,二维数组也有两种创建方式:
- 动态初始化
int[][] array = {{1,2,3},{4,5,6}};
int[][] array2 = new int[][]{{1,2,3},{4,5,6}};
- 静态初始化
int[][] array3 = new int[2][3];
二维数组的访问
- 普通打印
int[][] array = {{1,2,3},{4,5,6}};
for (int i = 0;
i < array.length;
i++) {
for (int j = 0;
j < array[i].length;
j++) {
System.out.print(array[i][j] +" ");
}
System.out.println();
}
在这里二维数组中其实存放的两个一维数组的地址;所以通过array[i].length就可以得到一维数组的长度,这就衍生出了不规则数组。
- 利用for-each打印
int[][] array = {{1,2,3},{4,5,6}};
for(int[] tmp : array) {
for(int x : tmp) {
System.out.print(x+" ");
}
System.out.println();
}
不规则数组
int[][] array2 = new int[2][];
array2[0] = new int[2];
array2[1] = new int[4];
for (int i = 0;
i < array2.length;
i++) {
for (int j = 0;
j < array2[i].length;
j++) {
System.out.print(array2[i][j] +" ");
}
System.out.println();
}
不规则数组标题与我们在C中的二维数组,我们可以先定义我们需要几个一维数组,然后为其赋予空间。
推荐阅读
- 即时通讯源码对企业到底有多重要呢()
- 牛客刷题集锦|『牛客|每日一题』 栈的压入、弹出序列
- 牛客刷题集锦|『牛客|每日一题』模板栈
- 后端|分布式锁用 Redis 还是 Zookeeper(看完你就明白了)
- #|红黑树的学习
- 笔记|SpringBoot发送邮件(详细学习笔记)
- spring|springboot发送邮件工具类
- java|来杯JAVA
- java|Java Web 利用 session 实现简单的购物车(数量可以累加)