Bootstrap

初识java - 数组的定义与使用

一,数组的基本概念

1.1什么数组

数组:可以看成是相同类型元素的一个集合。在内存中是一段连续的空间。

1.2数组的创建及初始化

1.2.1数组的创建

T[] 数组名 = new T[N];

  • T 表示数组中元素的数据类型
  • T[] 表示数组的数据类型
  • N 表示数组长度(最大存放数据的个数)

例:
int[] array = new int[5];//创建了一个能容纳5个元素类型为int的数组
double[] array = new double[5];//创建了一个能容纳5个元素类型为double的数组
String[] array = new String[5];//创建了一个能容纳5个元素类型为String的数组 (注意:是String,不是string)

1.2.2数组的初始化

数组的初始化分为动态初始化静态初始化

动态初始化:在创建数组时直接指定元素个数。
int[] array = new int[10];
double[] array = new double[10];
String[] array = new String[10];

  • 注意如果没有对数组进行初始化,数组中元素有其默认值:
    在这里插入图片描述
    在这里插入图片描述
    引用数据类型的默认值为null,如String
    在这里插入图片描述

静态初始化:在创建数组时不直接指定数据元素个数,而直接将具体的数据内容进行指定。
int[] array = {1,2,3,4,5};//一般用这种方式进行静态初始化
int[] array = new int[]{1,2,3,4,5};
在这里插入图片描述
如果写成int[] array = new int[5]{1,2,3,4,5};编译器会报错
在这里插入图片描述
在这里插入图片描述

1.2.3二维数组的定义与使用
1.2.3.1二维数组的定义

T[][] 数组名= new T[M][N];

  • T 表示数组中元素的数据类型
  • T[][] 表示数组的数据类型
  • M 表示数组有几行(只是这样表达,但是在内存上存储并不是这样的)
  • N表示数组有几列(只是这样表达,但是在内存上存储并不是这样的)

【一张图带你了解二维数组】

二维数组是一个特殊的一维数组在这里插入图片描述

1.2.3.2二维数组的使用
	public static void main(){
		int[][] array = {{1,2,3},{4,5,6}};
		printArray(array);
	}
	//打印二维数组
    public static void printArray(int[][] array){
        //外层for循环为行
        for (int i = 0; i < array.length; i++) {
            //内层for循环为列
            for (int j = 0; j < array[i].length; j++) {
                System.out.print(array[i][j] + " ");
            }
            //换行
            System.out.println();
        }
	---------
	1 2 3
	4 5 6
 public static void main(String[] args) {
        //二维数组
        int[][] array = {{1,2,3},{1,2,3}};
        //Arrays中打印二维数组的方法
        System.out.println(Arrays.deepToString(array));
        for (int i = 0; i < array.length; i++) {
            System.out.println(Arrays.toString(array[i]));
        }

    }
    -----------
    [[1, 2, 3], [1, 2, 3]]
	[1, 2, 3]
	[1, 2, 3]
1.2.3.3不规则二维数组
public static void mainRandom(String[] args) {
        //不规则二维数组
        int[][] array = {{1,2},{3,4,5}};
        printArray(array);
        System.out.println(Arrays.deepToString(array));
    }
    ----------
    1 2 
	3 4 5 
	[[1, 2], [3, 4, 5]]

在这里插入图片描述

1.3数组的使用

数组是在内存中一块连续的空间中进行存储的,可以通过下标(索引)来对其中的元素进行访问,数组的其实下标(索引)为0。当然也可以通过下标(索引)对数组元素进行修改。
在这里插入图片描述

例:访问元素
int[] array = {1,2,3,4,5};
我想拿到数组中的数字3就可以通过
int number = array[2];
在这里插入图片描述
例:修改元素
在这里插入图片描述

1.4数组的遍历

int[] array = {1,2,3,4,5};
//for循环遍历数组
for (int i = 0; i < array.length; i++) {
 System.out.print(array[i] +" “);
}
System.out.println(); //隔行
//增强for循环遍历 – foreach
for (int x:array) {
 System.out.print(x +” ");
}
System.out.println(); //隔行
//java.uitl.Arrays包下的方法遍历数组
System.out.println(Arrays.toString(array));
在这里插入图片描述

二,数组是引用类型

2.1初始JVM的内存分布

在这里插入图片描述

  • 程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址。
  • java栈(虚拟机栈)(JVM Stack): 与方法调用相关的一些信息,每个方法在执行时,都会先创建一个栈帧,栈帧中包含有:局部变量表、操作数栈、动态链接、返回地址以及其他的一些信息,保存的都是与方法执行时相关的一些信息。比如:局部变量。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了。
  • 本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部变量. 在有些版本的 JVM 实现中(例如HotSpot), 本地方法栈和虚拟机栈是一起的。
  • 堆(Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2,3} ),堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销
    毁。
  • 方法区(Method Area): 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据. 方法编译出的的字节码就是保存在这个区域。
      现在我们只简单关心虚拟机栈这两块空间,后序JVM中还会更详细介绍。

2.2 基本类型变量与引用类型变量的区别

基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的
而引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址

在这里插入图片描述
   从上图可以看到,引用变量并不直接存储对象本身,可以简单理解成存储的是对象在堆中空间的起始地址。通过该地址,引用变量便可以去操作对象。类似C语言中的指针,但是Java中引用要比指针的操作更简单。

2.3数组作为参数在传参上的数据变动

在这里插入图片描述
在这里插入图片描述

三,数组的应用场景(cv程序猿)

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
  • 参数传数组类型(引用数据类型)
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

3.3 作为函数的返回值

  • 比如:获取斐波那契数列的前N项
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.1 冒泡排序

 public static void main(String[] args) {
        //冒泡排序
        int[] array = {1, 3 , 2 , 4 ,5 ,6 ,7 , 8 ,9};
        newBubSort(array);
        System.out.println(Arrays.toString(array));
    }
    //冒泡排序优化版
    public static void newBubSort(int[] array){
        //判断数组是否已经有序
        int boolSort = 0;
        //循环计数
        int count = 0;
        for (int i = 0; i < array.length - 1; i++) {
            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;
                    boolSort++;
                }
                count++;
            }
            //判断数组是否在第一次循环后是否有序
            if(boolSort <= 1){
                break;
            }
        }
        System.out.println(count);
    }
    //冒泡排序
    public static void bubSort(int[] array){
        //循环计数
        int count = 0;
        for (int i = 0;i < array.length - 1;i++){
            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;
                }
                count++;
            }
        }
        System.out.println(count);
    }

4.2 逆置数组

public static void main(String[] args) {
        //逆置数组
        int[] array = {1,2,3,4,5,6,7,8,9};
        reverseArray(array);
        System.out.println(Arrays.toString(array));
    }
    //逆置数组
    public static void reverseArray(int[] array){
        int left = 0;//左边界下标
        int right = array.length - 1;//右边界下标
        while(left < right){
            int tmp = array[left];
            array[left] = array[right];
            array[right] = tmp;
            left++;
            right--;
        }
    }

4.3 偶先奇后

public static void main(String[] args) {
        //将数组中偶数先输出,奇数后输出
        int[] array = {1,3,5,7,9};
        arrayOddEven(array);
        System.out.println(Arrays.toString(array));
    }
    //奇,偶交换
    public static void arrayOddEven(int[] array){
        int left = 0;
        int right = array.length - 1;
        while(left < right){
            //left找奇数   right找偶数
            if(array[left] % 2 == 0 && array[right] % 2 != 0){
                left++;
                right--;
            }else if(array[left] % 2 == 0 ){
                left++;
            }else if(array[right] % 2 != 0){
                right--;
            }else{
                int tmp = array[left];
                array[left] = array[right];
                array[right] = tmp;
            }
        }
    }

4.4数组拷贝

 public static void main(String[] args) {
        //数组的拷贝
        //有三种
        int[] array = {1,2,3,4,5};

        //第一种常用拷贝方式
        /* //[I@1b6d3586
        //[I@4554617c
        //int[] arr = cpySArray(array);
        //System.out.println(arr);
        //System.out.println(Arrays.toString(arr));

        //[I@1b6d3586
        //[I@1b6d3586
        //int[] arr = cpyQArray(array);
        //System.out.println(arr);
        //System.out.println(Arrays.toString(arr));*/


        //第二种java.util.Arrays包下的copyOf方法或者copyOfRang方法
        /*//返回一个从数组array中拷贝了array.length长度的数组
        int[] arr1 = Arrays.copyOf(array, array.length);
        //同时也可以实现扩容
        int[] arr3 = Arrays.copyOf(array,array.length*2);
        System.out.println(Arrays.toString(arr3));
        //返回一个指定拷贝位置的数组
        int[] arr2 = Arrays.copyOfRange(array, 2, 4);
        System.out.println(Arrays.toString(arr2));*/

        //第三种由native修饰的方法 -- 一般都是由c/c++已经实现了的方法
        //优点速度快
        /*int[] arr = new int[array.length];
        System.arraycopy(array,0,arr,0,arr.length);
        System.out.println(Arrays.toString(arr));*/

        //第四种克隆拷贝 
        /*int[] arr = array.clone();
        System.out.println(array);
        System.out.println(arr);
        arr[0] = 10;
        System.out.println(Arrays.toString(array));
        System.out.println(Arrays.toString(arr));*/
    }
    //第一种常用拷贝
    public static int[] cpySArray(int[] array){
        // 直接在堆里开辟一块内存来存放数据
        int[] arrayCpy = new int[array.length];
        for (int i = 0; i < array.length; i++) {
            arrayCpy[i] = array[i];
        }
        return arrayCpy;
    }
    public static int[] cpyQArray(int[] array){
        int[] arrayCpy = array;
        return arrayCpy;
    }
;