Java数组

#1024程序员节|用代码,改变世界#

Java数组

  • 1. 数组基本用法
    • 1.1 什么是数组
    • 1.2 创建数组
    • 1.3 数组的使用
  • 2.数组作为方法的参数
    • 2.1 基本用法
    • 2.2 理解引用类型(重点/难点)
    • 2.3 认识 null
    • 2.4 初识 JVM 内存区域划分(重点)
  • 3. 数组作为方法的返回值
  • 4. 数组练习
    • 4.1 数组转字符串
    • 4.2 数组拷贝
    • 4.3 找数组中的最大元素
    • 4.4 求数组中元素的平均值
    • 4.5 查找数组中指定元素(顺序查找)
    • 4.7 检查数组的有序性
    • 4.8 数组排序(冒泡排序)
    • 4.9 数组逆序
    • 4.10 数组数字排列
  • 5. 二维数组

大家好,我是晓星航。今天我们将为大家讲解的是我们Java数组的用法及相关概念!

1. 数组基本用法

1.1 什么是数组

数组:存储一组相同数据类型的数据的集合。

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

1.2 创建数组

基本语法:

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

代码示例:

int[] arr = new int[]{1, 2, 3};
int[] arr = {1, 2, 3};
int arr[] = {1, 2, 3};//和 C语言更相似了.但是我们还是更推荐写成 int[] arr 的形式. int和 [] 是一个整体.
int[] array = {1,2,3,4,5,6,7};//定一个数组并初始化
int[] array2 = new int[3];//代表我们创建了一个可以存放3个整形的数组 默认值为全0
int[] array2 = new int[]{1,2,3,4,5};//代表我们创建了一个可以存放5个整形的数组 并初始化为1 2 3 4 5

注意事项: 静态初始化的时候, 数组元素个数和初始化数据的格式是一致的.

1.3 数组的使用

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

public class TestDemo1 {

    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
    }
}
Java数组_第1张图片

注意事项

  1. 使用 arr.length 能够获取到数组的长度. . 这个操作为成员访问操作符. 后面在面向对象中会经常用到.(数组名+.length 可以得到数组的长度)

  2. 使用 [ ] 按下标取数组元素. 需要注意, 下标从 0 开始计数

  3. 使用 [ ] 操作既能读取数据, 也能修改数据.

  4. 下标访问操作不能超出有效范围 [0, length - 1] , 如果超出有效范围, 会出现下标越界异常

代码示例: 下标越界

public class TestDemo1 {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        System.out.println(arr[100]);
    }
}
Java数组_第2张图片

代码示例: 遍历数组

所谓 “遍历” 是指将数组中的所有元素都访问一遍, 不重不漏. 通常需要搭配循环语句.

Java数组_第3张图片

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

public class TestDemo1 {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        for (int x : arr) {
            System.out.println(x);
        }
    }
}
Java数组_第4张图片

for-each 是 for 循环的另外一种使用方式. 能够更方便的完成对数组的遍历. 可以避免循环条件和更新语句写错.

for循环 和 for each 循环 区别?

for循环是可以拿到下标的

for each是拿不到下标的

Java数组_第5张图片

2.数组作为方法的参数

2.1 基本用法

代码示例: 打印数组内容

import java.util.Arrays;//Arrays方法的包(头文件)
public class TestDemo {
    public static void printArray(int[] a) {
        for (int x : a) {
            System.out.println(x);
        }
    }
    public static void main(String[] args) {
            int[] arr = {1, 2, 3};
            printArray(arr);
            String ret = Arrays.toString(arr);
        System.out.println(ret);
    }
}
Java数组_第6张图片

第一个是通过传参打印我们的数组

第二个则是通过我们的方法 Array.toString(数组名) 来打印我们的数组 注意这里我们是以字符串的形式来打印的

2.2 理解引用类型(重点/难点)

引用传值 传的即是值也是地址 java中只有传值,因为地址值也是值

Java数组_第7张图片

题目:上述代码中在调用func1和func2后分别打印的是什么?(此题用来区分形参和实参)

func1:

1:1 2 3 4 5 6

2:1 2 3 4 5 6

func2:

1:1 2 3 4 5 6

2:899 2 3 4 5 6

总结:对于func1来说 虽然形参的值改变了 但他并没有传回给实参 形参只是改变了自己的指向而已 因此我们的实参打印仍然是1 2 3 4 5 6.

而对于func2来说我们形参的值改变了 它是直接在我们实参的地址上进行改变的 所以我们的实参打印完变为899 2 3 4 5 6

如何理解内存?

内存就是指我们熟悉的 “内存”. 内存可以直观的理解成一个宿舍楼. 有一个长长的大走廊, 上面有很多房间. 每个房间的大小是 1 Byte (如果计算机有 8G 内存, 则相当于有 80亿 个这样的房间). 每个房间上面又有一个门牌号, 这个门牌号就称为 地址

什么是引用?

引用相当于一个 “别名”, 也可以理解成一个指针.创建一个引用只是相当于创建了一个很小的变量, 这个变量保存了一个整数, 这个整数表示内存中的一个地址.

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

2.3 认识 null

null 在 Java 中表示 “空引用” , 也就是一个无效的引用. (注意在Java中是小写的null 而在C语言中是大写的NULL)

int[] array2 = null;//这个引用 不指向 任何的对象
System.out.println(array2.length);
Java数组_第8张图片

也会报空指针异常

注意: Java 中并没有约定 null 和 0 号地址的内存有任何关联.

2.4 初识 JVM 内存区域划分(重点)

Java数组_第9张图片 Java数组_第10张图片

程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址.

虚拟机栈(JVM Stack): 重点是存储局部变量表(当然也有其他信息). 我们刚才创建的 int[] arr 这样的存储地址的引用就是在这里保存.

本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部变量. 在有些版本的 JVM 实现中(例如HotSpot), 本地方法栈和虚拟机栈是一起的.

堆(Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2,3} )

方法区(Method Area): 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据. 方法编译出的的字节码就是保存在这个区域.

方法区中运行时常量池(Runtime Constant Pool): 是方法区的一部分, 存放字面量(字符串常量)与符号引用. (注意 从 JDK1.7 开始, 运行时常量池在堆上).

局部变量和引用保存在栈上, new 出的对象保存在堆上.

堆与栈的大小比较:堆的空间非常大, 栈的空间比较小.

是整个 JVM 共享一个, 而栈每个线程具有一份(一个 Java 程序中可能存在多个栈).

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

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

public class TestDemo {
    public static void func(int[] array){
        for (int i = 0; i < array.length; i++) {
            array[i] = 2*array[i];
            System.out.print(array[i] + " ");
        }
    }
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5};
        func(array);
    }
}
Java数组_第11张图片

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

因此我们引进一个新方法:

import java.util.Arrays;
public class TestDemo {
    public static int[] transform(int[] array){
        int[] ret =new int[array.length];
        for (int i = 0; i < array.length; i++) {
            ret[i] = 2*array[i];
        }
        return ret;
    }
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        int ret2[] = transform(array);
        System.out.println(Arrays.toString(ret2));
    }
}
Java数组_第12张图片

这里我们使用了一个新的数组来返回我们所需要的值,没有破坏原有数组。

Java数组_第13张图片

4. 数组练习

4.1 数组转字符串

我们实现一个自己版本的数组转字符串(myToString)

import java.util.Arrays;
public class TestDemo {
    public static String myToString(int[] array){
        if (array == null){
            return null;
        }
        String str = "[";
        for (int i = 0; i < array.length; i++) {
            str = str + array[i];
            if (i != array.length-1){
                str = str + ",";
            }
        }
        str = str + "]";
        return str;
    }
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        System.out.println(myToString(array));
    }
}
Java数组_第14张图片

什么是包?

例如做一碗油泼面, 需要先和面, 擀面, 扯出面条, 再烧水, 下锅煮熟, 放调料, 泼油.

但是其中的 “和面, 擀面, 扯出面条” 环节难度比较大, 不是所有人都能很容易做好. 于是超市就提供了一些直接已经扯好的面条, 可以直接买回来下锅煮. 从而降低了做油泼面的难度, 也提高了制作效率.

程序开发不是从零开始, 而是要站在巨人的肩膀上.

像我们很多程序写的过程中不必把所有的细节都自己实现, 已经有大量的标准库(JDK提供好的代码)和海量的第三方库(其他机构组织提供的代码)供我们直接使用. 这些代码就放在一个一个的 “包” 之中. 所谓的包就相当于卖面条的超市. 只不过, 超市的面条只有寥寥几种, 而我们可以使用的 “包” , 有成千上万.

4.2 数组拷贝

import java.util.Arrays;
public class TestDemo {
    public static int[] copyArray(int[] array){
        int[] copy = new int[array.length];//copy数组的长度
        for (int i = 0; i < array.length; i++) {
            copy[i] = array[i];
        }
        return copy;
    }
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5,7,8,10};
        int[] ret = copyArray(array);
        System.out.println(Arrays.toString(ret));
    }
}
Java数组_第15张图片

第二种方法:

Java数组_第16张图片

第三种方法:array.clone();

深拷贝:拷贝之后 通过修改拷贝后的数组不会影响原来的

浅拷贝:拷贝之后 通过修改拷贝后的数组会改变原来的数组

4.3 找数组中的最大元素

给定一个整型数组, 找到其中的最大元素 (找最小元素同理)

public class TestDemo {
    public static  int maxNum(int[] array){
        if (array == null){
            return -1;
        }
        int max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (max < array[i]){
                max = array[i];
            }
        }
        return max;
    }
    public static void main(String[] args) {
        int[] array = {12,8,1,2,10};
        System.out.println(maxNum(array));
    }
}
Java数组_第17张图片

4.4 求数组中元素的平均值

public class TestDemo {
    public static double avg(int[] array){
        int sum = 0;
        for (int x:array) {
            sum += x;
        }
        return (double)sum/(double)array.length;
    }
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5,6};
        System.out.println(avg(array));
    }
}
Java数组_第18张图片

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

public class TestDemo {
    public static int find(int[] arr, int toFind){
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == toFind){
                return i;
            }
        }
        return -1;
    }
    public static void main(String[] args) {
        int[] arr = {1,2,3,10,5,6};
        System.out.println(find(arr,10));
    }
}
Java数组_第19张图片

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

key是我们传的要找的参数

如果key比我们的中间值小,我们就取左半边即right = mid - 1;

如果key比我们的中间值大,我们就取右半边即 left = mid + 1;

public class TestDemo {
    public static int binarySearch(int[] array,int key){
        int left = 0;
        int right = array.length-1;
        while (left <= right) {
            int mid = (left+right)/2;
            if (array[mid] > key){
                right = mid - 1;
            } else if(array[mid] < key){
                left = mid + 1;
            } else {
                return mid;
            }
        }
        return -1;
    }
    public static void main(String[] args) {
        int[] array = {1,2,4,7,15,17,21,32,55,88};
        int ret = binarySearch(array,17);
        System.out.println(ret);
    }
}
Java数组_第20张图片

优点:效率高

缺点:必须有序数组,否则不可使用

4.7 检查数组的有序性

public class TestDemo {
    public static boolean isSorted(int[] array){
        for (int i = 0; i < array.length - 1; i++) {
            if (array[i] > array[i+1]){
                return false;
            }
        }
        return true;
    }
    public static void main(String[] args) {
        int[] array = {1,2,3,10,5,6};
        System.out.println(isSorted(array));
    }
}
Java数组_第21张图片

4.8 数组排序(冒泡排序)

public class TestDemo {
    public static void bubbleSort(int[] array){
        for (int i = 0; i < array.length; i++) {
            boolean flg = false;
            for (int j = 0; j < array.length-i-1; j++) {
                if(array[j] >array[j+1]){
                    int tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                }
            }
            //flg == false
            if (!flg) {
                return;
            }
        }
    }
    public static void main(String[] args) {
        int[] array = {1,5,3,9,7,15,13,11};
        bubbleSort(array);
        System.out.println(Arrays.toString(array));
    }
}
Java数组_第22张图片

如果我们有10个数,我们需要交换9次,每次交换之后就会少比较一次 即-1

那么如果我们有n个数,我们就需要比较n-1次,每次交换之后我们就会少比较一次 即我们这里的j为 数组长度 - i - 1 这里的减去1是因为我们比较n个数实际只需要比较n-1次,所以我们要减去一个1 避免我们的数组越界 而减去i是因为我们没交换一次之后 最左边就会确定好一个数 我们下次比较的时候就可以不用再把它拿出来比较(即可以提高我们的程序效率)

这里用布尔boolean定义的flag是用来检查数组是否已经排序完成 如果已经排序好 便会直接返回原数组 增加程序的运行效率

这里我们还有一个方法来帮助我们排序:Array.sort(array);//(这里的排序方法我们暂时不知道)

import java.util.Arrays;
public class TestDemo {
        public static void main(String[] args) {
        int[] array = {1,5,3,9,7,15,13,11};
        Arrays.sort(array);
        System.out.println(Arrays.toString(array));
    }
}
Java数组_第23张图片

这里我们可以看到,用方法排序更快 但是要注意我们要引入包。 import java.util.Arrays;

4.9 数组逆序

public class TestDemo {
    public static void reverse(int[] array){
        int i = 0;
        int j = array.length-1;
        while (i < j) {
            int tmp = array[i];
            array[i] = array[j];
            array[j] = tmp;
            i++;
            j--;
        }
    }
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5,6,7,8,9,10};
        reverse(array);
        System.out.println(Arrays.toString(array));
    }
}
Java数组_第24张图片

4.10 数组数字排列

给定一个整型数组, 将所有的偶数放在前半部分, 将所有的奇数放在数组后半部分

public class TestDemo {
    public static void transfrom(int[] array){
        int left = 0;
        int right = array.length-1;
        while (left < right){
            //找奇数 停下来
            while (left < right && array[left] % 2 == 0){
                left++;
            }
            //找偶数 停下来
            while (left < right && array[right] % 2 != 0){
                right--;
            }
            //交换 奇数和偶数
            int tmp = array[left];
            array[left] = array[right];
            array[right] = tmp;
        }
    }
    public static void main(String[] args) {
        int[] array = {1,3,5,4,7,10,9,8,6};
        transfrom(array);
        System.out.println(Arrays.toString(array));
    }
}
Java数组_第25张图片

5. 二维数组

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

基本语法:

数据类型[][] 数组名称 = new 数据类型 [行数][列数] { 初始化数据 };
int[][] array = {{1,2,3},{4,5,6}};
int[][] array2 = new int[][]{{1,2,3},{4,5,6}};
int[][] array3 = new int[2][3];

遍历方法一(两次for循环遍历):

public class TestDemo {
    public static void main(String[] args) {
        int[][] arr = {
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 10, 11, 12}
        };
        for (int row = 0; row < arr.length; row++) {
            for (int col = 0; col < arr[row].length; col++) {
                System.out.printf("%d\t", arr[row][col]);
            }
            System.out.println("");
        }
    }
}
Java数组_第26张图片

打印二维数组是不用去数它的行数和列数 直接用 数组名.length 作为行数 数组[行] 作为列数来进行打印

打印方法二(foreach遍历):

public class TestDemo {
    public static void main(String[] args) {
        int[][] array = {
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 10, 11, 12}
        };
        for (int[] ret:array) {
            for (int x:ret) {
                System.out.print(x+" ");
            }
            System.out.println();
        }
    }
}
Java数组_第27张图片

遍历方法三( 用Arrays.deepToString()来遍历 ):

import java.util.Arrays;
public class TestDemo {
    public static void main(String[] args) {
        int[][] array = {
                {1, 2, 3, 4},
                {5, 6, 7, 8},
                {9, 10, 11, 12}
        };
        System.out.println(Arrays.deepToString(array));
    }
}
Java数组_第28张图片

不规则的二维数组定义:

Java数组_第29张图片 Java数组_第30张图片

感谢各位读者的阅读,本文章有任何错误都可以在评论区发表你们的意见,我会对文章进行改正的。如果本文章对你有帮助请动一动你们敏捷的小手点一点赞,你的每一次鼓励都是作者创作的动力哦!

你可能感兴趣的:(Java,JavaSE,java,算法,1024程序员节)