美文网首页
JavaSE进阶三 数组

JavaSE进阶三 数组

作者: SimonLike | 来源:发表于2021-06-09 10:09 被阅读0次

    数组的定义

    • 1,java语言中的数组是一种引用数据类型,不属于基本数据类型。数组的父类是Object。

    • 2,数组是一个容器,可以同时容纳多个元素。(数组是一个数据的集合)

    • 3,数组当中可以存储基本数据类型的数据,也可以存储引用数据类型的数据。

    • 4,数组是引用类型,所以数组对象是存在堆内存中的。

    • 5,数组当中如果存储的是"java对象"的话,实际上存储的是对象的"引用(内存地址)",数组中不能直接存储java对象。

    • 6,数组一旦创建,在Java语言中规定,长度不可变。(数组长度不可变)

    • 7,数组分类:一维数组,二维数组,三维数组,多维数组...(一维数组使用较多,二维偶尔使用)

    • 8,所有数组对象都有length属性(java自带的),用来获取数组中元素的个数。

    • 9,java中的数组要求数组中元素类型统一;比如int类型数组只存储int类型,Person类型数组只存储Person类型。

    • 10,数组在内存方面存储的时候,数组中的元素内存地址(存储的每个元素都是有规则的挨着排列的)是连续的,内存地址连续。 这是数组存储元素的特色,数组实际上是一种简单的数据结构。

    • 11,数组中首元素的内存地址作为整个数组对象的内存地址。

    • 12,数组中每个元素都有下标,下标从0开始,以1递增;最后一个元素的下标是:length - 1。 下标非常重要,我们对数组中元素进行"存取"的时候,都需要通过下标来进行。

    • 13,数组的优点和缺点?

      优点:
          查询/查找/检索某个下标元素时效率极高,可以说是查询效率最高的一个数据结构。
          为什么检索效率高?
              1,每个元素的内存地址在空间存储上是连续的。
              2,每个元素类型相同,所占用空间大小一样。
              3,知道第一个元素内存地址,知道每个元素占用空间的大小,知道下标,所有通过一个
              数学表达式就可以计算出某个下标元素的内存地址,直接通过内存地址定位元素,所以数组的
              检索效率是最高的。
      
              数组中存储100个元素,或者存储100万个元素,在元素查询/检索方面,效率是相同的,因为数组中元素查找的时候
              不会一个一个的找,是通过数学表达式计算出来的。(酸菜一个内存地址,直接定位的)
      缺点:
          1,由于为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或增加元素的时候,
      效率较低,因为随机增删元素会涉及后面元素统一向前或向后移位的操作。
          2,数组不能存储大数据量,因为很难在内存空间上找到一块特别大的连续空间。
      
      注意:对于数组中最后一个元素的增删是没有效率影响的。
      
    • 14,声明/定义一个一维数组

      int[] array1;
      double[] array2;
      String[] array3;
      ...
      
    • 15,初始化一个一维数组?

      • 两种方式:静态初始化一维数组,动态初始化一维数组。

      静态初始化语法格式:

        int[] array = {1,2,3,4,5}
      

      动态初始化语法格式:

        int[] array = new int[5]; // 5表示数组的元素个数。
                                 // 初始化一个5个长度int类型数组,每个元素默认值0.
        String[] names = new String[6] // 初始化一个6个长度String类型数组,每个元素默认值null
      
    • 16,什么时候采用静态初始化方式,什么时候采用动态初始化方式?

        当你创建数组的时候,确定数组中存储哪些具体元素时,采用静态初始化方式。
      
       当你创建数组的时候,不确定将来数组中存储哪些数据,你可以采用动态初始化的方式,预先分配内存空间。
      
    代码示例
    public class Array01 {
        public static void main(String[] args) {
            //使用静态初始化方式声明一个int类型数组
            int[] arr1 = {1,3,4,6,62};
            // 数组中的length属性
            System.out.println("数组中元素的个数:" + arr1.length);
    
            // 使用下标对数组中的元素进行存取
            // 取(读)
            System.out.println("数组中第一个元素:" + arr1[0]);
            System.out.println("数组中最后一个元素:" + arr1[arr1.length - 1]);
    
            // 存(修改)
            // 把第一个元素修改为11
            arr1[0] = 11;
            // 把最后一个元素修改为119
            arr1[arr1.length - 1] = 119;
    
            System.out.println("数组中第一个元素:" + arr1[0]);
            System.out.println("数组中最后一个元素:" + arr1[arr1.length - 1]);
    
           //遍历数组
            for (int i = 0 ;i < arr1.length; i++ ){
                System.out.println(arr1[i]);
            }
            // 下标为5表示第6个元素,数组中没有第6个元素,越界了;会出现异常
            // System.out.println(arr1[6]);//ArrayIndexOutOfBoundsException(数组越界异常)
    
            // 倒序遍历数组
            for (int i = arr1.length - 1 ; i >=0 ; i-- ){
                System.out.println("倒序-->" + arr1[i]);
            }
           
            // -------------------------------------------------------------------------------
           
            // 初始化动态数组
            int[] arr = new int[4];
            for (int i = 0;i < arr.length; i++){
                System.out.println("数组中下标" + i + "的元素是:" + arr[i]);
            }
    
            //初始化一个Object类型的数组,采用动态方式初始化
            Object[] objs = new Object[3]; // 3个长度,动态初始化,每个元素默认值是null
            for (int i = 0 ; i < objs.length; i++){
                System.out.println(objs[i]);
            }
            
            
        }
    }
    

    数组存储 "引用数据类型"

    • 一维数组的深入,数组中存储的类型为:引用数据类型
    • 对于数组来说,只能存储java对象的"内存地址"。数组中存储的每个元素是"引用"。
    代码示例
    public class Array02 {
        public static void main(String[] args) {
            // 创建一个Animal类型的数组
            Animal a1 = new Animal();
            Animal a2 = new Animal();
            Animal[] animals = {a1,a2};
            // 对Animal数组进行遍历
            for (int i = 0; i < animals.length; i++){
    
                // Animal a = animals[i];
                // a.move();
                // 代码合并
                animals[i].move();
            }
    
            //------------------------------------------------
    
            // 动态初始化一个长度为2的Animal类型的数组
            Animal[] animals2 = new Animal[2];
            animals2[0] = new Animal();
            // Animal数组中可以存储Cat类型数据,因为Cat是一个Animal。
            // Cat 是Animal的子类。
            animals2[1] = new Cat();
    
            //------------------------------------------------
    
            // 创建一个Animal类似的数组,数组中存储Cat和Bird
            Animal[] animals3 = {new Cat(),new Bird()};
            // 对Animal数组进行遍历
            for (int i = 0; i < animals3.length; i++){
    
                // 调用的方法是父类型中存在的方法不需要向下转型,直接使用父类引用调用即可。
                animals3[i].move();
    
                // 调用子类特有方法,父类中没有的方法  需要向下转型(多态)
                if (animals3[i] instanceof Cat){
                    ((Cat) animals3[i]).moveCat();
                }else if (animals3[i] instanceof Bird){
                    ((Bird) animals3[i]).moveBird();
                }
    
            }
        }
    }
    class Animal{
        public void move(){
            System.out.println("Animal move--");
        }
    }
    
    class Cat extends Animal{
        public void move(){
            System.out.println("Cat move--");
        }
    
        public void moveCat(){
            System.out.println("猫在抓老鼠--");
        }
    }
    
    class Bird extends Animal{
        public void move(){
            System.out.println("Bird move--");
        }
        public void moveBird(){
            System.out.println("鸟儿在飞翔--");
        }
    }
    

    数组的扩容

    • 在java开发中,数组长度一旦确定不可变,那么数组满了怎么办?

      • 数组满了,需要扩容。
      • 先新建一个大容量的数组,然后将小容量数组中的数据一个一个的拷贝到大数组中。
    • 数组扩容效率较低,因为涉及拷贝问题。所以在以后的开发中注意:尽可能少的进行数组的拷贝。

    • 可以在创建数组对象的时候预估一下多长合适,最好预估准确,这样可以减少数组的扩容次数,提高效率。

    代码示例
    public class Array03 {
        public static void main(String[] args) {
            // java中的数组是如何进行拷贝的
            // 拷贝源 (从这个数组中拷贝)
            int[] arr = {1,3,5,7,6};
            // 拷贝目标(拷贝到这个目标数组上)
            int[] dest = new int[10];// 每个默认元素为0
    
            // 调用JDK System类中的arraycopy方法,来完成数组的拷贝。
            // 将arr数组中的数据从下标1开始,拷贝2个元素
            // 放入dest数组中,从下标3开始。
            System.arraycopy(arr,1,dest,3,2);
    
            // 将arr数组中的数据全部拷贝到dest数组中,dest数组从下标0开始。
            // System.arraycopy(arr,0,dest,0,arr.length);
    
            for (int i = 0;i< dest.length; i++){
                System.out.println("dest-->" + dest[i]);
            }
    
        }
    }
    

    二维数组

    • 二维数组其实是一个特殊的一维数组,特殊在这个一维数组当中的每一个元素是一个一维数组。

    • 三维数组是一个特殊的二维数组,特殊在这个二维数组中的每一个元素是一个一维数组。实际开发中
      使用最多的是一维数组,二维数组也很少使用,三维数组几乎不用。

    • 二维数组的静态初始化

    • int[][] array = {{1,2,3},{4,5,9,6},{5,6,7},...};
      
    代码示例
    public class Array04 {
        public static void main(String[] args) {
            // 一维数组
            int[] array = {1,3,2,5,9};
            int[] array1 = {32,23,54,95};
            int[] array2 = {15,36,22,53,92,23,55};
    
            // 二维数组
            // 里面是3个一维数组
            int[][]arr = {array,array1,array2};
    
            System.out.println("二维数组长度:" + arr.length);// 3
    
            for (int i = 0;i<arr.length;i++){
                System.out.println(arr[i].length);// 输出arr中元素(一维数组)的长度: 5 4 7
            }
    
            System.out.println("--------------------------------------------------");
    
            // 取二维数组中第1个元素(一维数组)中的第1个元素
            System.out.println(arr[0][0]);
            // 取二维数组中第2个元素(一维数组)中的第3个元素
            System.out.println(arr[1][2]);
            // 取二维数组中第3个元素(一维数组)中的第4个元素
            System.out.println(arr[2][3]);
    
            // 修改二维数组中第1个元素(一维数组)中的第1个元素
            arr[0][0] = 320;
            System.out.println(arr[0][0]);
    
            System.out.println("--------------------------------------------------");
    
            // 遍历二维数组
            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("这是第" + (i + 1) + "个一维数组");
            }
    
            System.out.println("--------------------------------------------------");
    
            // 动态初始化二维数组
            // 3个一维数组,每个一维数组有4个元素
    
            int[][] a34 = new int[3][4];
    
            for (int a = 0;a<a34.length;a++){
                
                for (int j = 0; j < a34[a].length; j++){
                    System.out.print( a34[a][j] + " " );
                }
                System.out.println("这是第" + (a + 1) + "个一维数组");
            }
        }
    }
    

    数组--冒泡排序算法

    • 每次循环结束之后,都要找出最大的数据,放到参与比较的这堆数据的最右边。(冒出最大的那个气泡。)
    • 核心:拿走左边的数字和右边的数字比对,当左边 > 右边,交换位置。
    代码示例
    public class Sort01 {
        public static void main(String[] args) {
            int[] arr = {2,8,6,3,1,9,4};
            int count = 0;
            // 使用冒泡排序算法进行排序
            for (int i = arr.length-1 ; i > 0; i--) {
                System.out.println("i-->" + i);
    
                for (int j = 0; j < i ; j++) {
                    System.out.println("j=" + j + ";" + "arr[j]=" + arr[j] + ";" + "arr[j+1]=" + arr[j+1]);
    
                    if (arr[j] > arr[j+1]){
                        count++;
                        int temp ;
                        temp = arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                    }
                }
            }
    
            System.out.println("交换位置次数:"+ count);
    
            // 排序之后遍历输出
            for (int a = 0;a < arr.length;a++){
                System.out.println(arr[a]);// 从小到大
            }
        }
    }
    

    数组--选择排序

    • 每一次从这堆参与比较的数据当中找出最小值,拿着这个最小值和最前面的元素交换位置。

    • 选择排序比冒泡排序好在: 每一次交换位置都是有意义的。

    代码示例
    public class Sort02 {
        public static void main(String[] args) {
            int[] arr = {2,8,6,3,1,9,4};
    
            int count = 0;
    
            // 使用选择排序算法进行排序(7条数据循环6次)
            for (int i = 0 ; i < arr.length - 1; i++) {
                int min = i;
                for (int j = i+1; j < arr.length; j++){
                    if (arr[min] > arr[j]){
                        min = j;// 最小值元素的下标
                    }
                }
                int temp ;
                // 当i和min相等时,不交换位置,
                // 当i和min不相等是,表示有更小的元素,需要拿更小的元素和最左边的元素交换位置。
                if (min != i){
                    count++;
                    // arr[min] 最小的元素
                    // arr[i] 最前面的元素
                    temp = arr[min];
                    arr[min] = arr[i];
                    arr[i] = temp;
                }
            }
            // 相对于冒泡排序 交换位置次数变少了
            System.out.println("交换位置次数:"+ count);
    
            // 排序之后遍历输出
            for (int a = 0;a < arr.length;a++){
                System.out.println(arr[a]);// 从小到大
            }
        }
    }
    

    数组--元素的查找

    • 数组元素查找有两种方式:
      • 1,一个一个挨着找,直到找到为止。
      • 2,二分法查找(算法),这个效率较高。
        二分法查找是基于排序的基础之上的。(没有排序的数据是无法查找的)
    代码示例
    public class Search {
        public static void main(String[] args) {
            int[] arr ={2,34,55,66,22,42,68,88};
            // 需求找到22的下标,如果没找到返回-1
    
            // 一个一个挨着找
            int index = ArrSearch(arr,68);
            System.out.println(index== -1 ? "该元素不存在!":"该元素的下标是:"+index);
    
            // --------------------------------------------------------------------
    
            //  二分法查找
            Arrays.sort(arr);// 对数组进行排序
            int index2 = ArrUtilSearch(arr,42);
    
            // 以下写法是sun公司封装好的二分法查询
            //int index2 = Arrays.binarySearch(arr,42);
    
            System.out.println(index2== -1 ? "该元素不存在!":"该元素的下标是:"+index2);
        }
    
        /**
         * 从数组中查找目标元素的下标(二分法查找)
         * @param array  被检索的数组(必须是已经排序的)
         * @param i 目标元素
         * @return -1表示该元素不存在,大于等于0的数表示元素的下标
         */
        private static int ArrUtilSearch(int[] array, int i) {
    
            int begin = 0;// 开始下标
            int end = array.length -1; // 最后一个元素的下标
    
           while (begin <= end){
               int mid = (begin + end) / 2; // 中间元素下标
    
               if (array[mid] == i){
                    return mid;
                }else if (array[mid] < i){
                    // 目标元素在中间元素的右边
                    // 开始元素的下标重新赋值
                    begin = mid + 1;
                }else {
                    // 目标元素在中间元素的左边
                    // 最后一个元素的下标需要重新赋值
                    end = mid - 1;
                }
           }
    
            // 程序执行到此处,表示没有找到元素
            return -1;
        }
    
        /**
         * 从数组中检索某个元素的下标(一个一个的查找)
         * @param array 被检索的数组
         * @param a 被检索的元素
         * @return -1表示该元素不存在,大于等于0的数表示元素的下标
         */
        public static int ArrSearch(int[] array,int a){
            for (int i = 0;i<array.length;i++){
                if (array[i] == a){
                    return i;
                }
            }
             // 程序执行到此处,表示没有找到元素
            return -1;
        }
    }
    

    上篇:JavaSE进阶二 Object中的方法
    下篇:JavaSE进阶四 String

    相关文章

      网友评论

          本文标题:JavaSE进阶三 数组

          本文链接:https://www.haomeiwen.com/subject/qxgqsltx.html