The Definition And Use OF Arrays - 数组的定义与使用(万字长篇)

x33g5p2x  于2021-11-22 转载在 其他  
字(20.2k)|赞(0)|评价(0)|浏览(312)

什么是数组

数组本质上就是让我们能 "批量" 创建相同类型的变量
 也可以说是存储一组相同数据类型的数据的集合

举个例子,我现在要创建一个整形数组

int[] array
int[] 就是相当于是一个类型(整形数组类型),
而 array 就相当于 该类型的变量
总得来说 就是我创建一个变量,它的类型是整形数组类型

再来看看这个 int a =10; a是变量,类型是int,且只能存储一个值。
而 int[] array,array是变量,类型是int[],它能存储一组相同类型的数据(能存储类型相同的数据,个数不限,取决你想放多少个类型相同的数据)
例: int[] array ={1,2,3,4,5,6}

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

创建数组

1.静态初始化

基本语法

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

程序实例

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array ={1,2,3,4,5,6};
    //数据类型[]+数组名称 = { 初始化数据 }; 如果后面已将数组初始化元素值了,其中[]里不能加任何数字,这是Java创建数组时,静态初始化的一个特点.

    }
}

既然创造出数组,就必然有它存在的价值,那么数组的好处是什么?

如果我们没有数据的支持,我们想要定义 6 个整形会变得巨繁琐,反正我学了数组,像例子这种呆头呆脑的写就没用过了。

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int a = 1;
        int b = 2;
        int c = 3;
        int d = 4;
        int e = 5;
        int f = 6;
    }
}

而且对数组有一定了解的人,都知道数组的每个元素都有一个下标(从0开始),方便去寻找寻找元素.

而且是所有元素都存储在一块连续的空间上,所以从内存上看,所有元素都是紧邻(图1)</font>

图1

注意事项: 静态初始化的时候, 数组元素个数和初始化数据的格式是一致的(依据初始化元素的数量,来决定数组的大小)

2.动态初始化

基本语法

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

代码实例

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = new int[]{1,2,3,4,5,6};//其表达意思与作用与第一种方法相同,就是创建一个数组,并初始化数据
          // 两个[]中,都不能有数字的存在

        // new 是java中的一个关键字,其作用是实例化一个对象
        // 意味着 在Java 数组其实是一个对象。对象具体是什么,后面再降
        // (注意,并不是前面有new,数组才是一个对象,而是数组本来是就是一个对象)
        //先这么认为,数组就是一款网页游戏,游戏没打开之前,它只是一个图标,而new的作用就是加载这游戏成为实体,就是运行起来。
    }
}

第三种创建数组的方法

基本语法:

类型[] 数组名 = new 类型[元素个数];
    
就是第二种方法中,删除了初始化数据,前者的[]中是不能有数字的存在,后者的[]可以有具体的数字来表示数组元素的个数

代码实例

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = new int[6];
        // 该写法表达的意思是 现在有一个数组,长度为6,注意数组的元素,并没有对其初始化,在Java中,默认6个元素都是0
        // 等价于 int[] array={0,0,0,0,0,0},

    }
}

总结

一套讲解下来,你会发现在Java中 是这么来表达一个数组:int[] array
 其实数组也可以写成
    int arr[] = {1, 2, 3};
    和 C 语言一样. 但是我们还是更推荐写成 int[] arr 的形式. int和 [] 是一个整体.,因此,其实在Java中数组的写法更为准确。
    
但是不能像C语言一样这样写 int array[10] = {0};
我们前面也看到了,在创建一个数组时,[]里是不能有具体数字的存在,除了第三种方法,其它的,一律不行。

数组的使用

代码实例1(获取数组的长度)

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        // 注意在Java是没有sizeof这种东西的,那么有人可能会问,在数组元素个数未知的情况下,我们该如何获得数组元素个数?
        // 方法 : 数组名.length 这样写Java就会自动获取数组的长度(元素个数)。
        System.out.println(array.length);
    }// 图2
}

图2

代码实例2 (读取数组中某个元素)

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array={1,2,3,4,5};
        // 下标从0开始,4的下标就是 3
        // 访问方法: 数组名[下标]
        System.out.println(array[3]);
    }// 图 3
}

图3

代码实例3(数组越界问题)

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array={1,2,3,4,5};
        // 下标从0开始递增,也就是正数下标,不存在所谓的负数下标
        System.out.println(array[-1]);// 我们将访问元素的下标写成负数,让我们来看看效果如何。
    }// 图 4
}

图4

续代码3

还有一种情况:元素只有 5 个,下标最高为4,你却要访问第6个元素,也就是下标为 5 的元素
public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array={1,2,3,4,5};
        System.out.println(array[5]);// 现在我们将访问元素的下标写成5,让我们来看看效果如何。
    }// 图 5
}

图 5

代码实例4(改变数组某元素的值)

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array={1,2,3,4,5};
        // 改变 元素3 的值,也就是改变数组中下标为2的元素值
        // 方法 数组名[下标] = 新值;
        array[2]=8;
        System.out.println(array[2]);// 让我们来看看效果如何。
    }// 图 6
}

图6

注意事项

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

遍历数组

代码实例1(for循环 - 遍历打印数组元素)

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array={1,2,3,4,5};
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i]+" ");
            // println 是因为它自带换行,输出结果是竖着的,不好看。
            // 所以我使用的是 print 打印不换行
        }//图 7
    }
}

图7

代码实例2(增加for循环 - foreach - 图 8)

foreach 基本语法:

for(定义一个 与数组元素类型 相同的变量 : 数组名)
 
  什么意思呢?
foreach(增加for循环), 数组名部分,表示的意思 遍历访问数组的元素
将访问的元素赋给 冒号前面 定义的 与数组元素类型相同 的变量
 我们只需要 将该变量每次得到的元素值,打印
  就能做到不依靠元素下标,遍历打印数组所有元素
public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        for (int x:array) {
            System.out.print(x+" ");
        }
    }//图9
}

图 8

图9

那么 for 和 foreach 两者有什么区别?

最大的区别在于,for是可以拿到元素下标,而foreach拿不到元素下标
 for循环用到的地方很多,但是foreach呢?
当我们只需要元素的值时,就是使用foreach,
 当我们还需要元素的下标时,就用for。
for-each 是 for 循环的另外一种使用方式. 能够更方便的完成对数组的遍历. 可以避免循环条件和更新语句写错

代码实例3(借助Java的操作数组的工具类 Arrays 图10)

toString 将当前的数组元素,转换成字符串形式,并将其返回(也可以说 将参数的数组,以字符串形式进行输出)
import java.util.Arrays;

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        String str = Arrays.toString(array);// 创建一个字符串变量来接收它的返回值
        System.out.println(str);// 图 11
        // 因为 Arrays.toString 是有返回值的,所以可以直接输出
         System.out.println(Arrays.toString(array));//图12
    }
}

图10

图11

图12

数组作为方法的参数

首先我们需要搞懂几样东西

看代码

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array ={1,2,3,4,5};
        int a = 10;

    }
}

array 和 a 都是局部变量,在栈上开辟空间
那么问题来了,a的空间里存的是 10
而数组后面的一大坨数据,放在哪里?
和 10 一样放在栈上?
然而并不是,还记得前面说到 数组是一个对象吗?
对象是存放在 堆上的.
在这里我们就需要介绍一些东西,图13

图13(这图没截好,下半部分少了东西,不过无伤大雅)

引用很像指针,最大的区别就是不能对 引用 解引用可以对指针解引用,因为在Java没有传址的概念的,其他功能类似,但时两个东西,不是同一个东西,不能混淆在一起。

有个问题就诞生了,指针有空指针,那引用有空引用(引用里面存的地址是空的)吗?
答案是有的,只不过跟C语言不同,C是大写NULL,Java是小写null
但是请注意,举这个例子只是为了让你理解引用是一个什么东西,顺便区别两者。
C的东西只是辅助你理解Java,尽量学Java的时候,抛开C,两者(引用和指针)有很多不同地方。

代码实例

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        int[] array1 = null;
        //当一个引用被赋予null,就代表这该引用不指向任何对象
        // 既然该引用不指向任何对象,那么我这样写代码会怎么样?
        System.out.println(array1.length);
        // 求一个空引用所指向的对象的长度,但是空引用不会指向任何一个对象的
        // 何来的长度?那么代码运行的效果如何?
         图14,由图可知该写法是错误的,另外引用被指为null,堆上是不会分配内存给它的
        // 意思是你都不创建任何对象,你还想拿我空间,疯了?

        System.out.println(array1[0]);
        // 这个写法毫无疑问也是错的,没对象,你怎么访问对象里的东西?
         来看看图 15
    }
}

图14

图15

现在我们来尝试用方法来遍历打印数组

代码如下

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        print(array);
    }
    public static void print(int[] array){
        for (int x:array) {
            System.out.print(x+" ");
        }
        System.out.println();// 换行
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i]+" ");
        }
    }// 效果见图16
}//让我们通过 图17 来说明

图16

图17

举个例子,你玩游戏DNF,有仓库对吧,你会设密码对吧?要不然被盗号,就算找回来,里面的东西也不见了。
只要别人知道你的密码,他不就可以拿里面的东西了吗?
按引用传递,就相当于你找朋友刷东西,把密码告诉他,这样他才能打开你的仓库,在里面拿或者取 装备和材料,不然他怎么刷的动?

实践题

下面两题先思考答案,再去看结果附图,这样你们才能对引用的理解进一步加深
下面两题的输出结果是什么?

题目一

import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        func1(array);
        System.out.println(Arrays.toString(array));// 图 18

    }
    public static void func1(int[] array){
        array = new int[]{11,2,13,4,51};
    }

}

题目2

import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        func2(array);
        System.out.println(Arrays.toString(array));
    }
    public static void func2(int[] array){
        array[0] = 99;
    }
}//图19

图 18

图19

##题目路2的两个array等价于下面的程序 array 和 array2

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        int[] array2 = array;
     这代表  array2 这个引用 指向 引用array指向 的对象
     array 和 array2 指向的是同一个对象
    }

}

图解(图20)

还有一个问题值得讨论:一个引用 是否 能同时 指向 多个对象?

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array1 = new int[]{1,2,3,4,5};
        array1 = new int[10];
        array1 = new int[2];
        array1 = new int[4];
    }
}

答案是不能,如果前面认真看了,就该知道此时的array1,存储的地址,已经被改变(array是一个局部变量,意味着存的值是可以被改变的),现在存的是 new int[4] 的这个对象的地址, 而不是说,存几个对象的地址。

结论

一个引用只能指向一个对象(一个引用只能保存一个对象的地址)

另外注意

写了这么多,有没有发现我们写的引用,都是在栈上
  那么 引用 就一定在栈上吗?
 答案是不一定的,因为一个变量在不在栈上,是你变量的性质决定的
 
   如果你的引用是一个局部变量,那就一定在栈上
 实例成员变量那就不一定了。(先告诉你们有这个概念,等后面讲到成员变量时,再说)

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

这时候,我们来讲讲前面文章留下来的问题(使用方法,来交换两个变量的值)

因为Java中是取不到栈上变量的地址的,也就意味不能传址,所以无法按照C一样去实现
 
 但是今天我们学了数组,我们用数组的方式来解决问题
import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        //int a = 10;
        //int b = 20;
        // 我们将其放在一个数组里,进行交换
        int[] array = {10,20};
        swap(array);
        System.out.println(Arrays.toString(array));
    }
    public static void swap(int[] array){
        int tmp = array[0];
        array[0] = array[1];
        array[1] = tmp;
    }
}// 图21,这只是一种取巧的方式来进行交换,等到我讲到类和对象的那个时候,会再讲几种方法

图21

数组作为方法的返回值

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

先来写没有返回值的(将原来的数组元素都扩大2倍)

import java.util.Arrays;

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array={1,2,3,4,5};
        func(array);
        System.out.println(Arrays.toString(array));
    }
    public static void func(int[] array){
        for (int i = 0; i < array.length; i++) {
            array[i]=2*array[i];
        }
    }//图22
}// 图解(图23)

图 22

图23

现在我们来写有返回值的(不在原来的数组上扩大2倍,保护原来的数组不被破坏)

代码入下

import java.util.Arrays;

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array={1,2,3,4,5};
         int[] ret = func(array);//建立数组类型(对象)变量来接收
        System.out.println(Arrays.toString(ret));
        System.out.println(Arrays.toString(array));
    }
    public static int[] func(int[] array){
         int[] ret = new int[array.length];
        for (int i = 0; i < array.length; i++) {
            ret[i]=2*array[i];
        }
        return ret;//这里返回是 新建对象(数组),在堆上的地址
    }//图24
}// 图解(图25)

图24

图25

这样的话就不会破坏原有数组了.
另外由于数组是引用类型, 返回的时候只是将这个数组的首地址返回给函数调用者, 没有拷贝数组内容, 从而比较高效.
有的人可能会说,方法调用完的时候,不是会销毁栈上的空间,我们这样将地址带回来,不会存在一些问题吗?
请注意 new 的对象,都是存在堆上的,而不是栈上。这里的返回的是将堆上对象的地址(注意返回类型int[]),而不是局部变量ret,所以不会出现问题

数组练习

模拟实现 toString 函数

toString 将当前的数组元素,转换成字符串形式,并将其返回(也可以说 将参数的数组,以字符串形式进行输出) 图12

代码如下

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array={1,2,3,4,5};
        String str = myToString(array);
        System.out.println(str);
    }
    public static String myToString(int[] array){
        if(array == null){
            return "null";// 判断是否形参接收的地址,是否为空指针
        }
        String str = "[";
        for (int i = 0; i < array.length; i++) {
            str+=array[i];// 用了一开始拼接输出方式,字符串开头后面用+拼接,使其成为一个字符串
            if(i< array.length-1){// array.length-1,因为最后一个元素不用加 ,号
                str+=",";
            }
        }
        str+="]";
        return  str;
    }
}// 图26

图26

找数组中的最大元素

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {12,8,1,2,10};
        System.out.println(maxNum(array));
    }
    public static int maxNum(int[] array){
        if(array==null){
            return -1;// 假设 -1 意味着array存储的是空指针
        }
        if(0 == array.length){
            return -2;// 假设 -2 意味着 array 没有元素(int[] array = {})
            // 故 数组长度为0(元素个数为0).
        }
        int max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max<array[i]){
                max = array[i];
            }
        }
        return max;
    }// 图 27
}

图27

查找数组中指定元素(顺序查找),返回它的下标

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,23,213,67,123};
        System.out.println(find(array,23));
    }
    public static int find(int[] array,int y){

        for (int i = 0; i < array.length; i++) {
            if (array[i] == y){
               return i;
            }
        }
        return -1;// 表示没找到,因为数组的下标不可能存在负数
    }
}

查找数组中指定元素(二分查找),返回其下标

针对有序数组, 可以使用更高效的二分查找
public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        System.out.println(find(array,4));
    }
    public static int find(int[] array,int y){
        int right = array.length-1;// 右下标
        int left = 0;// 左下标
        int mid = 0;
        while(right>=left){
            mid=(right+left)/2;
            if(array[mid]>y){
                right--;
            }
            else if(array[mid]<y){
                left++;
            }else{
                return mid;
            }
        }
        return -1;//表示没找到
    }
}// 图28
 图释( 图29)

图28

图29

其实在Java中有一个工具,就是二分查找,意味这我们没必要像上面一样去写一个二分查找的方法

写法: Arrays.binarySearch(数组名,想查找的元素)

代码如下

import java.util.Arrays;

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        System.out.println(Arrays.binarySearch(array,2));// 图30
        // 如果找一个不存在的数呢?
        System.out.println(Arrays.binarySearch(array,6));// 图 31
        // 有人会好奇,为什么是-6?
        // 左键点击 binarySearch,ctrl + 左键点击
        // 再点击 binarySearch,ctrl + 左键点击
         你会看到 图 32
        // -(low+1),意思是最后low的位置下标+1,取负
        // 因为我们要找的数,比有序数组里所有元素都要大,所以最后low的位置应该最后一个元素的位置
        // 也就是下标为 5 的位置,对其加一取负,所以输出的值是-6
        // 另外注意,下标是没有负数的,别以为这-6 是一个元素的下标,不是的啊。
        // 只是告诉你找不到。
        // 下标不可能为负,你给我个负数,不是找不到是什么
    }
}

图30

图31

图32

二分查找对于有序数列的效率是非常高的,你想想取一个中间下标的值

不管你要找的数,是大于或者小于这个值,都意味着有一边的数据直接pass。

图33

检查数组的有序性(升序:从左往右,从小到大)

public class TheDefinitionAndUseOfArrays {
     public static void main(String[] args) {
         int[] array = {1,2,3,10,5,6};
         System.out.println(isSorted(array));
     }
     public static  boolean isSorted(int[] array){
         for (int i = 0; i < array.length-1; i++) {
// 注意 array.length-1,为什么减一呢?因为你想想看,假设有6个元素(array.length == 6)
// 但是下标最大为 5 == array.length-1,因为有小于号,所以这个减一,可以被省略,那为什么还要减一?
// 注意我们的if条件(array[i]>array[i+1]),当循环元素到下标为5的元素(最后一个元素),就会有问题了
// array[i+1] == array[6] == 第七个元素,第七个元素有没有?没有。那我们访问的话会产生数组越界访问错误
// 图35
             if(array[i]>array[i+1]){// 左边的元素比右边的元素大,那么就不满足升序,称为乱序
                 return false;// 乱序
             }
         }
         return true;// 有序
     }
}// 图34

图34

图35

数组排序(冒泡排序)

升序

import java.util.Arrays;

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {9,5,2,7};// 我们假设一个整形数组
        bubbleSort(array);
        // 调用我们的自定义的冒泡的方法,把我们的数组名(引用)扔过去,按引用传递
        System.out.println(Arrays.toString(array));// 偷个油,不用循环打印,将其转换成字符串输出
    }
    public static void bubbleSort(int[] array){// 创建一个 数组变量,来接收传参
         // 理一下思绪,首先假设我定义一个 i 来表示元素下标,通过引用(数组名) 和 [] 来访问下标所对应的函数。
        //既然要排升序,肯定要比较大小,不可能自己跟自己比吧?要跟它后面的元素比,比它大,相互交换位置,反则什么都不做(升序)。
        // 但是不可能只比一次,我这里有四个元素,至少要比3次,才能完成把最大的数放在最后。
        // 有的人可能会说,不是有4个元素吗?不应该是4次,记住我们2个一比,每次都是前面比后面,
        // 到了倒数第二个元素,它是最后的元素相比较,比较完了,那么最后一个元素已经最大的了,还有比较的意义吗?没有!
        //而且这是,一趟,还要比较3趟。我们第一趟比较只是把最大的数,放到了最后,其它三个数,还不知是否是升序
         图 36

        // 现在我们正式开始
        for (int i = 0; i < array.length; i++) {// 有4个元素,需要比 3 趟
            // 根据 图36 最后的结论,表示有可能,在未来完成某一趟比较之后,后面的数值已经有序,那我们没有比较的必要
            // 所以 我们在这里定义一个 flag = 1,再在 交换程序中 写一个flag=0;
            // 什么意思呢? 就是你只要交换了两元素的位置,说明这一趟,数组肯定不是有序的,你都交换了,还有序?
            // 如果 这一趟下来flag还是等于1,我们结束整个排序,为什么?因为根据图36来看,冒泡排序的比较模式 是交换式比较,
            // 1 和 2 一比,比完; 2 和 3一比,也就是如果flag等于1,说明后面没有发生交换
            // 后面的每一位都比自身前一位都要大(比前面的位,早在之前就给你换了)
            // 说明升序排列完成
            int flag =1;// 假设这一趟是有序的

            // 每一趟的比较过程
            for (int j = 0; j < array.length-1-i; j++) {// 减一是为了防止越界,这个应该都懂
                // 至于减 i,想想看,我们每一趟比较,把最大的数往后排,小的数往前挪,作为下一次标胶的起点
                // 再加上这一趟比下来,可以说一个数跟其他都比较了,只有全比较了,我们才能知道最大数究竟是谁?
                // 得出了最大数,放在最后,那还有比较的必要,再去比,就是疯了。(都打过一架了,还输了,你还找别人去单挑,不是疯了,就是zz)
                // 所以每比完一趟,我们比较次数就减一,
                // 第一次,i==0,是因为倒数2个大值,还需要比较,你再减一个1,还比什么。搞黑手?还没比,就把最后的一位数,放在最后一位
                // 万一倒数第二位,比最后的数,要大呢?,这不是搞黑幕,是搞什么?嗯?
                if(array[j]>array[j+1]){
                    // 升序,前者比后者小,只要前者比后者大,就意味着需要交换位置
                    int tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1]=tmp;
                    // 假设
                    // 2 1
                    // tmp = 2 == array[0] ; array[0] = array[1] == 1,此时array[0]已经被改变
                    // array [1] = tmp ==2;
                    // 即 数组元素顺序 为 1,2

                    flag = 0;// 都交换了,那么肯定是不是有序的
                }
            }
            if(1== flag){
                break;//如果flag等于1,说明后面的每一位都比自身前一位都要大,那就说明没有比较的意义,同时意味着排序完成,跳出循环。
            }
        }

        来看看看结果 图 37
    }
}

图36

图37

经过上面的讲解,至少你对冒泡有一定的了解,很遗憾,我想告诉你,我们辛辛苦苦做出的冒泡排序,在Java是有函数可以做到的(但并不意味我们刚才的努力都是白费,万一面试官,让你模拟实现一个冒泡排序呢?)对吧? 废话不多说,我们来看看这哥函数是什么?

Arrays.sort

import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {9,5,2,7};
        Arrays.sort(array);// 是借助Java工具Arrays.sort来完成的,图 39
        System.out.println(Arrays.toString(array));// 图38
    }
}

图38

图39

我们在顺便拓展一下 Arrays 的其它功能

Arrays.fill

import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = new int[10];// 此时数组默认10个元素都是0,图40
        Arrays.fill(array,99);// fill 是 填的意思,图 42
        System.out.println(Arrays.toString(array));// 效果见 图 41
    }
}

图 40

图41

图42

根据图 43,发现 Arrays。fill 的参数,还可以写两个

图43

import java.util.Arrays;
public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = new int[10];// 此时数组默认10个元素都是0,图40
        Arrays.fill(array,0,5,99);// 意思将下标为0的元素到下标为4的元素全部置为0
        // 至于为什么不是下标为5,是因为 该范围是 左闭右开 [0,5) == 0=<下标 && 下标<5
        System.out.println(Arrays.toString(array));// 效果见 图 44
    }
}

图44

数组逆序

假设数组元素顺序为 1,2,3,4,5(并不一定是有序,只是为了举例方便)
结果为       5,4,3,2,1
import java.util.Arrays;

public  class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        echange(array);
        System.out.println(Arrays.toString(array));// 图 45
    }
    public static void echange(int[] array){
        int left =0;// 左下标
        int right = array.length-1;// 右下标
        while(left<right){
            // 就是两边的数据对着换
            // 当left 和 right 所指向的下标相遇是,也就同一个元素
            // 循环终止
            int tmp = array[left];
            array[left]=array[right];
            array[right]= tmp;
            right--;
            left++;
        }
    }
}

图45

数组数字排列

给定一个整型数组, 将所有的偶数放在前半部分, 将所有的奇数放在数组后半部分 
 例如
    {1, 2, 3, 4}
    调整后得到
    {4, 2, 3, 1}
import java.util.Arrays;

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4};
        transform(array);
        System.out.println(Arrays.toString(array));// 图 46
    }
    public static void transform(int[] array){
        int left = 0;
        int right = array.length-1;
        while(left<right){
            while(left<right && array[left]%2 == 0){
                // 找奇数(%2 !=0),找到了,跳出循环
                  left++;
                  // left 是不能一直加加的,如果没有 left<right 这个限制条件,在交换完成(left和right相遇),该下标还会一直 ++。
                 // 甚至可能会越界(全偶数),因为(小)循环体执行完了,才会去判断(大)循环条件,
            }
            while(left<right && array[right]%2 != 0 ){
                // 找偶数(%2 == 0),找到了,跳出循环
                right--;// 这个与left同理
            }
            int tmp = array[left];
            array[left] = array[right];
            array[right] = tmp;
        }
    }
}

图46

数组拷贝

拷贝方法1 循环拷贝

假设你要拷贝的数组 是 int[] array = {1,2,3,4,5}
 那么我就需要 创一个相同类型,元素个数相同的 数组变量array2来接收(int[] array2 [array.length])
通过 对应的下标进行复制拷贝

代码如下

import java.util.Arrays;

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array={1,2,3,4,5};
        int[] array2 = copyOf(array);// 是方法中 引用ret存储值的一份拷贝,能够访问 ret 指向的堆上的对象
        System.out.println(Arrays.toString(array));
        System.out.println(Arrays.toString(array2));// 图 47
    }
    public static int[] copyOf(int[] array){
        int[] ret = new int[array.length];//创一个相同类型,元素个数相同的 数组变量array2来接收 array 的元素
        for (int i = 0; i < array.length; i++) {
            ret[i] = array[i];//通过 对应的下标进行复制拷贝
        }
        return  ret;// 将对象的地址转过去
    }
}// 图 48

图47

图48

方法2

利用Java提供的函数: Arrays.copyOf
 图49

图 49

代码如下

import java.util.Arrays;

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        int[] array2 = Arrays.copyOf(array,array.length);
        System.out.println(Arrays.toString(array2));// 图 50
        // 既然能规定 拷贝数量,我输入拷贝数量超过,源数组array的元素个数呢?
        int[] array3 = Arrays.copyOf(array,array.length*2);
        System.out.println(Arrays.toString(array3));// 图 51,由图可知类似扩容
    }// 但是注意一点,本质是copy明白嘛? 这扩容出来的数组,跟元素组,不是同一个数组
     左键点击copyOf +Ctrl+左键),来看看得到的  图52 ,由图52,还可以得知 如果我们想"扩容",输入的倍数必须整数,因为它的长度类型规定为整形
}

图50

图51

图52

方法3

不知道你们注意到没? 图52中的一个程序语句
 图 53
图中所圈部分,就是我们拷贝数组的第三种方法

图53

但是我们先来看第四种方法,为第三种方法做铺垫

Arrays.copyOfRange()

图54

代码如下

import java.util.Arrays;

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        int[] ret = Arrays.copyOfRange(array,0,4);
        System.out.println(Arrays.toString(ret));//图 55
    }
}

图 55

好,现在我们来看看 第三方法

import java.util.Arrays;

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        int[] array2 = new int[array.length];
        System.arraycopy(array,0,array2,0,array.length);
        // 跟用for循环进行拷贝时一个道理,根据对应的下标进行赋值拷贝
        System.out.println(Arrays.toString(array2));
        // 图 56
    }
}

图56

拓展

图 57

注意图中所圈部分,怎么进我就不再教了,忘了就往上翻。
我来提示你,System.arraycopy是不是没有实现过程,只是一个类似函数声明一样,放在那里?
那它是怎么实现数组拷贝的呢?
这就跟我们所圈起来的native(本地的)有关,
所有被 native 所修饰的方法,方法的实现过程,都已经被 C/C++ 实现了
我们是看不到运行过程的,这样写的最大好处就是 速度快,效率高

方法 5 数组克隆

基本语法:

数组名.clone();
import java.util.Arrays;

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[] array = {1,2,3,4,5};
        int[] array2 = array.clone();// 类似 副本,不是游戏副本啊!
        // 可以理解为是一份资料的备份

        System.out.println(Arrays.toString(array2));
    }// 图58
}

图58

在 一维数组的最后我们在讲一个概念, 深拷贝 和 前拷贝

图 59

&ensp;

二维数组

二维数组的创建

基本语法1

数据类型[][] 数组名 = { 初始化数据 }

基本语法2

数据类型[][] 数组名 = new 数据类型[][]{ 初始化数据 }

基本语法3

数据类型[][] 数组名 = new 数据类型[行数][列数]
跟一维数组几乎一样,只要初始化了数据,你的[][]里就不能有数字的存在

代码如下

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        // 创建一个 2行3列的二维数组
        int[][] array = {{1,2,3},{4,5,6}};
        int[][] array2 = new int[][]{{1,2,3},{4,5,6}};
        int[][] array3 = new int[2][3];
    }
}

二维数组的打印

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        // 创建一个 2行3列的二维数组
        int[][] array = {{1,2,3},{4,5,6}};
        int[][] array2 = new int[][]{{1,2,3},{4,5,6}};
        int[][] array3 = new int[2][3];
        print(array);
    }
    public static void print(int[][] array){
        // 按照我们以前对C的理解,二维数组的存储模式应该为 图60
        for (int i = 0; i < 2; i++) {
            for (int j = 0; j < 3; j++) {
                //打印一行数据
                System.out.print(array[i][j] + " ");
            }
            System.out.println();// 换行
        }
    }
}// 效果图 61

图60

图 61

由图的结果来看没问题
但是我总不能,每个二维数组都自己去算它有几个元素吧。
问题就在于怎么去获得 行 和 列
这里就引用C语言的一个概念,二维数组是一个特殊的一维数组
经过前面讲解,大家都知道数组是存储在堆上的,再加上面这句话的概念
让我们看看图62

图 62

接着我们来对上面的程序(二维数组的打印)进行改良

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        // 创建一个 2行3列的二维数组
        int[][] array = {{1,2,3},{4,5,6}};
        int[][] array2 = new int[][]{{1,2,3},{4,5,6}};
        int[][] array3 = new int[2][3];
        print(array);
        // 这里我们在用实例证明一下
        // array.length 是否能的得到 行数 2
        System.out.println(array.length);
        // array[下标].length 是否能得到 列数3
        System.out.println(array[0].length);
        System.out.println(array[1].length);
    }
    public static void print(int[][] array){
        // 按照我们以前对C的理解,二维数组的存储模式应该为图60
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                //打印一行数据
                System.out.print(array[i][j] + " ");
            }
            System.out.println();// 换行
        }
    }
}// 图63

图63

前面使用for循环来打印数组,这回我们foreach

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[][] array = {{1,2,3},{4,5,6}};
        print(array);
    }
    public static void print(int[][] array){
        for (int[] ret:array) {// array元素的数据类型是一个一维数组,我就需要一个相同的类型的变量来接收
            for (int x:ret) {
                // ret是一个一维数组的数组名,接下来就跟前面使用foreach是一样,将 引用ret 所指向的对象(数组)的元素,
                // 读取并赋值给 与其元素类型相同的变量, 我们再将其输出。就可以了
                System.out.print(x + " " );
            }
            System.out.println();//换行
        }
    }
}// 图 64

图64

还有一种输出二维数组的方法

在前面,我们使用了 Arrays.toString,将数组转换的字符串输出

 二维数组也有对应的 方法: Arrays.deepToString(数组名)
import java.util.Arrays;

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[][] array = {{1,2,3},{4,5,6}};
        System.out.println(Arrays.deepToString(array));
    }
}//图 65

图65

接下来,我会让你们见识到一种特别的二维数组

代码案例

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[][] array = {{1,2},{1,2,3}};
        for (int[] ret:array) {
            for (int x:ret) {
                System.out.print(x+" ");
            }
            System.out.println();// 换行
        }
    }
}//图 66,见证奇迹,参考图62

图66

再来举个例子

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[][] array = new int[2][];
        // 在C语言中,二维数组,是不能省略列的,行可以省略
        // 而Java与之相反,行不能省略,列可以(图67、68)
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                System.out.print(array[i][j] + " ");
            }
            System.out.println();// 换行
        }
    }//图 69,图 70
}

图67

图68

图69

图70

哪有人可能会问,虽然写法没问题,但是程序运行会报错,那么省略列的意义在哪?

意义在于我们可以改,去赋予
这种二维数组,我们将其称为 不规则的二维数组,

代码如下

import java.util.Arrays;

public class TheDefinitionAndUseOfArrays {
    public static void main(String[] args) {
        int[][] array = new int[2][];
        array[0]=new int[3];// 意味着第一个数组长度为3
        array[1]=new int[2];// 意味着第二个数组长度为2
        System.out.println(Arrays.deepToString(array));
    }
}// 图71,72

图71

图72

本文结束。

相关文章

目录