javaSE学习-3-数组的定义与使用

1 数组的创建及初始化


int[] array1 = new int[10]; 
// 创建一个可以容纳10个int类型元素的数组 
double[] array2 = new double[5]; 
// 创建一个可以容纳5个double类型元素的数组 
String[] array3 = new double[3]; 
// 创建一个可以容纳3个字符串元素的数组

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


public class Test {
    public static void main(String[] args) {
        int[] array = {1,2,3,4};
        fun1(array);
        System.out.println(Arrays.toString(array));
        fun2(array);
        System.out.println(Arrays.toString(array));

    }
    public static void fun1(int[] array){
        array = new int[]{11,22,33,44};
    }
    public static void fun2(int[] array){
        array[0] = 99;
    }
}

输出结果:

[1, 2, 3, 4]
[99, 2, 3, 4]

可以看出来fun1没有起作用, 但是fun2起作用了

为什么fun1没有起作用呢

解释如下:

在Java中,参数传递是按值传递的,这意味着方法接收的是实际参数值的副本(将实际参数的值复制一份传递给方法),而不是参数本身。

在`fun1`方法中,对`array`参数进行了重新赋值,但这只会在`fun1`方法内部产生影响,不会影响到`main`方法中的`array`。

这一句array = new int[]{11,22,33,44}; 可以分为两个步骤来理解:

  1. new int[]{11, 22, 33, 44}: 这一部分在堆内存中创建了一个新的整数数组,并将数组的引用(地址)返回。这个数组是匿名的,因为没有指定数组的变量名。

  2. array = ...:将步骤1中创建的数组的引用赋值给名为 array 的变量。现在,array 变量引用堆内存中创建的整数数组。

具体来说,当调用`fun1(array)`时,`array`的副本被传递给了`fun1`方法,然后在`fun1`方法内部,重新给`array`赋值为一个新的数组。这个新的数组在堆内存中分配,但它只在`fun1`方法的作用域内有效。一旦`fun1`方法执行完毕,这个新数组的引用就丢失了,而`main`方法中的`array`仍然引用原来的数组。

画了幅图 理解一下:

javaSE学习-3-数组的定义与使用_第1张图片

相比之下,在`fun2`方法中,修改的是原数组中的元素,而不是创建一个新的数组。因此,这个修改是在原数组的内存地址上进行的,对于调用`fun2`的`main`方法中的`array`是可见的,因此`fun2`方法的修改在`main`方法中是起作用的,导致输出 `[99, 2, 3, 4]`。

(简单点说, 形参实参引用类型存储的都是同一个地址, 都是指向栈中地址为0x12的数组对象)

因此不是传了引用就能够修改实参的值

学过C语言的同学注意一下,c语言中分传值调用和传址调用, 但是java中,严格意义来说,只有传值调用, 有时候传的值为地址

引用不相当于地址, 在java中, 引用是引用变量的简称,

  1. 引用变量存的是地址,
  2. 引用指向对象
 public static void main(String[] args) {
        int x = 10;
        System.out.println(x);
    }
    public static void func1(int x){
        x = 20;
    }

栈上的变量的地址是取不出来的

对于基本数据类型的变量,其实际的数值直接存储在栈上,而不是在堆上分配内存,并且在栈上的变量地址是无法直接获取的。

堆上的对象,包括通过 new 关键字创建的对象,是由Java虚拟机动态分配和释放内存的,可以通过引用来访问堆上对象,但通常不能直接获取对象的地址。

public static void main(String[] args) {
        int[] ret = func5();
        System.out.println(Arrays.toString(ret));
    }
    public static int[] func5() {
        int[] arr = {1,2,3,4,5};
        return arr;
    }

先new了一个数组, 在形参arr中存储的是栈上的地址, 再return给ret ret也拿到了栈上的0x99地址, 指向了数组{1,2,3,4}

javaSE学习-3-数组的定义与使用_第2张图片

小应用:数组作为返回值的斐波那契数列

public static void main(String[] args) {
        int[] arr = fib(10);
        System.out.println(Arrays.toString(arr));
    }
    public static int[] fib(int n) {
        if (n <= 0) {
            return null;
        }
        int[] arr = new int[n];
        arr[0] = arr[1] = 1;
        for (int i=2; i

二维数组

定义

int[][] arr = new int[][]{{1,2,3},{4,5,6}};
或者
int[][] arr = {{1,2,3},{4,5,6}};

数组定义可以省略列不能省略行

因此可以定义不规则数组(即对于所有行,每一行的列数不一定相同)

int[][] arr1 = new int[2][];

对于arr1的每一行, 都是一个未初始化的一维数组, 每一行都可以单独new

遍历

对于arr.length 相当于arr的行数 

这个数组arr[0].length相当于一维数组arr[0]的长度

因此遍历可以这样双重for循环

for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[0].length; j++) {
                System.out.print(arr[i][j]+" ");
            }
            System.out.println();
        }

那么如何使用for each呢

对于一维数组

 int[] array = {1,2,3,4};
        for (int x:
             array) {
            System.out.print(x+" ");
        }

对于二维数组

for (int[] intx:
             arr) {
            for (int x:
                 intx) {
                System.out.print(x+" ");
            }
            System.out.println();
        }

里面的是一维数组遍历, 那么外面同样是一维数组遍历,每个元素是二维数组的每一行

你可能感兴趣的:(JavaSE,学习,java,算法)