Java入门(四)之 数组的定义与使用

  • 数组基本用法
  • 什么是数组
  • 创建数组
  • 数组的使用
  • 数组作为方法的参数
  • 基本用法
  • 理解引用类型
  • 认识 null
  • 初识 JVM 内存区域划分
  • 数组作为方法的返回值
  • 数组练习
  • 数组转字符串
  • 数组拷贝
  • 找数组中的最大元素
  • 求数组中元素的平均值
  • 查找数组中指定元素(顺序查找)
  • 查找数组中指定元素(二分查找)
  • 检查数组的有序性
  • 数组排序(冒泡排序)
  • 数组逆序
  • 数组数字排列
  • 二维数组


数组基本用法

什么是数组

数组:一块连续的内存,且存储的是相同数据类型的集合。
数组本质上就是让我们能 “批量” 创建相同类型的变量。
例如:

  1. 如果需要表示两个数据, 那么直接创建两个变量即可 int a;int b。
  2. 如果需要表示五个数据, 那么可以创建五个变量 int a1; int a2; int a3; int a4; int a5;。
  3. 但是如果需要表示未知个数据,那么就不能创建未知个变量了。这时候就需要使用数组,帮我们批量创建。

注意事项:在 Java 中,数组中包含的变量必须是相同类型的。

创建数组

基本语法

// 动态初始化
数据类型[] 数组名称 = new 数据类型 [] { 初始化数据 };
// 静态初始化
数据类型[] 数组名称 = { 初始化数据 };

代码示例如下

public class TextDemo {
    public static void main(String[] args) {
        int[] array1 = {1,2,3,4,5,6};//1.定义且初始化一个数组(静态初始化)。
        int[] array2 = new int[10];//2.定义了一个数组,但是没有初始化。new 关键字不可缺。
        int[] array3 = new int[]{1,2,3,4,5,6,7,8,9};//3.动态初始化数组。
    }
}

这个代码中,array1,array2,array3 都是局部变量;而{1,2,3,4,5,6},new int[10],{1,2,3,4,5,6,7,8,9}都是存放在堆区的。

JAVA 实例化Long数组 java定义long数组_字符串

注意: 数组,实际上是数组对象

JAVA 实例化Long数组 java定义long数组_jvm_02


引用不一定在栈上,取决于变量的位置。当变量做局部变量时,引用才在栈上。

JAVA 实例化Long数组 java定义long数组_intellij idea_03

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

数组的使用

使用数组做局部变量时,必须对其初始化;若不知道引用对象,应使用引用对应的零值(null)。
我们来打印数组作为示例

import java.util.*;

public class TextDemo {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5,6};
        int[] array2 = null;//array2 这个引用,不指向任何对象。
        //此时,我们来打印创建好的数组array。
        //3种方法
        //1.for 循环     length:数组的属性
        for (int i = 0; i < array.length;i++){
            System.out.print(array[i]+ " ");
        }
        System.out.println();
        //2.增强型for each循环
        for (int x :array) {
            System.out.print(x+ " ");
        }
        System.out.println();
        //3.使用操作数组工具类。
        //Arrays.toString 将数组以字符串的形式进行输出。
        /*String ret = Arrays.toString(array);
        System.out.println(ret);*/
        System.out.println(Arrays.toString(array));
    }
}

运行结果如下

JAVA 实例化Long数组 java定义long数组_java_04


这是三种打印数组的方式。

其中for()循环与for each () 循环的区别,for 循环通过下标 [ i ] 进行遍历整个数组;而for each () 循环遍历数组是不需要通过下标的。

注意事项

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

public class TextDemo {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5,6};
        System.out.println(array[100]);
    }

运行结果如下

JAVA 实例化Long数组 java定义long数组_intellij idea_05


这个异常的原因是数组下标超出范围(数组越界访问了)。

数组作为方法的参数

基本用法

我们还是用打印数组内容作为示例

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

运行结果如下

JAVA 实例化Long数组 java定义long数组_JAVA 实例化Long数组_06


在这个代码中:

  1. int[] a 是函数的形参, int[] arr 是函数实参。
  2. 如果需要获取到数组长度, 同样可以使用 a.length

理解引用类型

一.参数传内置类型,代码如下:

public class TextDemo {
    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);
    }
}

执行结果

JAVA 实例化Long数组 java定义long数组_java_07


可以看出,修改形参 x 的值,不影响实参的 num 值。

JAVA 实例化Long数组 java定义long数组_JAVA 实例化Long数组_08


二.参数传数组类型,代码如下:

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

执行结果

JAVA 实例化Long数组 java定义long数组_JAVA 实例化Long数组_09


可以看出,在函数内部修改数组内容,函数外部也发生改变。

此时数组名 arr 是一个 “引用” 。当传参的时候,是按照引用传参的。

认识 null

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

public class TextDemo {
    public static void main(String[] args) {
        int[] arr = null;
        System.out.println(arr[0]);
    }
}

执行结果如下

JAVA 实例化Long数组 java定义long数组_JAVA 实例化Long数组_10


这是因为,null 的作用类似于 C 语言中的 NULL (空指针),都是表示一个无效的内存位置。因此不能对这个内存进行任何读写操作。一旦尝试读写,就会抛出 NullPointerException异常。

初识 JVM 内存区域划分

JAVA 实例化Long数组 java定义long数组_jvm_11

JVM Stack 虚拟机栈 :就是我们平时所说的栈,用来存储局部变量。
Native Method Stack 本地方法栈:C/C++代码。
Heap 堆:new 创建的对象都是在堆上保存,用来存放对象。
PC Register 程序计数器:只是一个很小的空间,用来保存下一条执行的指令的地址。
Method Area 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法编译出的的字节码就是保存在这个区域。
Runtime Constant Pool 方法运行池:存放字面量(字符串常量)与符号引用。(从 JDK1.7 开始, 运行时常量池在堆上)

数组作为方法的返回值

将原来数组的值,扩大二倍。改变原数组。

import java.util.*;

public class TextDemo {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        System.out.println("数组扩大二倍前打印");
        System.out.println(Arrays.toString(array));
        int[] ret = fun(array);
        System.out.println("数组扩大二倍后打印");
        System.out.println(Arrays.toString(ret));
        System.out.println(Arrays.toString(array));
    	}
    public static int[] fun(int[] array){
        for (int i = 0;i < array.length;i++){
            array[i] = array[i] * 2;
        }
        return array;
    }
}

运行结果如下

JAVA 实例化Long数组 java定义long数组_字符串_12


可见,修改了原数组。

将原来数组的值,扩大二倍。不改变原数组。

import java.util.*;

public class TextDemo {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        System.out.println("数组扩大二倍前打印");
        System.out.println(Arrays.toString(array));
        int[] ret = fun(array);
        System.out.println("数组扩大二倍后打印新数组");
        System.out.println(Arrays.toString(ret));
        System.out.println("数组扩大二倍后,打印原数组");
        System.out.println(Arrays.toString(array));
        }
    public static int[] fun(int[] array){
        int[] ret = new int [array.length];
        for (int i = 0;i < array.length;i++){
            ret[i] = array[i] * 2;
        }
        return ret;
    }
}

运行结果如下

JAVA 实例化Long数组 java定义long数组_JAVA 实例化Long数组_13


可见,未修改原数组。

这两个代码的区别在于,是否改变原数组。
这就是典型的数组作为方法的返回值。

数组练习

数组转字符串

这道题,在这一期前面的内容有写过,非常之简单。

import java.util.*;

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

执行结果

JAVA 实例化Long数组 java定义long数组_intellij idea_14

Java 中提供了 java.util.Arrays 包,其中包含了一些操作数组的常用方法。
用自己的方法如下

import java.util.*;

public class TextDemo {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        //String ret = Arrays.toString(array);
        System.out.println(toString(array));
    }
    public static String toString(int[] array){
        String ret = "[";
        for (int i = 0;i <array.length;i++){
            ret += array[i];
            if (i != array.length-1){
                ret += ",";//各元素之间需要添加‘,’
            }
        }
        ret += "]";
        return ret;
    }
}

执行结果

JAVA 实例化Long数组 java定义long数组_jvm_15

数组拷贝

import java.util.*;

public class TextDemo {
    public static void main(String[] args) {
        int[] array1 = {1,2,3,4,5};
        int[] array2 = new int[array1.length];
        System.out.println("拷贝完成前,打印数组array1");
        System.out.println(Arrays.toString(array1));
        System.out.println("拷贝完成前,打印数组array2");
        System.out.println(Arrays.toString(array2));
        System.out.println("=========================");
        for (int i = 0;i < array1.length;i++){
            array2[i] = array1[i];
        }//方法一
        
        /* array2 = Arrays.copyOf(array1,array1.length);
        //使用操作数组工具类
        //方法二
         */
        /*System.arraycopy(array1,0,array2,0,array1.length);
        方法三
         */
        /*array2 = array1.clone();
        方法四
         */
        System.out.println("拷贝完成后,打印数组array1");
        System.out.println(Arrays.toString(array1));
        System.out.println("拷贝完成后,打印数组array2");
        System.out.println(Arrays.toString(array2));
        //四种方法其中方法三最快。
        System.out.println("=========================");
        array2[0] = 99;
        System.out.println("修改array2后,打印数组array1");
        System.out.println(Arrays.toString(array1));
        System.out.println("修改array2后,打印数组array2");
        System.out.println(Arrays.toString(array2));
        //拷贝后修改array2数组的值,array1数组不发生改变。
    }
}

运行结果如下(其中四种方法的运行结果均相同)

JAVA 实例化Long数组 java定义long数组_java_16


只拷贝某个范围。

import java.util.*;

public class TextDemo {
    public static void main(String[] args) {
        int[] array1 = {1,2,3,4,5};
        int[] array2 = new int[array1.length];
        array2 = Arrays.copyOfRange(array1,2,5);
        System.out.println(Arrays.toString(array2));
        // 范围拷贝
    }
}

执行结果

JAVA 实例化Long数组 java定义long数组_字符串_17

找数组中的最大元素

import java.util.*;

public class TextDemo {

    public static void main(String[] args) {
        int[] arr = {12,21,33,24,45,16};
        System.out.println(max(arr));
    }
    public static int max(int[] arr) {
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        return max;
    }
}

执行结果

JAVA 实例化Long数组 java定义long数组_字符串_18

求数组中元素的平均值

import java.util.*;

public class TextDemo {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6,7};
        System.out.println(avg(arr));
    }
    public static double avg(int[] arr) {
        int sum = 0;
        for (int x : arr) {
            sum += x;
        }
        return (double)sum / (double)arr.length;
    }
}

执行结果

JAVA 实例化Long数组 java定义long数组_jvm_19

查找数组中指定元素(顺序查找)

import java.util.*;

public class TextDemo {
    public static void main(String[] args) {
        int[] arr = {21,12,3,81,59,36};
        System.out.println(find(arr, 81));
    }
    public static int find(int[] arr, int toFind) {
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == toFind) {
                return i;
            }
        }
        return -1; // 表示没有找到
    }
}

执行结果

JAVA 实例化Long数组 java定义long数组_java_20

查找数组中指定元素(二分查找)

针对有序数组,可以使用更高效的二分查找。

import java.util.*;

public class TextDemo {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6};
        System.out.println(binarySearch(arr, 6));
    }
    public static int binarySearch(int[] arr, int toFind) {
        int left = 0;
        int right = arr.length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (toFind < arr[mid]) {
                // 去左侧区间找
                right = mid - 1;
            } else if (toFind > arr[mid]) {
                // 去右侧区间找
                left = mid + 1;
            } else {
                // 相等, 说明找到了
                return mid;
                }
            }
            // 循环结束, 说明没找到
        return -1;
    }
}

执行结果

JAVA 实例化Long数组 java定义long数组_jvm_21

检查数组的有序性

import java.util.*;

public class TextDemo {
    public static void main(String[] args) {
        int[] arr = {1,2,3,10,5,6};
        System.out.println(isSorted(arr));
    }
    public static boolean isSorted(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            if (arr[i] > arr[i + 1]) {
                return false;
            }
        }
        return true;

执行结果

JAVA 实例化Long数组 java定义long数组_java_22

数组排序(冒泡排序)

冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。

import java.util.*;

public class TextDemo {
    public static void main(String[] args) {
        int[] array = {9, 9, 8, 1};
        bubbleSort(array);
        System.out.println(Arrays.toString(array));
    }

    public static void  bubbleSort(int[] arr){
        for (int i = 0; i < arr.length; i++) {
            for (int j = arr.length - 1; j > i; j--) {
                if (arr[j - 1] > arr[j]) {
                    int temp = arr[j - 1];
                    arr[j - 1] = arr[j];
                    arr[j] = temp;
                }
            }
        }
    }
}

执行结果

JAVA 实例化Long数组 java定义long数组_字符串_23

Java中,实现数组排序可以使用操作数组工具类。代码如下

public class TextDemo {
    public static void main(String[] args) {
        int[] arr = {3, 2, 5, 1};
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

执行结果

JAVA 实例化Long数组 java定义long数组_字符串_24

数组逆序

给定一个数组,将里面的元素逆序排列。
思路
设定两个下标, 分别指向第一个元素和最后一个元素. 交换两个位置的元素.
然后让前一个下标自增, 后一个下标自减, 循环继续即可。

import java.util.*;

public class TextDemo {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4,5,6,7,8,9};
        reverse(arr);
        System.out.println(Arrays.toString(arr));
    }
    public static void reverse(int[] arr) {
        int left = 0;
        int right = arr.length - 1;
        while (left < right) {
            int tmp = arr[left];
            arr[left] = arr[right];
            arr[right] = tmp;
            left++;
            right--;
        }
    }
}

执行如下

JAVA 实例化Long数组 java定义long数组_intellij idea_25

数组数字排列

给定一个整型数组,将所有的偶数放在前半部分,将所有的奇数放在数组后半部分。代码如下:

import java.util.*;

public class TextDemo {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5, 6,7,8};
        transform(array);
        System.out.println(Arrays.toString(array));
    }
    public static void transform(int[] arr) {
        int left = 0;
        int right = arr.length - 1;
        while (left < right) {
            // 该循环结束, left 就指向了一个奇数

            while (left < right && arr[left] % 2 == 0) {
                left++;
            }
            // 该循环结束, right 就指向了一个偶数
            while (left < right && arr[right] % 2 != 0) {
                right--;
            }
            int temp = arr[left];
            arr[left] = arr[right];
            arr[right] = temp;
        }
    }
}

执行结果

JAVA 实例化Long数组 java定义long数组_java_26

二维数组

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

JAVA 实例化Long数组 java定义long数组_字符串_27

基本语法

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

我们用打印一个二维数组作为示例,代码如下:

import java.util.*;

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

执行结果

JAVA 实例化Long数组 java定义long数组_intellij idea_28


二维数组的用法和一维数组并没有明显差别,因此我们不再赘述。

同理,还存在 “三维数组”,“四维数组” 等更复杂的数组, 只不过出现频率都很低,很少用到。

Java入门(四)之 数组的定义与使用,到这里就基本结束了。
下期带来Java入门(五)之 类和对象。各位铁铁,我们下期见。