数组 就是指一组相关类型的变量集合,并且这些变量可以按照统一的方式进行操作。
1.数组的基本用法
1.1创建数组
数组是引用类型,在Java当中所有引用类型想要分配空间就必须要使用new关键字。
- 数组静态初始化
数据类型[] 数组名称 = {初始化数据};
int[] array1 = {1,2,3,4,5,6};
静态初始化时候,数组元素的个数和初始化数据的格式是保持一致的。
- 数组动态初始化(声明并开辟数组)
数据类型[] 数组名称 = new 数据类型[长度];
int[] array2 = new int[]{1,2,3,4,5};
int[] array3 = new int[5];
数组3未进行初始化,若数组的数据类型为引用类型时,数据初始值为null;若数组的数据类型为基本数据类型时,数据初始值为0。上述的array3的数据初始值即为0。
1.2数组的使用
在Java当中有一种能够动态获取数组长度的方法:数组名称.length ,这是一个属性而不是一个方法。
- 获取长度并访问数组的元素
int[] array = {1,2,3,4,5};
System.out.println("数组的长度为:"+array.length);
System.out.println(array[1]);
System.out.println(array[3]);
array[2] = 99;
System.out.println(array[2]);
----------------------------------------
输出结果:
数组的长度为:5
2
4
99
注意事项:
1. 使用 [ ] 按下标访问数组元素的时候,是从0号下标进行计数的。
2. 下标的访问不要超出了数组的有效范围 [0,length-1],若超出了这个有效范围就会发生下标越界异常(java.lang.ArrayIndexOutofBoundsExecption。
示例1:
int[] array = new int[]{1,2,3,4,5};
System.out.println(arr[66]);
----------------------------------------------------
执行结果:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:66
at JavaTest10.main
示例2:使用for-each遍历数组
int[] array = new int[]{1,2,3,4,5,6}
for(int x: array){
System.out.print(x+" ");
}
------------------------------------------------
输出结果:
1 2 3 4 5 6
2.数组作为方法的参数
2.1基本用法
示例:将数组所有元素相加返回和。
public static void addArray(int[] array){
int sum = 0;
for(int x: array){
sum += x;
}
return sum;
}
public static void main(String[] args){
int[] array = {1,2,3}
System.out.println(addArray(array));
}
-------------------------------
输出结果:
6
2.2 引用类型
示例1:将基本数据类型作为参数传入方法当中。
public static void func(int n){
n = 100;
System.out.println("n = "+n);
}
public static void main(String[] args){
int num = 10;
func(num);
System.out.println("num = "+num);
}
---------------------------------
输出结果:
n = 100
num = 10
在上述的代码当中,修改形参的值并没有改变实参的值。
示例2:将数组(引用)类型作为参数传入方法当中。
public static void func(int[] n){
n[0] = 100;
System.out.println("n[0] = "+n[0]);
}
public static void main(String[] args){
int[] num = {10};
func(num);
System.out.println("num[0] = "+num[0]);
}
----------------------------------
输出结果:
n[0] = 100
num[0] = 100
通过上述示例1 和示例2可以得知在方法内部修改了数组的内容,方法内部也会发生改变。数组是引用类型,数组名num在本质上只是存放了数组起始内存的地址。
2.3 初识JVM内存区域的划分
.java文件通过编译之后会生成 .class(字节码文件),通过加载到JVM实现代码的功能。
JVM 的内存大致被分为几个区域,如下图所示:
- 程序计数器(PC Register):很小的一块空间,保存下一条执行指令的地址。
- 虚拟机栈(JVM Stack):存储了局部变量表 以及其他一些信息。
- 本地方法栈(Native Method Stack):本地方法栈和虚拟机栈的作用类似,只不过保存的是Native方法的局部变量。
- 堆(Heap):JVM所管理的最大内存区域,使用new 创建的对象都是在堆上保存的。
- 方法区(Method Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即使编译器后的字节码等数据。
- 运行时常量池(Runtime Constant Pool):是方法区的一部分,存放字面量与符号引用。
对于常量池来说,在JDK1.7之前,常量池是放在方法区当中的;
在JDK1.7开始,常量池在堆中。
示例:
String str1 = "hello";
String str2 = "he" + new String("llo");
System.out.println(str1 == str2);
System.out.println(str1.equals(str2));
-------------------------------------------------
输出结果:
false
true
分析:String str1 = “hello”; 这样创建字符串是存在于常量池当中的;
String str2 = new String(“llo”); str2存在于堆当中;
“ == ” 是为了验证两个对象是否为一个(内存的地址是否相同);
str1.equals(str2) 仅仅只是比较二者之间的内容是否相同。
因此在实际情况下比较两个字符串的内容是否相同应该使用equals来判断。
关于虚拟机栈还有堆还有如下几点需要注意:
1. 局部变量和引用都保存在栈上,new出的对象也保存在堆上。
2. 堆的控件非常大,栈的空间比较小。
3. 堆是整个JVM共享一个,而栈每个线程都至少具有一份。
3.数组应用
3.1 遍历数组
- 使用for循环
- 使用for - each遍历
- 使用Array.toString(数组名)以字符串的形式输出数组
public static void myPrintOne(int[] array){
for(int i = 0;i < array.length -1;i++){
System.out.print(array[i]+" ");
}
System.out.println();
}
public static void myPrintTwo(int[] array){
for(int x: array){
System.out.print(x + " ");
}
System.out.println();
}
public static void main(String[] args) {
int[] array = new int[]{1,2,3,4,5,6,7,8,9,10};
myPrintOne(array);
myPrintTwo(array);
System.out.println(Arrays.toString(array));
}
---------------------------------------
输出结果:
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9 10
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
3.2 拷贝数组
- System.arraycopy()
- Arrays.copyOf()
- 模拟实现Arrays.copyOf()
- array.clone()
public static void myPrintOne(int[] array){
for(int i = 0;i < array.length -1;i++){
System.out.print(array[i]+" ");
}
System.out.println();
}
public static void myPrintTwo(int[] array){
for(int x: array){
System.out.print(x + " ");
}
System.out.println();
}
public static int[] myCopyOf(int[] array,int length){
int[] ret = new int[length];
for (int i = 0; i < length; i++) {
ret[i] = array[i];
}
return ret;
}
public static void main(String[] args) {
int[] array = new int[]{1,2,3,4,5,6,7,8,9,10};
int[] ret = new int[array.length];
System.arraycopy(array,0,ret,0,array.length);
System.out.println("System.arraycopy()拷贝的结果为: "+Arrays.toString(ret));
ret =Arrays.copyOf(array,array.length);
System.out.println("Arrays.copyOf()拷贝的结果为: "+Arrays.toString(ret));
ret = myCopyOf(array,array.length);
System.out.println("myCopyOf()拷贝的结果为: "+Arrays.toString(ret));
System.out.println("array.clone()拷贝的结果为: "+Arrays.toString(array.clone()));
}
------------------------------------------------------------------------------------------------
输出结果:
System.arraycopy()拷贝的结果为: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Arrays.copyOf()拷贝的结果为: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
myCopyOf()拷贝的结果为: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
array.clone()拷贝的结果为: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
System.arraycopy()和 Array.copyOf()的区别与联系:
Array.copyOf()方法调用了System.arraycopy(),在速度上略低一筹;
System.arraycopy()被 native所修饰,处理速度很快。
相比于赋值语句,Array.copyOf()是将数组进行深拷贝,即使修改原数组也不会影响到新数组。而浅拷贝(如果是两个引用同时指向同一个对象,那么通过一个引用修改当前对象的值后,那么另一个对象引用也会受到影响,这样的拷贝即为浅拷贝)与其反之。
3.3 二分查找
递归方式:
public static int binarySearch(int[] array,int key,int left,int right) {
if (left <= right) {
int mid = (left + right) / 2;
if (array[mid] == key) {
return mid;
} else if (array[mid] < key) {
return binarySearch(array, key, mid + 1, right);
} else {
return binarySearch(array, key, left, mid - 1);
}
}
return -1;
}
非递归方式:
public static int binarySearch(int[] array,int key){
int left = 0;
int right = array.length - 1;
while(left <= right){
int mid = (left + right) >>> 1;
if(array[mid] < key){
left = mid + 1;
}else if (array[mid] > key){
right = mid - 1;
}else {
return mid;
}
}
return -1;
}
4.二维数组
二维数组其本质上也是一维数组,只不过每一个元素又是一个一维数组。
基本语法
数据类型[][] 数组名称 = new 数据类型[行数][列数]{初始化数据};
打印二维数组可以使用Arrays.deepToString(数组名称)
public static void main(String[] args) {
int[][] array4 = new int[3][];
array4[0] = new int[3];
array4[1] = new int[4];
array4[2] = new int[5];
System.out.println(Arrays.deepToString(array4));
}
---------------------------------------
输出结果:
[[0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0, 0]]