目录
1. 数组的基本概念
-
1.1 数组的定义
数组:可以看成是相同类型元素的一个集合。在内存中是一段连续的空间
-
1.2 数组的创建及初始化
int[] array1 = new int[10]; // 创建一个可以容纳10个int类型元素的数组 double[] array2 = new double[5]; // 创建一个可以容纳5个double类型元素的数组 String[] array3 = new double[3]; // 创建一个可以容纳3个字符串元素的数组
数组的创建第一种为最常用类型。
数组的初始化分为动态初始化和静态初始化
动态初始化:在创建数组时,直接指定数组中元素的个数
例如:
int[] array = new int[10];
静态初始化:在创建数组时不直接指定数据元素个数,而直接将具体的数据内容进行指定
例如:
int[] array1 = new int[]{0,1,2,3,4,5,6,7,8,9};
double[] array2 = new double[]{1.0, 2.0, 3.0, 4.0, 5.0};
String[] array3 = new String[]{"hell", "Java", "!!!"};
-
1.3 数组的使用
数组中元素的访问:数组在内存中是一段连续的空间,空间的编号都是从0开始的,依次递增,该编号称为数组的下标,数组可以通过 下标访问其任意位置的元素
int[]array = new int[]{10, 20, 30, 40, 50};
System.out.println(array[0]);//输出结果为10
遍历数组 :是指将数组中的所有元素都访问一遍, 访问是指对数组中的元素进行某种操作,比如:打印。
int[] array = new int[]{10, 20, 30, 40, 50};
for(int i = 0; i < 5; i++){
System.out.println(array[i]);
}
获取数组长度:在数组中可以通过 数组对象.length 来获取数组的长度,也可以使用 for-each 遍历数组
int[] array = {1, 2, 3};//for each遍历数组
for (int x : array) {
System.out.println(x);
}
2. 数组是引用类型
-
2.1 数组在JVM中的分布
JVM主要有本地方法栈,方法区,堆,虚拟机栈,程序计数器等。数组名称存储在栈中,变量存储在堆中
-
2.2 基本类型变量与引用类型变量
基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值;
引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址。
public static void func() {
int a = 10;
int b = 20;
int[] arr = new int[]{1,2,3};
}
在上述代码中,a、b、arr,都是函数内部的变量,因此其空间都在main方法对应的栈帧中分配。
a、b是内置类型的变量,因此其空间中保存的就是给该变量初始化的值。
array是数组类型的引用变量,其内部保存的内容可以简单理解成是数组在堆空间中的首地址。
3. 数组的应用场景
-
3.1 保存数据
public static void main(String[] args) {
int[] array = {1, 2, 3};
for(int i = 0; i < array.length; ++i){
System.out.println(array[i] + " ");
}
}
-
3.2 作为函数的参数
传基本数据类型
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;
}
传引用数据类型:发现在func方法内部修改数组的内容, 方法外部的数组内容也发生改变. 因为数组是引用类型,按照引用类型来进行传递,是可以修改其中存放的内容的。
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;
}
总结: 所谓的 "引用" 本质上只是存了一个地址. Java 将数组设定成引用类型, 这样的话后续进行数组参数传参, 其实 只是将数组的地址传入到函数形参中。这样可以避免对整个数组的拷贝(数组可能比较长, 那么拷贝开销就会很大).
-
3.3 作为函数的返回值
//斐波那契数列
public class TestArray {
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.println(array[i]);
}
}
}
4. 数组的相关练习
-
4.1 数组转字符串
import java.util.Arrays
int[] arr = {1,2,3,4,5,6};
String newArr = Arrays.toString(arr);
System.out.println(newArr);
// 执行结果
[1, 2, 3, 4, 5, 6]
-
4.2 数组拷贝
public static void main(String[] args) {
int[] array={1,2,3};
//接收拷贝的数组
int[] ret=copy(array);
//打印被接收的数组
System.out.println(Arrays.toString(ret));
System.out.println("=====分割线========");
//数组拷贝的第一个方法
//对数组进行扩容,直接*2
int[] ret1=Arrays.copyOf(array,array.length*2);
System.out.println(Arrays.toString(ret1));
//数组拷贝的第二个方法
//直接拷贝数组的下标,从1下标到3下标,[1,3)左闭右开的区间
int[] ret2=Arrays.copyOfRange(array,1,3);
System.out.println(Arrays.toString(array));
}
//数组的拷贝
//返回int型数组
public static int[] copy(int[] array){
//为数组提前申请空间
int[] copyArray=new int[array.length];
for(int i=0;i<array.length;i++){
copyArray[i]=array[i];
}
return copyArray;
}
-
4.3 求数组中元素是平均值
public static void main(String[] args) {
int[] array = {1,2,3,4,5,6};
System.out.println(avg(array));
}
public static double avg(int[] array) {
int sum = 0;
//for each语句
for (int x : array) {
sum += x;
}
return (double)sum / (double)array.length;
}
// 结果
3.5
-
4.4 查找数组中指定元素(顺序查找)
public static void main(String[] args) {
int[] array = {1,3,5,7,9};
//在上面数组中找到5
System.out.println(find(array, 5));
}
public static int find(int[] array, int data) {
for (int i = 0; i < array.length; i++) {
if (array[i] == data) {
return i;
}
}
return -1; // 表示没有找到
}
-
4.5 查找数组中指定元素(二分查找)
二分查找仅适用于有序数组
public static void main(String[] args) {
//给定一个数组
int[] array = {1,2,3,4,5,6};
System.out.println(find(array, 6));
}
public static int find(int[] array, int toFind) {
int left = 0;
int right = array.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (toFind < arr[mid]) {
// 去左侧区间找
right = mid - 1;
} else if (toFind > arr[mid]) {
// 去右侧区间找
left = mid + 1;
} else {
// 相等, 说明找到了
return mid;
}
}
// 循环结束, 说明没找到
return -1;
}
-
4.6 数组排序(冒泡排序)
冒泡排序就是两个相邻的元素依次比较,将大的替换到数组后面,直到所有的元素都排列好
public static void main(String[] args) {
int[] array = {1, 3, 2, 4};
compare(array);
System.out.println(Arrays.toString(arr));
}
public static void compare(int[] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = 1; j < arr.length-i; j++) {
if (arr[j-1] > arr[j]) {
int tmp = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = tmp;
}
}
} // end for
} // end compare
// 执行结果
[1,2,3,4]
相比于冒泡排序java 中内置了更高效的排序算法
public static void main(String[] args) {
int[] array = {1,3,2,4};
Arrays.sort(array);
System.out.println(Arrays.toString(array));
}
-
4.7 逆序数组
方法:设定两个下标, 分别指向第一个元素和最后一个元素. 交换两个位置的元素,然后让前一个下标自增, 后一个下标自减, 循环继续即可
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4};
reverse(arr);
System.out.println(Arrays.toString(arr));
}
public static void reverse(int[] arr) {
int left = 0;
int right = arr.length - 1;
while (left < right) {
int tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
}
5. 二维数组
格式:数据类型[][] 数组名称 = new 数据类型 [行数][列数] { 初始化数据 };
例如:
int[][] arr = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};