目录
1.数组的基本概念
数组:可以看作是相同类型元素的一个集合,在内存中是一段连续的空间
int n = 10;
int[] array4 = new int[n];//
1.1 数组的初始化
数组的初始化主要分为动态初始化和静态初始化。
1.动态初始化:在创建数组时,直接指定数组中元素的个数
int[] array3=new int[10];//这种定义方式并没有初始化当前指定的值,默认都是0
2.静态初始化:在创建数组时不直接指定数组元素个数,而直接将具体的数据进行指定
int[] array={1,2,3,4,5,6};//简化形式
int[] array2=new int[] {1,2,3,4,5,6};
new是一个关键字,一般用来new对象,即数组是一个对象,Java当中一切皆对象
注意:
- 静态初始化虽然没有指定数组的长度,编译器在编译时会根据{}中元素个数来确定数组的长度
- 静态初始化时,{}中数据类型必须与[ ]前数据类型一致
- 静态初始化可以简写,省区后面的new arr[]
- 数组也可以按照C语言格式创建,不推荐
- 静态和动态初始化也可以分为两步,但是省略格式不可以
int[] arr2;
arr2=new int[]{10,20,30};
//注意省略格式不可以拆分,否则编译失败
//int[] arr3;定义数组
//arr3={1,2,3};初始化
//对数组进行整体的初始化,只能是在定义这个数组的时候
- 如果没有对数组进行初始化,数组中元素有其默认值
- 如果数组中存储元素类型为引用类型,默认值为null
1.2 数组的使用
遍历数组:
int[] nums={1,2,3,4,5,6};
for (int i = 0; i < nums.length; i++) {//通过.length来获取数组的长度
System.out.print(nums[i]+" ");//1 2 3 4 5 6
}
也可以使用for-each遍历数组: 能够更方便地完成对数组的遍历,可以避免循环条件和更新语句写错。
//for-each循环
//增强for循环
//这种循环不需要下标
for (int x : nums) {//(元素:数组名)
System.out.print(x + " ");//1 2 3 4 5 6
}
//操作数组的工具类 Arrays
//先导包 import java.util.Arrays;
String ret=Arrays.toString(nums);//使用Array的toString方法,把传入的参数nums表示的数组,以字符串的形式输出
System.out.println(ret);//[1, 2, 3, 4, 5, 6]
2.数组是引用类型
2.1 初始JVM的内存分布
JVM中有本地方法栈和Java虚拟机栈,2个栈的区别为:
本地方法栈:会执行一些底层是由C/C++代码实现的方法
Java虚拟机栈:“平时所说的栈”
内存是一段连续的存储空间,主要用来存储程序运行时数据的。比如:
- 程序运行时代码需要加载到内存
- 程序运行产生的中间数据要存放在内存
- 程序中的常量也要保存
- 有些数据可能需要长时间存储,而有些数据当方法运行结束后就要被销毁
如果对内存中存储的数据不加区分随意存储,那对内存管理起来将会非常麻烦,因此JVM也对所使用的内存按照功能的不同进行了划分:
2.2 基本变量与引用变量
基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值;
而引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址,引用指向对象,比如一个数组这个引用指向了一个数组对象
引用变量并不直接存储对象本身,可以简单理解为存储的是对象在堆中空间的起始地址,通过该地址,引用变量可以操作对象。有点类似C语言中的指针,但是Java中引用要比指针的操作更简单
当2个引用同时指向一个对象的时候(即arr1=arr2),通过任何一个引用都能修改这个对象的值
2.3 认识null
public class test {
public static void main(String[] args) {
int[] array=null;//array不指向任何对象
System.out.println(array.length);
//NullPointerException
}
}
null在Java中表示“空引用”,也就是不指向对象的引用
null的作用类似于C语言中的NULL(空指针),都是表示一个无效的内存位置,因此不能对这个内存进行任何读写操作,一旦尝试读写,就会抛出NullPointerException
注意:Java中并没有约定null和0号地址的内存有任何关系。
对象不能指向对象,只有引用可以指向对象。
3.数组的应用场景
3.1 作为函数的参数
import java.util.Arrays;
public class test {
//需求:把数组中的每个数据扩大2倍
public static int[] func(int[] array) {
int[] ret = new int[array.length];//与C语言不同,可以是变量
for (int i = 0; i < array.length; i++) {
ret[i] = array[i] * 2;
}
return ret;
}
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5};
int[] tmp=func(array);
System.out.println(Arrays.toString(array));//[1, 2, 3, 4, 5]
System.out.println(Arrays.toString(tmp));//[2, 4, 6, 8, 10]
}
}
import java.util.Arrays;
public class test {
public static void func(int[] array){
array=new int[] {9,8,7,6,5};//又创建了一个对象
}
public static void main(String[] args) {
int[] array={1,2,3,4,5};
func(array);
System.out.println(Arrays.toString(array));//[1, 2, 3, 4, 5]
}
}
在方法内部修改数组的内容,方法外部的数组内容也发生改变。因为数组是引用类型,按照引用类型来进行传递,是可以修改其中存放的内容的 。
总结:
- 通过数组名直接打印数组数据和直接使用toString方法都只能打印出数组的地址,因此需要使用Arrays的toString方法来打印数组中的数据
- int[] array=null;代表这个引用不指向任何对象
- array1=array2;代表array1这个引用指向了array2这个引用指向的对象
- 一个引用不可能同时指向2个对象
3.2 作为函数的返回值
比如:获取斐波那契数列的前N项
public class test {
public static int[] fib(int n) {//返回一个数组
if (n <= 0) {
return null;
}
int[] array = new int[n];//创建数组
array[0] = array[1] = 1;
for (int i = 2; i < n; i++) {
array[i] = array[i - 1] + array[i - 2];
}
return array;
}
public static void main(String[] args) {
int[] array = fib(10);
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
}
4. 数组练习
4.1 数组转字符串
import java.util.Arrays;
public class Shift {
public static void main(String[] args) {
int[] array = {21, 12, 13, 54, 5};
System.out.println(myToString(array));//打印
// Arrays.sort(array);//自动排序
Arrays.sort(array, 0, 2);//区间排序[0,2)——>0,1
System.out.println(myToString(array));
int[] array2 = {};
System.out.println(Arrays.toString(array2));//[]
}
public static String myToString(int[] array) {//相当于Arrays.toString
if (array == null) {
return "null";
}
if (array.length == 0) {
return "[]";
}
String ret = "[";
for (int i = 0; i < array.length; i++) {
ret += array[i];
if (i != array.length - 1) {
ret += ", ";
}
}
ret += "]";
return ret;
}
}
4.2 二分查找
import java.util.Arrays;
public class test {
public static int binarySearch(int[] array, int key) {//此函数Arrays类中存在
int left = 0;
int right = array.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] == key) {
return mid;
} else if (array[mid] > key) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1;//没有该数字
}
public static void main(String[] args) {
int[] array = {1, 2, 43, 46, 5};
Arrays.sort(array);//默认从小到大排序
System.out.println("排序后的数组:"+Arrays.toString(array));//排序后的数组:[1, 2, 5, 43, 46]
int index = binarySearch(array, 3);
System.out.println(index);//-1
}
}
4.3 冒泡排序(优化后的)
import java.util.Arrays;
public class test {
public static void bubbleSort(int[] array) {
for (int i = 0; i < array.length - 1; i++) {//冒泡排序
//i代表趟数
boolean flg = false;
for (int j = 0; j < array.length - 1 - i; j++) {//第一处优化——-i
if (array[j] > array[j + 1]) {
int tmp = array[j];
array[j] = array[j + 1];
array[j + 1] = tmp;
flg = true;
}
}
if (flg == false) {//第二处优化——判断
return;
}
}
}
public static void main(String[] args) {
int[] array = {91, 29, 34, 56, 87};
bubbleSort(array);
System.out.println(Arrays.toString(array));//[29, 34, 56, 87, 91]
}
}
4.4 拷贝数组
Java中的内置函数Arrays.copyOf(array,array.length);可以对数组进行拷贝,也可以进行扩容(后面的元素都是0)
import java.util.Arrays;
public class test {
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5};
int[] copy = Arrays.copyOf(array, array.length * 2);
System.out.println(Arrays.toString(copy));//[1, 2, 3, 4, 5, 0, 0, 0, 0, 0]
}
}
也可以拷贝一部分
int[] copy=Arrays.copyOfRange(array,1,3);//1-3下标
System.out.println(Arrays.toString(copy));//[2, 3]
其他拷贝方法:
int[] copy=new int[array.length];
System.arraycopy(array,0,copy,0,array.length);//arraycopy是本地方法,C/C++实现,速度较快
System.out.println(Arrays.toString(copy));//[1, 2, 3, 4, 5]
Java中还有equal函数,fill函数:
import java.util.Arrays;
public class test {
public static void main(String[] args) {
int[] array1 = {1, 2, 3, 4, 5};
int[] array2 = {1, 2, 3, 4, 5};
System.out.println(array1 == array2);//false
boolean flg = Arrays.equals(array1, array2);//一个数一个数比较大小
System.out.println(flg);//true
int[] ret = new int[10];
Arrays.fill(ret, -1);//将数组元素初始化为-1
System.out.println(Arrays.toString(ret));//[-1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
//当然也可以指定范围
Arrays.fill(ret, 1, 3, 2);
System.out.println(Arrays.toString(ret));//[-1, 2, 2, -1, -1, -1, -1, -1, -1, -1]
}
}
4.5 内置排序函数
import java.util.Arrays;
public class Shift {
public static void main(String[] args) {
int[] array = {21, 12, 13, 54, 5};
System.out.println(Arrays.toString(array));//打印
// Arrays.sort(array);//自动排序
Arrays.sort(array, 0, 2);//区间排序[0,2)——>0,1
System.out.println(Arrays.toString(array));
}
}
5. 二维数组
import java.util.Arrays;
public class test {
public static void main(String[] args) {
int[][] array = {{1, 2, 3}, {4, 5, 6}};
int[][] array2 = new int[][]{{1, 2, 3}, {4, 5, 6}};//与C语言定义方式不同
int[][] array3 = new int[2][3];//二维数组是一个特殊的一维数组
System.out.println(array[0]);//[I@1b6d3586
System.out.println(array[1]);//[I@4554617c
System.out.println(array.length);//2(行)
System.out.println(array[0].length);//3(列)
System.out.println(array[1].length);//3(列)
System.out.println(Arrays.toString(array[0]));//[1, 2, 3]
System.out.println(Arrays.toString(array[1]));//[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();
//1 2 3
//4 5 6
}
for (int[] tmpArray : array) {//第二种打印数组方法
for (int x : tmpArray) {
System.out.print(x + " ");
}
System.out.println();
//1 2 3
//4 5 6
}
String ret = Arrays.deepToString(array);//第三种打印数组方法
System.out.println(ret);//[[1, 2, 3], [4, 5, 6]]
}
}
注意:Java当中的二维数组不能省略行,可以省略列
public class Test {
public static void main(String[] args) {
int[][] array = new int[2][];//不规则二维数组
array[0] = new int[3];
array[1] = new int[5];
for (int[] tmp : array) {
for (int x : tmp) {
System.out.print(x + " ");
}
System.out.println();
//0 0 0
//0 0 0 0 0
}
}
}