java数组

2021/01/22 Java基础知识 共 4414 字,约 13 分钟
闷骚的程序员

1. Java中定义数组的两种方式

注意:数组在 java 底层实际上是JVM层面实现的,整个JDK中找不到数组的实现,它直接对应的就是cpu指令,数组比较经典也比较难。

数组是个引用对象,可以进行引用传递,改变其对象内容(除了8大基本数据类型包装类和String内容不可变外其他的引用类型的内容几乎都可以改变)。

1.1. 静态声明数组:

数据类型 数组名称[]={初值1,初值2,…..,初值n};
数据类型 数组名称[]=new 数据类型[]{初值1,初值2,…..,初值n}。

// 方式1
char[] chars = new char[]{'V', 'D', 'P', 'Y', '0', '-', '/'};

// 方式2
int[] numbers = {2, 3, 5, 6, 1, 9, 67, 43, 12, 45};

1.2 动态声明数组:

数据类型 数组名称[] = new 数据类型[数组长度]。

// 动态声明数组
String[] names = new String[6];

2. 静态声明数组和动态声明数组的区别

静态声明数组,除了声明了数组的定义之外,还同时对数组做了初始化,即初始化了数组中各个元素的值。正因为明确初始化了数组元素的值,因此静态声明数组不用指定数组长度。
动态声明数组,仅仅是声明一个数组对象的定义,申请了一块具有大小的内存空间,并没有做数组的初始化操作。
注意:动态声明数组后,是需要手动为数组中每个元素进行初始化的。你可以一个一个的去赋值,也可以采用循环遍历去赋值。对于没有赋值的数组元素,其值为对应类型的默认值。

3. 数组的本质

数组的本质是个容器,存储类型相同的一堆数据,有长度限制,在声明数组时就需要明确数组的长度大小以便确定申请多大的内存空间。

根据往数组中存储数据的方式不同,将数组划分为有序数组和无序数组。
首先明确:数组是物理内存连续的一片内存空间,简单点理解就是物理地址挤在一起的一块内存。
有序数组和无序数组,其实和数组本身的结构没有任何关系,无论是有序数组还是无序数组,都需要指定数组的初始化大小,其开辟的内存空间都是物理内存连续的空间。
区别在于给这块空间存储值的时候,是按照放置的顺序存储呢?还是按照其他的顺序存储呢?
有序数组:表示往数组中存储数据,就按照放置的顺序来存储,第1个放进来的数据就放在下标为0的数组元素中,第2个依次…
无序数组:表示不按照放置的顺序进行存储,而是根据存储进来的对象动态计算出它在数组中应该存储的下标位置,从而实现某种散列存储。

有序数组和无序数组的jdk实现案例:
ArrayList底层就是有序数组,表示ArrayList在放置数据时,是按照放置的数据存储到底层是数组中的,比如add(m),add(d)…,则m存储在第0位,d存储在第1位…
HashSet底层就是无序数组,表示按照散列的顺序存储,比如put(f),put(k)…则f放在哪个位置,需要计算f对象的Hash值,由hash值来确定数组下标,k对象也是如此.

反映在代码曾铭,有序数组相当于数组的静态初始化:

String[] a = {d,c,o,p,u};

其中d在第1个,c在第2个…

无序数组相当于数组的动态初始化:

String[] a = new String[10]; 

然后具体哪个值往哪个下标放置,由代码自己控制放置的顺序。

4. 匿名数组

只能使用new 数据类型[]{初值1,初值2,…..,初值n}来创建匿名数组对象,使用{初值1,初值2,…..,初值n}是无法创建匿名对象的。

package javase.demo03.array;
import org.junit.Test;

// 1、数组初始化方式学习-匿名数组(本质是匿名对象),没有名称的数组称为匿名数组,匿名数组和匿名对象一样,其构造方法返回的是当前堆内存空间的地址。
// 2、匿名对象一般只使用一次,但是一旦被接收了就和具名对象是一样的了。
public class Demo03NiMingArray {
    // 测试静态初始化方式一初始化匿名数组
    @Test
    public void testCase1() {
        System.out.println("案例一");
        int[] array = getArray1();
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }
    // 测试静态初始化方式二初始化匿名数组
    @Test
    public void testCase2() {
        System.out.println("案例二");
        // 报错,案例二没法实现匿名数组
        int[] array = getArray2();
        if (array == null) {
            return;
        }
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }
    // 测试动态初始化方式初始化匿名数组
    @Test
    public void testCase3() {
        System.out.println("案例三");
        int[] array = getArray3();
        for (int i = 0; i < array.length; i++) {
            array[i] = i;
            System.out.println(array[i]);
        }
    }

    // 案例一:使用数组静态初始化方式一实现匿名数组对象。
    // 结论:可以直接创建匿名数组对象。
    public static int[] getArray1() {
        return new int[]{1, 2, 3};
    }
    
    // 案例二:使用数组静态初始化方式二实现匿名数组对象。
    // 结论:很明显,匿名数组对象必须要使用new进行。只能使用静态方式一实现匿名数组。
    public static int[] getArray2() {
        // return { 1, 2, 3 };//
        return null;
    }
    
    // 案例三:使用数组动态初始化方式实现匿名数组对象
    // 结论:以直接创建匿名数组对象,但是在调用方必须要动态初始化。
    public static int[] getArray3() {
        return new int[3];
    }
}

5. 数组常见操作

5.1 给数组元素赋值

数组名称[下标]=初值。 

(1)注意静态声明数组已经实现了数组的静态初始化,即在声明数组变量的同时给数组内的所有元素已经初始化了。
(2)动态声明数组要想实现赋值操作,就采用 “数组名称[下标]=初值” 的方式(一般都是在循环中遍历赋值)。

// 数组的声明
PersonCode03 per1[] = null;
// 数组的静态初始化方式一
per1 = new PersonCode03[]{new PersonCode03("zhaoerhu", 22),
        new PersonCode03("daxiyang", 25), new PersonCode03("shixiang", 18)};
// 数组的静态初始化方式二
PersonCode03 per2[] = {new PersonCode03("zhangsan", 10),
        new PersonCode03("Lisi", 18), new PersonCode03("wangwu", 9)};
// 数组的动态初始化
PersonCode03 per3[] = new PersonCode03[3];
per3[0] = new PersonCode03("Eric", 16);
per3[1] = new PersonCode03("Daisy", 10);
per3[2] = new PersonCode03("Gorden", 30);

5.2 遍历数组

典型的for循环的方式,因为通过数组的length属性可以取得数组的长度,从而可以使用for循环去遍历数组中的每一个元素。或者使用foreach循环的方式遍历数组取得每个数组元素的值。

    @Test
    public void testDynamicInit() {
        String[] names = new String[6];
        System.out.println("目标数组的长度:" + names.length);
        names[0] = "Eric";
        names[1] = "Daisy";
        names[2] = "Frank";
        // names[3] = "Join";//注释掉下标为3的数组元素,则该位置的数组元素将被初始化为默认值null值。
        names[4] = "Manny";
        names[5] = "Sally";// 一般不会使用for循环动态索引的方式初始化动态数组,因为这样赋值要求值有固定的规律,对于规律的数字一般可以动态赋值

        //for循环遍历数组
        for (int i = 0; i < names.length; i++) {
            System.out.println("for循环遍历数组元素:" + names[i]);
        }

        //foreach遍历数组
        for (String name : names) {
            System.out.println("foreach遍历数组元素:" + name);
        }
    }

5.3 数组越界

当访问数组中某个元素时,访问的指定索引超出了数组的最大索引,就会报错数组越界。

    @Test
    public void testArrayIndexOutBoundsException() {
        int[] array = {1, 2, 3};
      
        // 注意具体的报错信息,如下,如果访问的索引是4,则报错的越界索引是4,;如果是100,则报错的索引就是100.
        System.out.println(array[4]);
    }

数组越界异常如下:

java.lang.ArrayIndexOutOfBoundsException: 4

	at zeh.myjavase.code03array.Demo01ArrayInit.testArrayIndexOutBoundsException(Demo01ArrayInit.java:90)

Process finished with exit code -1

5.4 直接输出数组输出的是引用地址

数组对象直接输出的是引用地址,数组对象不像集合容器,它底层由cpu指令实现,所以没法覆盖toString()方法,因此直接输出就是它对应的引用地址。
要想获取数组的元素内容,就需要循环遍历数组去获取其对应的内容。

    @Test
    public void testArrayOutput() {
        int array[] = {};
        //输出的是引用地址
        System.out.println("直接输出数组对象:" + array);
    }

输出如下:

直接输出数组对象:[I@51521cc1

Process finished with exit code 0

6. 空数组和null值

可以声明一个空数组,空数组的长度为0。 静态声明空数组:

   int[] a = {};
   int[] a = new int[]{};

动态声明空数组:

   int[] a = new int[0];

请注意: 声明一个空数组,即表示向内存空间申请了一块长度为0的内存,因此,空数组并不是null值,它是一个对象,只不过它的内部不存在任何数据,其长度为0。

文档信息

Search

    Table of Contents