目录
(3)Arrays.deepToString(二维数组名);
(2)Arrays.copyOfRange(原数组名,起始下标,终止下标);
(4)System.arraycopy(原数组名,原数组的起始下标,拷贝的数组名,拷贝数组的起始下标,需要拷贝的长度);
上节我们说到方法的使用,这一节我们来说一说关于数组的使用。数组让我们能 "批量" 创建相同类型的变量,然后存放在一起。
一、数组的基本用法
1、创建数组
语法格式如下:
数据类型[] 数组名称 = { 初始化数据 };
数据类型[] 数组名称=new 数据类型[数组长度];
数据类型[] 数组名称 = new 数据类型 [] { 初始化数据 };
例:
2、数组的使用
数组使用这块,Java提供了一个非常便捷的方法——
如果给一个数组arr[]赋了确定的初始值,则用 arr.length 即可快捷获取改数组的元素个数。
int[] arr = {1, 2, 3};
System.out.println("length: " + arr.length);// 执行结果 length:3
System.out.println(arr[1]); // 执行结果: 2
System.out.println(arr[0]); // 执行结果: 1
注:[ ]获取元素时从0开始,到 length-1 为止,超过这个范围,会出现数组越界,从而程序报错无法继续执行。
3、遍历数组
顾名思义,将数组中每个元素打印出来。
·for 循环遍历数组
int[] arr = {1, 2, 3};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
// 执行结果
1
2
3
·使用 for-each 遍历数组
for-each 是 for 循环的另外一种使用方式。能够更方便的完成对数组的遍历。 可以避免循环条件和更新语句写错。
for-each 相当于for循环的增强版,此时语法格式为:
for(元素类型 元素变量 : 遍历对象){
引用了x的java语句;
}
int[] arr = {1, 2, 3};
for (int x : arr) {
System.out.println(x);
}
// 执行结果
1
2
3
二、数组作为参数
1、认识引用类型
我们先来对比两个例子。
public static void main(String[] args) {
int num = 0;
func(num);
System.out.println("num = " + num);
}
public static void func(int x) {
x = 10;
System.out.println("x = " + x);
}
// 执行结果
x = 10
num = 0
此时,修改形参x的值,num的值却没有改变。
而如果以数组传参,
public static void main(String[] args) {
int[] arr = {1, 2, 3};
func(arr);
System.out.println("arr[0] = " + arr[0]);
}
public static void func(int[] a) {
a[0] = 10;
System.out.println("a[0] = " + a[0]);
}
// 执行结果
a[0] = 10
arr[0] = 10
此时,在方法内部修改了数组内容,函数外部也发生了变化。
2此时数组名 arr 是一个 "引用" 。
2、认识null
3、认识JVM内存区域划分
JVM的内存被划分为了几个区域:
程序计数器(PC Register):保存下一条执行的指令的地址。
虚拟机栈(JVM Stack):重点是存储局部变量表,我们刚才创建的int[]arr这样的存储地址的引用就是在这里保存。
本地方法栈(Native Method Stack):本地方法栈与虚拟机栈的作用类似。只不过保存的内容是Native方法的局部变量。
堆(Heap):JVM所管理的最大内存区域。使用 new 创建的对象都是在堆上保存(例如前面的newint[]{1,2,3})。
方法区(Method Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法编译出的的字节码就是保存在这个区域。
运行时常量池(Runtime Constant Pool):是方法区的一部分,存放字面量(字符串常量)与符号引用。
Native 方法 :JVM 是一个基于 C++ 实现的程序 。 在 Java 程序执行过程中 , 本质上也需要调用 C++ 提供的一些函数进行和操作系统底层进行一些交互。 因此在 Java 开发中也会调用到一些 C++ 实现的函数。这里的 Native 方法就是指这些 C++ 实现的 , 再由 Java 来调用的函数。
总结:1、局部变量和引用保存在栈上,new 出的对象保存在堆上。(如下图所示)
2、堆的空间非常大,栈的空间比较小。
三、认识二维数组
1、基本语法
数据类型 [][] 数组名称 = new 数据类型 [ 行数 ][ 列数 ] { 初始化数据 };
![](https://i-blog.csdnimg.cn/blog_migrate/50d0e98ed534e2772290e81f347abc7b.png)
2、循环输出二维数组的方法
(1)使用 for 循环嵌套
如上图所示, i 为数组一维的长度,j 为数组二维的长度。画个图,就清晰明多了:
(2)使用 for-each 循环输出
如下图,如果array是二维数组,array中的每个元素就是一维数组。则外层 for 循环的 ret 就是拿到了 array 中的每个元素,则ret就是一维数组,内部循环是拿到 ret 一维数组中的每个元素。
注:除了正常的输出,还可以用自带的Arrays方法 快捷得到二维数组的元素值——
(3)Arrays.deepToString(二维数组名);
调用该方法后打印,最后会以字符串的形式输出。
int[][] array= {{1,2,3}, {4,5,6}};
System.out.println(Arrays.deepToString(array));
//运行结果
[[1, 2, 3], [4, 5, 6]]
四、部分Arrays方法
那么问题来了,还有其他便捷的处理数组元素的方法吗?
答案是当然有,这里列举几个常用的方法——
1、Arrays.toString(数组名);
这个与二维数组的输出有异曲同工之妙,就是将一维数组以字符串的形式输出。
int[] array={1,2,3,4,5};
System.out.println(Arrays.toString(array));
//运行结果
[1, 2, 3, 4, 5]
2、Arrays.sort(数组名);
顾名思义,就是将数组自动按从小到大顺序排序。(向冒泡法say goodbye~)
int[] array = {1,45,23,73,57,25,46};
Arrays.sort(array);
System.out.println(Arrays.toString(array));
//运行结果
[1, 23, 25, 45, 46, 57, 73]
3、Arrays.binarySearch(数组名,值);
实现二分查找功能,查找数组中有的数值,并返回其数组下标。
注:二分查找要求数组中元素必须是有序递增的,否则返回值会出问题。
int[] array = {1,3,5,7,9,13,15};
System.out.println(Arrays.binarySearch(array,3));
//运行结果
1
4、Arrays.fill(数组名,值);
【 或 Arrays.fill(数组名,数组起始下标,数组终止下标,值) 】
就是将某个值填入数组中,或者定向填入数组的某个位置中。
第一种用法:
int[] array = {1,45,23,73,57,25,46};
Arrays.fill(array,99);
System.out.println(Arrays.toString(array));
//运行结果
[99, 99, 99, 99, 99, 99, 99]
第二种:
int[] array = {1,45,23,73,57,25,46};
Arrays.fill(array,2,5,99);
System.out.println(Arrays.toString(array));
//运行结果
[1, 45, 99, 99, 99, 25, 46]
由此可见,第二个引用是左闭右开的 [2,5),并且注意输入的参数是直接从1开始的索引值,而非数组下标值!!!
5、Arrays方法之数组的拷贝
Arrays提供了不少数组拷贝的方法——
(1)Arrays.copyOf(原数组名,拷贝的长度);
int[] array = {1,45,23,73,57,25,46};
int[] array2=Arrays.copyOf(array,2);
System.out.println(Arrays.toString(array2));
//运行结果
[1, 45]
如上例子,可以只拷贝部分数组元素。
当然,也可以扩容,只需将第二个参数设置大于数组长度即可。如下例——
int[] array = {1,45,23,73,57,25,46};
int[] array2=Arrays.copyOf(array,10);
System.out.println(Arrays.toString(array2));
//运行结果
[1, 45, 23, 73, 57, 25, 46, 0, 0, 0]
(2)Arrays.copyOfRange(原数组名,起始下标,终止下标);
注:这里的起始位置指的是数组下标的起始位置,而不是数组长度的起始!并且取值范围是
[起始位置,终止位置)。如下例:
int[] array = {1,45,23,73,57,25,46};
int[] array2=Arrays.copyOfRange(array,2,5);
System.out.println(Arrays.toString(array2));
//运行结果
[23, 73, 57]
(3)数组名.clone();
这个不用传参,直接克隆,然后用新数组接收即可,比较便捷。
int[] array = {1,45,23,73,57,25,46};
int[] array2=array.clone();
System.out.println(Arrays.toString(array2));
//运行结果
[1, 45, 23, 73, 57, 25, 46]
(4)System.arraycopy(原数组名,原数组的起始下标,拷贝的数组名,拷贝数组的起始下标,需要拷贝的长度);
参数确实比较多,多用几遍就能理解了,上例子:
int[] array = {1,45,23,73,57,25,46};
int[] array2=new int[array.length];
System.arraycopy(array,2,array2,3,4);
System.out.println(Arrays.toString(array2));
//运行结果
[0, 0, 0, 23, 73, 57, 25]
五、数组应用经典例题
1、冒泡排序
将数组中的元素经过比较后,按升序的顺序输出。
import java.util.Arrays;
class testdemo {
public static void main(String[] args) {
int[] array = {3,26,17,38,16,42,33};
bubbleSort(array);
}
public static void bubbleSort(int[] array){
for (int i = 0; i < array.length-1; i++) {//外层循环代表要比较array.length-1趟
boolean flag=false;
for (int j = 0; j < array.length-1-i; j++) { //内层循环为每趟要进行比较的数
if (array[j]>array[j+1]){
int tmp =array[j];
array[j]=array[j+1];
array[j+1]=tmp;
flag =true;
}
}
if (flag==false)
break;
}
System.out.println(Arrays.toString(array));
}
}
//运行结果
[3, 16, 17, 26, 33, 38, 42]
注:flag是用来优化代码的,只要有一趟中没有交换,说明数组已经有序了,即可直接退出循环,能让程序效率提高。
2、二分查找
(查找的数组必须是有序的)
class testdemo {
public static void main(String[] args) {
int[] array = {1,3,5,7,9,13};
int key =13;
System.out.println(binarySearch(array, key));
}
public static int binarySearch(int[] array,int key){
int left =0;
int right=array.length-1;
while(left<=right) {
int mid=(left+right)/2;
if (key>array[mid]) {
left=mid+1;
} else if (key<array[mid]){
right=mid-1;
}else {
return mid;
}
}
return -1;
}
}
//运行结果
5
我们下一节类与对象见!
to be continue →
欢迎大家互相探讨交流补充 欢迎捉虫!