目录
1.初始化定义
java数组的定义分两种,静态初始化,动态初始化
int [] a =new int[20];//动态
int [] b =new int[]{1,2,3,4,5};//静态
注意下面的框内是没有数字的,不能填写数字,编译器会根据后面的元素得到。
这种方式在初学者,尤其是先学C语言的人看来比较奇怪,
首先是 int [ ] a;int [ ]代表数组的类型,a是变量名
其次,java中的数组是一种引用类型,也就是a变量存放的是地址,是右边new出来的那片空间的地址
最后来看一下一张图,java程序是在jvm(虚拟机)上跑的,那他的内存分布是什么样子
简单介绍一下各自空间:
java虚拟机栈:存放局部变量
java本地方法栈:运行c,c++编写的程序【JVM是一个由c,c++编写的软件,因为底层开发高效】
堆:存放对象(new出来的那些)
程序计数器:存放指令,以便程序顺序,循环,选择,跳转的执行
方法区:存放静态的成员变量
PS:线程隔离共享可以简单理解成多个程序共享一个方法区和堆区,其他的程序计数器等等都是自己拥有一片空间
我们主要从虚拟机栈和堆区上理解数组
int [ ] a = new int[ ]{1,2,3};是怎么执行的?
首先是创建a,假定a是一个局部变量,因此他在栈上开辟空间,然后new了一块空间,就是在堆上开辟了一块放着四个整形的1,2,3;然后a取这块空间的地址
ps:这里的0x99是一个哈希印射的地址,但是可以通过这个虚拟地址找到存放位置
变量的地址是伪地址(安全性)
2.数组的三种打印方式
1.常规遍历
2.创建变量接受
3.转换成字符串直接打印
1.直接遍历
public class TestDemo4 {
public static void main(String[] args) {
int[] a = new int[]{1, 2, 3, 4};
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
}
2.创建变量接受
public class TestDemo4 {
public static void main(String[] args) {
int[] a = new int[]{1, 2, 3, 4};
for (int x:a) {
System.out.println(x);
}
}
}
创建了一个x接受a里面的元素
3.转换字符串
import java.util.Arrays;
public class TestDemo4 {
public static void main(String[] args) {
int[] a = new int[]{1, 2, 3, 4};
String s = Arrays.toString(a);
System.out.println(s);
}
}
转换字符串的打印结果
第三种方法是Arrays.toString 把数组a转换成字符串,然后用s接受,然后直接打印
3.数组引用null
如果给数组定义null,那就是引用空的意思,类似C语言的NULL,都是指向无效地址,然后对其的任何读取操作都会出现空指针异常错误。【java并没有规定null与0地址有关系】
4.浅谈引用变量的影响
例1:下面代码的结果是什么?
public class TestDemo4 {
public static void main(String[] args) {
int[] a = new int[]{1,2,3,4};
int[] b=a;
b[1]=10;
for (int i = 0; i < b.length; i++) {
System.out.println(b[i]);
}
}
}
答案是1 10 3 4(有分行)
int [ ]b=a;代表什么,是b引用了a引用的对象
a,b是栈上的不同变量,但是都指向了堆上的同一块内存1,2,3,4;
因此用b来修改内存,也就相当修改了a的
可以看到两个变量放的地址是一样的
例2:最终的打印结果是什么
public class TestDemo4 {
public static void exchange(int [] b){
b = new int []{7,8,9,10};
}
public static void main(String[] args) {
int []a = new int[]{1,2,3,4};
exchange(a);
for (int i = 0; i < a.length; i++) {
System.out.println(a[i]);
}
}
}
1,2,3,4;
一开始a指向1,2,3,4;然后函数exchange的形参b接受a的值,所以a,b同时指向1,2,3,4
接着b便指向了7,8,9,10;然后函数结束,然后打印a,a本身没有任何改变
区别引用是否改变的一个关键就是:它拿这个引用干了什么,例1拿到地址修改值;例二拿到了地址,然后不要这个地址,重新拿了一块新地址
5.与数组相关的字符串操作
1.转换字符串
前面提到了,Arrays.toSting(数组名),返回一个字符串
如int [ ] a = new int [ ]{1,2,3,4};
Arrays.toString(a)
返回”[1,2,3,4]”
2.字符串拷贝函数
Arrays.copyOf(数组名,拷贝长度);返回一个数组
还可以用于拓展数组
import java.util.Arrays;
public class TestDemo4 {
public static void main(String[] args) {
int []a = new int[]{1,2,3,4};
int []copy=Arrays.copyOf(a,a.length);
}
}
6.二维数组的创建和遍历
第一种是静态初始化
int[][] b = new int[][]{{1, 2, 3}, {2, 3, 4}, {6, 7, 8}};
第二种是动态初始化
int[][] b = new int[2][4];
遍历数组(for循环直接遍历)二维数组的元素是一维数组,因此可以用b[i].length来找长度
int[][] b = new int[][]{{1, 2, 3}, {2, 3, 4}, {6, 7, 8}};
for (int i = 0; i < b.length; i++) {
for (int j = 0; j < b[i].length; j++) {
System.out.println(b[i][j]);
}
}
第二种是for each遍历 二维数组的元素的类型是int [ ] (假设是int型)
int[][] b = new int[][]{{1, 2, 3}, {2, 3, 4}, {6, 7, 8}};
for (int []x:b) {
for(int y:x){
System.out.println(y);
}
}
7.不规则二维数组
int[][] b = new int[2][];
System.out.println(b[1][0]);
与c语言不同,java可以指定行而不指定列
现在对第二行取第一个元素会发生什么?
会发生空指针异常错误
首先需要了解的是java的数组存储的对象是一片连续的空间
但是二维数组的元素是一维数组,也就是引用类型,因此他们的空间自然就可以不连续了,不妨自己画个图理解一下,不连续也就不用硬性要去他们的引用的长度都一样,所以会延伸出以一种不规则的二维数组。
c语言的数组是连续空间,也有指针概念,所以可以数组名+1来跳过一个元素,因为数组名本质就是指针,但是java中没有指针概念,因此没有数组名+1这种操作
int[][] b = new int[][]{{1, 2}, {1, 5, 6}, {6, 7, 8, 6}};
它们每一行的长度都不一样
回到刚刚的问题,为什么会空指针异常?java中定义数组不赋初识值都会默认给一个值,int就0
那这里的二维数组相当于定义一个存放两个引用类型的变量,那引用了谁,你没赋值,所以默认是null,因此我们对null进行下标查找的操作自然就会异常。