- 数组的定义及初始化
- 数组的使用
- 数组作为方法的参数及返回值
- 数组应用
- 二维数组
数组的定义及初始化
首先,我们要了解什么是数组。数组是存放相同类型数据的集合,数组的内存分布是连续的。
我们创建数组一般有三种方式:
int[] arr = new int[]{1,2,3}; //动态初始化
int[] arr = {1,2,3}; //静态初始化 也产生了对象
int[] arr = new int[3]; //定义数组
即数组的初始化可以:
1、动态初始化:数据类型[] 数据名称 = new 数据类型 {初始化数据};
2、静态初始化:数据类型[] 数据名称 = {初始化数据}; (比较常用)
3、定义数组:要注意定义数组并没有初始化数组,只是指定了数组的大小,即就是在堆上给数组开辟了一块连续的空间。
两种异常:我们创建数组的时候容易出现两种异常:
int[] arr = {};
这种看起来是我们的静态初始化,不一样的就是初始化大括号里没有数据,这说明我们数组长度为0,所以不能进行数组的访问,否则会造成数组越界异常(java.lang.ArrayIndexOutBoundsException)
int[] arr = null;
System.out.println(arr.length);
null在引用类型中的地位就相当于基本类型(int)中的0。我们定义arr数组初始化为null,获取长度时对arr进行操作相当于操作null,会报出空指针异常(java.lang.NullPointerException)
数组的使用
定义完数组后,我们就要操作一个数组啦
1.获取数组arr长度
int[] arr = {1,2,3};
System.out.println(arr.length);
2.访问数组通过下标来访问,注意数组下标是从0开始的,下标属于[0,length-1]
int[] arr = {1,2,3};
System.out.println(arr);
这会输出什么呢---[I@16d3586 其实这就类似于c语言中数组存放首元素的地址,不过这个诡异的数字是地址的哈希码,而且地址和哈希码是一一对应的关系。
3.遍历数组:遍历数组就是访问数组的元素,有三种方式
①用for循环遍历数组
int[] arr = {1,2,3};
for (int i = 0; i < arr.length ; i++) {
System.out.println(arr[i]);
}
②for-each循环遍历数组
int[] arr = {1,2,3};
//x是用来接收arr数组中的元素,arr是要遍历的数组
for (int x: arr) {
System.out.println(x);
}
我们会发现他们两个的不同之处就是for-each循环不能通过下标来访问数组
③Array.toString()直接访问数组--使用时必须导入java.util.Arrays包
int[] arr = {1,2,3};
System.out.println(Arrays.toString(arr)); //将数组以字符串形式输出
数组作为方法的参数及返回值
数组作为方法的参数:
public static void printArr(int[] arr1) {
for (int x: arr1) {
System.out.println(x);
}
}
public static void main(String[] args) {
int[] arr = {1,2,3};
printArr(arr);
}
这样可以依次打印出数组的元素,实际上就是这样的:方法名arr是一个引用,传参的时候按照引用传参。
数组作为方法的返回值:
我们原来可以返回int,float,boolean ....,其实数组也可以当做参数返回的。注意返回的是你new出来的数组,接收当然必须也是同类型数组。
public static int[] transform(int[] arr) { //不改变原来的数组把数组大小扩大为原来的两倍,并返回
int[] tmp = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
tmp[i] = arr[i]*2;
}
return tmp;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
int[] arr2 = transform(arr);
System.out.println(Arrays.toString(arr2));
}
数组的应用
数组转字符串:方便打印
public static void main(String[] args) {
int[] arr = {1,2,3};
String newArr = Arrays.toString(arr);
System.out.println(newArr);
}
如何自己实现数组转化为字符串呢?其实就是遍历数组字符串拼接的工作啦。。
public static String tostring(int[] arr) {
String ret = "[";
for (int i = 0; i < arr.length; i++) {
ret += arr[i];
if(i != arr.length-1) {
ret += ",";
}
}
ret += "]";
return ret;
}
public static void main(String[] args) {
int[] arr = {1,2,3};
System.out.println(tostring(arr));
}
数组拷贝:
数组的拷贝共有四种方式,对于数组当中如果是简单类型,就是深拷贝。如果是引用类型,那么就是浅拷贝。
1、for循环进行拷贝
int[] array = {1,2,3,4,5};
int[] array2 = new int[array.length];
for (int i = 0; i < array.length; i++) {
array2[i] = array[i];
}
System.out.println(Arrays.toString(array2));
2、System.arraycopy拷贝
arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
//src:代表源数组
//srcPos:从源数组的pos位置开始拷贝
//dest:目的数组
//destPos:目的数组的位置
//length:要拷贝的长度
int[] array = {1,2,3,4,5};
int[] array2 = new int[array.length];
System.arraycopy(array,0,array2,0,array.length);
System.out.println(Arrays.toString(array2));
3、Array.copyOf拷贝
copyOf(int[] original, int newLength)
//original:源数组
//newLength:拷贝的长度
int[] arr = {1,2,3};
int[] arr2 = Arrays.copyOf(arr,arr.length); //arr2只是存放拷贝完的引用
System.out.println(Arrays.toString(arr2));
4、数组名.clone clone是Object的方法,返回一个副本
int[] arr = {1,2,3};
int[] arr2 = arr.clone();
System.out.println(Arrays.toString(arr2));
那么arrayCopy和copyOf的区别是什么?
①返回值:arrayCopy返回类型是void,copyOf返回类型是int[](具体的类型)
②代码层次:Array.copyOf()底层调用System.arraycopy()
③速度:System.arraycopy()速度更快(native)
这四种拷贝方式对于简单类型是深拷贝,直接运用于引用类型来说是浅拷贝,若要深拷贝,还要拷贝对象。。ps:后续需补充
------------
浅拷贝只是拷贝了引用,两个引用指向同一块空间,通过其中一个引用改变对象的值,通过另一个引用访问该对象时值也是改变的;深拷贝不仅拷贝了其引用,还拷贝了其对象。通过一个引用改变对象的值,不影响另一个引用和对象。
可变参数编程:
public static int sum(int...array) {
int ret = 0;
for(int x: array) {
ret += x;
}
return ret;
}
public static void main(String[] args) {
System.out.println(sum(1,2,3,4,5));
int[] array = {1,2,3,4,5};
System.out.println(sum(array));
//匿名数组
System.out.println(sum(new int[]{1,2,3,4,5}));
}
二维数组
定义:数据类型[][] 数组名称 = new 数据类型[行数][列数] {初始化数据};
int[][] array1 = {{1,2,3},{4,5,6}};
int[][] array2 = new int[][]{{1,2,3},{4,5,6}};
int[][] array3 = new int[2][3]; //定义 没有初始化
int[][] array4 = new int[2][]; //可以不写列
二维数组的分布
打印二维数组:
Arrays.deepToString();
用法和一维数组大同小异。。。不再赘述后续补充。。
=====================================================================================
补充JVM的五大内存区域划分:
1、程序计数器:存放下一条执行的指令的地址。(很small一块)
2、java虚拟机栈:主要用来存放局部变量表
3、本地方法栈:主要用来调用native()方法。存放native方法的局部变量。(native()是由C/C++代码实现的方法,一般出现在源码中)
4、堆:主要来存放对象(new)的
5、方法区:用于存储已经被虚拟机加载的类信息、Class对象
ps:常量池:主要用来存放字符串常量。在JDK1.7以前,常量池存放在方法去。JDK1.7开始,挪到了堆里
每个线程都会有三块独立的内存区域:程序计数器、java虚拟机栈、本地方法栈