08月31, 2020

JAVA数组

JAVA数组重点掌握知识,以后肯定会用到的,可以了解一下底层原理。数组是指一组数据的集合,数组中的每个数据被称作元素。在数组中可以存放任意类型的元素,但同一个数组里存放的元素类型必须一致。

数组

数组定义格式:

数据类型[] 数组名(变量名) = new 数据类型[元素个数或数组长度];

实例:

public class ArrayDemo01 {

    public static void main(String[] args) {
        int[] x = new int[100];
    }
}

注意:数组定长,一但定义长度为100,在使用时大小就是100了。不变量。

数组特点:定长、引用类型。

JVM

java程序运行时,操作系统会给jvm虚拟机分配一块内存。JVM又会将这块内存,进行划分管理。

JVM内存划分:JVM对自己的内存进行了划分,分成5个区域。

1、寄存器:内存和CPU之间。
2、本地方法栈:JVM调用操作系统中的功能。
3、方法和数据共享:运行时其class文件,进入的地方。
4、方法栈:所有的方法运行的时候,进入的内存。
5、堆:存储的是容器和对象。

开发人员主要关心:方法和数据共享、方法栈、堆。

数组内存划分

  1. 首先,运行class文件,所以先进入方法区。
  2. 运行main方法,在方法栈中运行,但是main用不了那么多,所以方法栈中会分配一块给main方法是用。
  3. 执行数组,一个容器,所以JVM在堆内存,开空间,存储数组容器。
  4. JVM会将该地址,给定义的数组变量arr(相当于arr引用了这个地址),所以数组是引用类型。
  5. 每次运行,JVM分配的地址是不同的。
  6. 当main方法运行完了,arr变量就没了,然后new int[3]也就没了 ,JVM垃圾回收机制,会自动帮我们回收,不用我们去处理了。

堆空间太大,怎么找到这个容器呢,所以每个数组,在内存中,都有自己的内存地址,也就是数组元素的首地址,第一个数据的地址。

注意:arr引用类型,保存的数据,实际上是内存中的地址。

数组元素的访问

数组是一个容器,存储到数组中的每个元素,都有自己的自动编号/下标(专业名词:索引)。

访问数组存储的元素,必须依赖索引。

访问公式:数组名[索引]

public class ArrayDemo02 {

    public static void main(String[] args) {
        int[] arr = new int[3];
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
    }
}

一初始化时,数组里面就有了默认值。

注意:数组索引是从0开始的。当数组被成功创建后,数组中元素会被自动赋予一个默认值,根据元素类型的不同,默认初始化的值也是不一样的。

byte、short、int、long:默认值0

float、double:默认值0.0

char:默认值一个空字符(空格),即’\u0000’

boolean:默认值false

引用数据类型:null,表示变量不引用任何对象

数组的属性

数组的长度length:

使用方法:数组名.length

public class ArrayDemo02 {

    public static void main(String[] args) {
        int[] arr = new int[3];
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
        System.out.println(arr.length);
    }
}

注意:length是int类型,因此数组最大索引为:数组名.length-1

数组中最小的索引是0,最大的索引是“数组的长度-1”。在Java中,为了方便我们获得数组的长度,提供了一个length属性,在程序中可以通过“数组名.length”的方式来获得数组的长 度,即元素的个数。

数组初始化

  1. 在定义数组时只指定数组的长度,由系统自动为元素赋初值的方式称作动态初始化。

  2. 数组的静态初始化

    方式一:数据类型[] 变量名 = new 数据类型[]{元素1,元素2,元素3...};

    方式二:数据类型[] 变量名 = {元素1,元素2,元素3,...};

    public class ArrayDemo03 {
    
        public static void main(String[] args) {
            //定义方式一
            int[] arr = new int[] {1,3,4,5};
            System.out.println(arr.length);
            //注意:new 后面的中括号中,不允许写任何内容,写了就编译失败。
            //错误实例:
            //int[] arr = new int[4]{1,2,3,4};
    
            //定义方式二(这种比较简单,常用)
            int[] arr2 = {1,2,3,4,};
            //注意:最后一个逗号,会自动去掉
            System.out.println(arr2.length);
        }
    }

    注意:第3行代码千万不可写成int[] arr = new int[4]{1,2,3,4};,这样写编译器会报错。原因在于编译器会认为数组限定的元素个数[4]与实际存储的元素{1,2,3,4}个数有可能不一致,存在一定的安全隐患。

数组元素赋值

   public class ArrayDemo04 {

       public static void main(String[] args) {
           //没有赋值的元素,都是默认值
           int[] arr = new int[3];
           arr[2] =5;
           System.out.println(arr[0]);
           System.out.println(arr[1]);
           System.out.println(arr[2]);
       }
   }

注意:如果在使用数组时,不想使用这些默认初始值,也可以显式地为这些元素赋值,如上代码。

数组的遍历

遍历:通过索引的方式,将数组中的每个元素,分别获取出来。

public class ArrayDemo05 {

    public static void main(String[] args) {
        int[] arr = {1,2,4,52,4,3,6,};
        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
        System.out.println(arr[3]);
        //......
        //如果有几千个,这样肯定不行,索引是依次加1的,因此可以用到循环来变量。

        //for:知道循环次数,计数器思想
        //while:不确定循环次数。
        for(int i=0;i<arr.length;i++) {
            System.out.println(arr[i]);
        }
    }
}

输出结果:

1
2
4
52
1
2
4
52
4
3
6

注意:

//for:知道循环次数,计数器思想

//while:不确定循环次数。

会自动去掉最后一个逗号。

数组中常见异常

  1. 数组索引越界异常

    public class ArrayError {
    
        public static void main(String[] args) {
            int[] arr = {1,2,4,};
            //1、数组索引越界异常
            System.out.println(arr[3]);
            System.out.println(arr[-2]);
        }
    }

    输出结果,编译时不出错,运行时,错误提示信息:

    Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:

    错误原因:索引越界、索引为负数。

  2. 空指针异常

    public class ArrayError {
    
        public static void main(String[] args) {
            //2、空指针异常
            int[] arr2 = {2,345,4};
            System.out.println(arr2[2]);;
            arr2 = null;//arr2不在保持数组的地址了
            System.out.println(arr2[2]);
        }
    }

    空指针内存运行说明:

    步骤1:int[] arr2 = {1,5,8},存在于栈中
    步骤2:同时在堆中开辟一块内存空间存储数据,并分配一个地址,如图右边。
    步骤3:arr2变量,引用执行该存储空间地址。
    
    上面3步是正常情况。
    
    步骤4:当执行arr2=null时,arr2引用就没有了指向的空间地址。
    步骤5:打印的数组的时候就会出现空指针异常了。

    输出结果:错误提示信息

    Exception in thread "main" java.lang.NullPointerException

    错误原因:数组变量为null

    注意:内存地址只能给一次,不能给第2次地址。因为为null空指向断了,JVM可能已经将堆地址内存释放掉了,不能再给回来。

数组获取最值

获取最值的原理思想:找到数组中的最大值或最小值,然后做比较。

最大值或最小值比较思想:将最大值放到一个变量中,赋值为第一个元素,每次将这个值与其他元素比较,将大的给这个值,最后这个就是最大值。最小值同理。

public class ArrayDemo05 {
    public static void main(String[] args) {
        int[] arr = { 4, 1, 6, 3, 9, 8 }; // 定义一个数组
        int max = arr[0]; // 定义变量max用于记住最大数,首先假设第一个元素为最大值
        // 下面通过一个for循环遍历数组中的元素
        for (int x = 1; x < arr.length; x++) {
            if (arr[x] > max) { // 比较 arr[x]的值是否大于max
                max = arr[x]; // 条件成立,将arr[x]的值赋给max
            }
        }
        System.out.println("max=" + max); // 打印最大值
    }
}

说明:

1、定义了一个临时变量max,用于记住数组的最大值。通过for 循环获取数组中的最大值,赋值给max变量。
2、首先假设数组中第一个元素arr[0]为最大值。
3、使用for循环对数组进行遍历,在遍历的过程中只要遇到比max值还大的元素,就将该元素赋值给max。
4、这样一来,变量max就能够在循环结束时记住数组中的最大值。

需要注意的是,在for循环中的变量i是从1开始的,这样写的原因是程序已经假设第一个元素为最大值,for循环中只需要从第二个元素开始比较,从而提高程序的运行效率。

二维数组

二维数组的定义有很多方式,几种常见的方式。

  1. 第一种方式:

     int[][] arr = new int[3][4];

    上面的代码相当于定义了一个3*4的二维数组,即二维数组的长度为3,二维数组中的每个元素又是一个长度为4的数组,接下来通过一个图来表示这种情况,如下图所示。

  2. 第二种方式:

    int[][] arr = new int[3][];

    第二种方式和第一种类似,只是数组中每个元素的长度不确定.

  3. 第三种方式:

    int[][] arr = {{1,2},{3,4,5,6},{7,8,9}};

    上面的二维数组中定义了三个元素,这三个元素都是数组,分别为{1,2}、{3,4,5,6}、{7,8,9}。

对二维数组中元素的访问也是通过角标的方式,如需访问二维数组中第一个元素数组的第二个元素,具体代码如下:

arr[0][1];

操作二维数组时,经常需要获取数组中元素的值。

public class TwoArrayDemo {

public static void main(String[] args) {
    //二维数组创建方式
    //方式一
    int[][] arr = new int[2][3];
    //方式二
    int[][] arr2 = new int[2][];
    arr2[0] = new int[5];
    arr2[1] = new int[1];
    //方式三
    int[][] arr3 = {{2,4,5},{1,2},{6,3,5,5}};
    //这种方式最简单,最常用。
 }
}

二维数组内存分配:

public class TwoArrayDemo {

    public static void main(String[] args) {
        int[][] arr3 = {{2,4,5},{1,2},{6,3,5,5}};

        //二维数组的访问
        System.out.println(arr3[2][2]);

        //二维数组的遍历
        for(int i=0;i<arr3.length;i++) {
            for(int j=0;j<arr3[i].length;j++) {
                System.out.print(arr3[i][j]);
            }
            System.out.println();
        }
    }
}

本文链接:https://www.yanxizhu.com/post/Java array.html

-- EOF --

Comments