目录

前言

一、数组的概念

二、如何使用数组

1.Java中数组的创建以及初始化

 2.数组的使用

2.1 用for循环打印(和C语言的原理是一样的)

2.2 用for each打印

2.3 用库函数打印

三、数组是引用类型

3.1 简单的认识JVM的内存分布

3.2 认识null

3.3 用两个练习题来加深数组引用的理解 

3.3.1 代码如下:

3.3.2 代码如下: 

 四、二维数组

五、练习题练习(冒泡排序和二分查找)

5.1 冒泡排序

 5.2 二分查找

总结


前言

语言的不同,表达方式也会有所不同,下面我们就来看看Java语言中数组是怎样的一种结构。

一、数组的概念

用最简单的一句话来说:数组(Array)是用于储存多个相同类型数据的集合。在内存中是一段连续的空间。

二、如何使用数组

1.Java中数组的创建以及初始化

代码如下:

public class Test1 {
    public static void main(String[] args) {
        //Java中有三种数组创建的方式
        //new是Java中的一个关键字,用来创建对象(下面以及后面的类会详细介绍)
        int[] array  = {1,2,3};
        int[] array1 = new int[3];
        int[] array2 = new int[]{7,8,9};
        System.out.println(array);//会打印 [I@1b6d3586
    }
}

下面画图来解释上面三种创建方式在内存中的有着怎样的不同:

java数据结构中的数组 java数组详解_eclipse

用int[] array  = {1,2,3};这一段代码块进行详解:

栈区就是所谓的虚拟机栈(下面有说),当执行一个mian方法的时候,就会在栈区中开辟一个main方法的栈帧,在堆区中也会开辟一块内存,用来存放array中的数组元素(对象,对象的内存在堆上),而array中存了数组元素(对象)的地址,array指向了堆区上的对象。

由上面的代码可知,当我们打印array时,会出现一串字符串[I@1b6d3586([:表示是一个数组,I:表示是数组的元素是整数,@后面的数字表示地址的哈希值,可以理解为地址)。虽然array的定义是一个变量,但是呢里面存了一个地址,那我们就把存了地址的变量叫做引用变量或者叫做引用,而array后面的数组元素就是一个对象。总结为一句话就是,在引用变量当中存了对象的地址,引用变量指向了(引用了)一个对象。(后面类和对象会详细解释)

如果没有对数组进行初始化,那么数组中的元素就会为默认值,数组类型的不同,默认值也会不同,如下表: 

double[] array3 = new double[3];
      System.out.println(array3[0]);//默认值为0.0

类型

默认值

byte

0

short

0

int

0

long

0

float

0.0f

double

0.0

char

/u0000

boolean

false

如果数组中存储的元素类型为引用类型,默认值为null。(后面类会详细介绍) 

 2.数组的使用

数组的使用无非就是将数组中的元素打印出来,而数组是一段连续空间,可以通过数组的下标来访问数组中的某一个元素。下面我们来介绍三种打印方式

2.1 用for循环打印(和C语言的原理是一样的)

public class Test1 {
    public static void main(String[] args) {
        int[] array = {0,1,2};
        //数组中通过数组名.length来获取数组的长度
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i]+" ");
        }
    }
}

2.2 用for each打印

public class Test1 {
    public static void main(String[] args) {
        int[] array = {0,1,2};
        //int x:int表示数组元素的类型是int,x是定义的变量;array代表数组
        //for each也叫做增强for循环,它会自动遍历。将array中的元素存到变量x中去,存一个打印一个
        for (int x: array) { 
            System.out.print(x+ " ");
        }
    }
}

2.3 用库函数打印

public class Test1 {
    public static void main(String[] args) {
        int[] array = {0,1,2};
        //为了让我们更好的操作数组,提供了一系列的方法在工具类Arrays中
        System.out.println(Arrays.toString(array));
    }
}

Java提供了很多包,包里面有着许多的类,类中的函数可以让我们快速的搞定某一些问题。 

三、数组是引用类型

3.1 简单的认识JVM的内存分布

为什么会有JVM的出现呢?因为程序的加载,程序运行后产生的数据,程序中定义的变量都要用到内存,如果我们不加以区分的话,内存的管理就会变得很糟糕。这好似我们随意摆放的房间,看起来就会很乱。所以JVM按照所使用内存功能的不同进行了划分:

java数据结构中的数组 java数组详解_开发语言_02

🚀程序计数器: 只是一个很小的空间 , 保存下一条执行的指令的地址

🚀虚拟机栈: 与方法调用相关的一些信息, 每个方法在执行时,都会先创建一个栈帧 ,栈帧中包含 有:局部变量表操作数栈动态链接返回地址 以及其他的一些信息,保存的都是与方法执行时相关的一 些信息。比如:局部变量。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了

🚀本地方法栈:   本地方法栈与虚拟机栈的作用类似 . 只不过 保存的内容是 Native 方法的局 部变量 . 在有些版本的 JVM 实现中 ( 例如 HotSpot), 本地方法栈和虚拟机栈是一起的

🚀堆 JVM 所管理的最大内存区域 . 使用 new 创建的对象都是在堆上保存 ( 例如前面的 new int[]{1, 2, 3} ) , 堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销

🚀方法区: 用于 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数 . 方法编译出的的字节码就是保存在这个区域

3.2 认识null

null在Java中表示空引用,表示不指向任何的对象。如下代码:

public class Test1 {
    public static void main(String[] args) {
        //int[] arr = 0;//引用类型赋值不能为0,
        int[] arr = null;
        //会出现异常,null表示一个无效的内存空间,因此不能对它进行任何的操作,不然会出现NullPointerException(空指针异常)
        System.out.println(arr[0]);
    }
}

3.3 用两个练习题来加深数组引用的理解 

3.3.1 代码如下:

public class Test1 {
    public static void func(int[] array1){//数组作为参数
        //array一旦被初始化后,就不能修改,除非动态初始化
        //改变了形参引用的指向
        array1 = new int[]{7,8,9};
    }
    public static void func1(int[] array2){
        array2[2] = 15;
    }
    public static void main(String[] args) {
        int[] array = {1,2,3};
        func(array);
        System.out.println(Arrays.toString(array));//打印[0,1,2]
        func1(array);
        System.out.println(Arrays.toString(array));//打印[0,1,15]
    }
}

对于上面的代码输出跟我刚开始所想是有些出入的,下面就来详细说明: 

java数据结构中的数组 java数组详解_c#_03

func()解释:执行mian函数的时,会在栈区上开辟一个mian函数的栈帧,用来存放arra,也会在堆区上开辟一块存储数组array元素的空间,调用func()方法的时候,数组作为参数,将array里面存储的内存地址传给了array1,array1指向了array所指向的数组(对象),但是呢,array1被动态初始化,在堆区上重新开辟了一块空间,并指向了这个对象(数组)。当func()函数执行完后,array1就不会指向任何对象了,array1自己所开辟的空间就会被JVM的垃圾回收器回收掉,在此之间,并没有对数组array有过任何的改变,所以会打印原数组的元素。

func1()解释:直接对array堆区上的数组元素进行改变。

3.3.2 代码如下: 

public class Test1 {
    public static int[] func(){
        int[] array = {1,2,3};
        return array;
    }
    public static void main(String[] args) {
        int[] ret = func();
        System.out.println(Arrays.toString(ret));//打印[1,2,3]
    }
}

 

java数据结构中的数组 java数组详解_开发语言_04

 堆区和栈区的内存回收:在栈区上,一个代码块结束,栈区就会回收内存,而堆区上的内存,编译器会判断是否还有其他的用处(是否有引用)再回收。

funct()函数执行完的时候,栈区上的内存就会被销毁,但是呢,堆区上的内存还需要编译器识别是否还有引用后再做处理,这时呢,数组ret就会接收到array里面所指向对象的地址,ret就会指向array数组指向的对象,从而打印[1,2,3,]。 

 四、二维数组


二维数组本质上也就是一维数组 , 只不过每个元素又是一个一维数组。下面用简单的代码来实现:


public class Test1 {
    public static void main(String[] args) {
        int[][] arr = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} };
        for (int row = 0; row < arr.length; row++) {
            for (int col = 0; col < arr[row].length; col++) {
                System.out.printf("%d\t", arr[row][col]);
            }
            System.out.println("");
        }
    }
}



java数据结构中的数组 java数组详解_jvm_05


五、练习题练习(冒泡排序和二分查找)

5.1 冒泡排序

public static int[] bubbleSearch(int[] array){
        for (int i = 0; i < array.length-1; i++) {
            boolean flg = false;
            for (int j = 0; j < array.length-i-1; j++) {
                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 array;
        }
        return array;
    }
    public static void main8(String[] args) {
        int[] array = {2,5,0,2,3,1};
        int[] ret = bubbleSearch(array);
        System.out.println(Arrays.toString(ret));
        /*Arrays.sort(array);
        System.out.println(Arrays.toString(array));*/
    }

 5.2 二分查找

public static int binarySearch(int key,int[] array){
        int right = array.length - 1;
        int left = 0;
        while (left<=right){
            int mid = (right-left)/2+left;
            if(array[mid] == key)
                return mid;
            else if(array[mid]>key)
                right = mid-1;
            else if (array[mid]<key)
                left = mid+1;
        }
        return -1;
    }
    public static void main(String[] args) {
        int[] array = {1,2,3};
        int key = 1;
        int ret = binarySearch(key,array);
        //int ret = Arrays.binarySearch(array,3);
        System.out.println(ret);
    }

总结

Java中数组和C语言中的数组还是有着异曲同工之妙的,在使用数组的过程中特别要注意数组越界的情况。引用会在类和对象中详细介绍