栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

java中的数组

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

java中的数组

目录

一、什么是数组

二、数组的创建

1.静态初始化

2.动态初始化

三、数组的使用

1.基本使用

2.数组作为方法的参数

2.1引用类型

2.2java中的null

2.3虚拟机栈和堆

3.数组中作为方法的返回值

四、二维数组


一、什么是数组

数组是相同类型数据的有序集合,数组中每一个数据称作一个数组元素,每个数组元素都可以通过一个下标来访问

注意:数组中的每个元素都必须是相同类型

二、数组的创建

1.静态初始化

基本语法:

//格式一
数据类型[] 数组名称 = { 初始化数据 };
//格式二
数据类型 数组名称[] = { 初始化数据 };

代码示例:

//格式一
int[] arr = {1, 2, 3};
//格式二
int arr[] = {1, 2, 3};

2.动态初始化

基本语法:

//格式一
数据类型[] 数组名称 = new 数据类型 [] { 初始化数据 };
//格式二
数据类型 数组名称[] = new 数据类型 [] { 初始化数据 };

代码示例:

//格式一
int[] arr = new int[]{1, 2, 3};
//格式二
int arr[] = new int[]{1, 2, 3};

从上可以看出格式二和C语言相似,但是更推荐写成 int[ ] arr 的形式,int和 [ ] 是一个整体

三、数组的使用

1.基本使用

代码示例:获取长度 与 访问元素

public class TestDemo {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        // 获取数组长度
        System.out.println("length: " + arr.length); // 执行结果: 3
        // 访问数组中的元素
        System.out.println(arr[1]); // 执行结果: 2
        System.out.println(arr[0]); // 执行结果: 1
        arr[2] = 100;
        System.out.println(arr[2]); // 执行结果: 100
    }
}

注意事项

  1. 使用 arr.length 能够获取到数组的长度,这个操作为成员访问操作符,在面向对象中会经常用到
  2. 使用 [ ] 按下标取数组元素,需要注意,下标从 0 开始计数
  3. 使用 [ ] 操作既能读取数据,也能修改数据
  4. 下标访问操作不能超出有效范围 [0, length - 1] ,如果超出有效范围,会出现下标越界异常

代码示例:下标越界

public class TestDemo {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        System.out.println(arr[100]);
    }
}
//执行结果
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
	at TestDemo.main(TestDemo.java:7)

代码示例:遍历数组

public class TestDemo {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}
//执行结果
1
2
3

代码示例:使用 for-each 遍历数组

public class TestDemo {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        for (int x : arr) {
            System.out.println(x);
        }
    }
}

2.数组作为方法的参数

2.1引用类型

代码示例:参数传内置类型

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

从上述代码中可以发现:修改形参 x 的值,不影响实参的 num 值(这是因为形参本质是实参的一份拷贝,形参的改变不会影响实参)

图解如下:

代码示例:参数传数组类型

public static void main(String[] args) {
    int[] arr = new int[]{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

从上述代码可以发现:在方法内部修改数组 a 中内容时,方法外部数组 arr 中的内容也发生改变,此时数组名 arr 是一个 "引用" ,当传参的时候,是按照引用传参

什么是引用?

引用其实就是地址的别名
举个例子:张三、李四、王五、老六这四个人上大学住在同一个宿舍,这间宿舍的编号为 "14-308",那么这个编号 "14-308" 其实就是这间宿舍的地址,然后他们四个又个这间宿舍取了个名字:"高颜值宿舍",那么这个 "高颜值宿舍" 也是这间宿舍的地址,也就是  "14-308" 的别名

针对 int[] arr = new int[]{1, 2, 3} 这样的代码, 内存布局如下:

  • 当我们创建 new int[]{1, 2, 3} 的时候,相当于创建了一块内存空间保存三个 int 类型的元素
  • 接下来执行 int[] arr = new int[]{1, 2, 3} 相当于又创建了一个 int[] 变量,这个变量是一个引用类型,里面只保存了一个整数(数组的起始内存地址)
  •  接下来我们进行传参相当于 int[] a = arr ,内存布局如图
  • 接下来我们修改 a[0] ,此时是根据 0x100 这样的地址找到对应的内存位置,将值改成 100 

此时已经将 0x100 地址的数据改成了 100 ,那么根据实参 arr 来获取数组内容 arr[0] ,本质上也是获取 0x100 地址上的数据,也是 100

总结: 所谓的 "引用" 本质上只是存了一个地址,Java 将数组设定成引用类型,这样的话后续进行数组参数传参,其实只是将数组的地址传入到函数形参中,这样可以避免对整个数组的拷贝(数组可能比较长,那么拷贝开销就会很大)

可能有人会有疑问,不是说形参是实参的一份拷贝,形参的改变不会影响是实参吗?那这里怎么有改变了原数组的值呢?下面我们用一段代码来验证一下

代码示例:

public static void main(String[] args) {
        int[] arr1 = new int[]{1,2,3};

        System.out.println("调用前arr1: "+arr1);
        System.out.println(Arrays.toString(arr1));
        func(arr1);
        System.out.println("调用后arr1: "+arr1);
        System.out.println(Arrays.toString(arr1));
    }
    public static void func(int[] arr2) {
        System.out.println("改变前arr2: "+arr2);
        System.out.println(Arrays.toString(arr2));
        int[] arr3 = {4,5,6};
        arr2=arr3;
        arr2[0] = 100;
        System.out.println("改变后arr2: "+arr2);
        System.out.println(Arrays.toString(arr2));
    }
//执行结果
调用前arr1: [I@1b6d3586
[1, 2, 3]
改变前arr2: [I@1b6d3586
[1, 2, 3]
改变后arr2: [I@4554617c
[100, 5, 6]
调用后arr1: [I@1b6d3586
[1, 2, 3]

通过上述代码我们可以发现:形参数组 arr2 在改变前,arr2 存的地址和地址所指向的那块空间的存的数据元素是一致的;当 arr2 存的地址改变时,那么它指向的空间也发生改变,对着块空间存的数据元素进行改变,并不会影响原数组 arr1 指向的空间的数据元素

2.2java中的null

null 在 Java 中表示 "空引用" ,也就是一个无效的引用

public static void main(String[] args) {
        int[] arr = null;
        System.out.println(arr[0]);
    }
//执行结果
Exception in thread "main" java.lang.NullPointerException
	at TestDemo.main(TestDemo.java:8)

null 的作用类似于 C 语言中的 NULL (空指针),都是表示一个无效的内存位置,因此不能对这个内存进行任何读写操作,一旦尝试读写, 就会抛出 NullPointerException.
注意:Java 中并没有约定 null 和 0 号地址的内存有任何关联

2.3虚拟机栈和堆

  • 局部变量和引用保存在栈上, new 出的对象保存在堆上
  • 堆的空间非常大,栈的空间比较小
  • 堆是整个 JVM 共享一个,而栈每个线程具有一份(一个 Java 程序中可能存在多个栈)

3.数组中作为方法的返回值

代码示例:写一个方法,将数组中的每个元素都 * 2

// 直接修改原数组
class TestDemo {
    public static void main(String[] args) {
    int[] arr = {1, 2, 3};
    transform(arr);
    printArray(arr);
}
    public static void printArray(int[] arr) {
    for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i]);
    }
} 
    public static void transform(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            arr[i] = arr[i] * 2;
        }
    }
}

这个代码固然可行,但是破坏了原有数组,有时候我们不希望破坏原数组,就需要在方法内部创建一个新的数组, 并由方法返回出来

// 返回一个新的数组
class TestDemo {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        int[] output = transform(arr);
        printArray(output);
} 
    public static void printArray(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
        System.out.println(arr[i]);
    }
} 
    public static int[] transform(int[] arr) {
        int[] ret = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            ret[i] = arr[i] * 2;
        }
        return ret;
    }
}

这样的话就不会破坏原有数组了,另外由于数组是引用类型,返回的时候只是将这个数组的首地址返回给函数调用者,没有拷贝数组内容,从而比较高效

四、二维数组

二维数组本质上也就是一维数组,只不过每个元素又是一个一维数组

基本语法:

数据类型[][] 数组名称 = new 数据类型 [行数][列数] { 初始化数据 };

代码示例:

public class TestDemo {
    public static void main(String[] args) {
        int[][] arr = new int[][]{{1,2,3},{4,5,6}};
        //打印方式一
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j]+" ");
            }
            System.out.println();
        }
        //打印方式二
        for (int[] temp:arr) {
            for (int x:temp) {
                System.out.print(x+" ");
            }
            System.out.println();
        }
        //打印方式三
        System.out.println(Arrays.deepToString(arr));
    }
}
// 执行结果
1 2 3 
4 5 6 
1 2 3 
4 5 6 
[[1, 2, 3], [4, 5, 6]]

代码示例:不定长二维数组

public class TestDemo {
    public static void main(String[] args) {
        int[][] arr = new int[3][];
        arr[0] = new int[1];
        arr[1] = new int[2];
        arr[2] = new int[3];

        // 获取二维数组的第一维长度(3)
        System.out.println(arr.length);
        // 获取二维数组的第一维的第一个数组长度(1)
        System.out.println(arr[0].length);
    }
}
// 执行结果
3
1

二维数组的用法和一维数组并没有明显差别,只是多了行数,同理,还存在 "三维数组", "四维数组" 等更复杂的数组,只不过出现频率都很低

注意:java中只能单独定义行数,不能单独定义列数

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1006366.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号