zoukankan      html  css  js  c++  java
  • JAVA 数组

       JAVA数组与容器类主要有三方面的区别:效率、类型和保存基本类型的能力。在JAVA中,数组是一种效率最高的存储和随机访问对象引用序列的方式。数组就是一个简单的线性数列,这使得元素访问非常快速。但是为此付出的代价却是数组的大小被固定,并且在其生命周期中不可改变。

            由于范型和自动包装机制的出现,容器已经可以与数组几乎一样方便地用于基本类型中了。数组和容器都可以一定程度上防止你滥用他们,如果越界,就会得到RuntimeException异常。数组硕果仅存的优势便是效率,然而,如果要解决更一般化的问题,那数组可能会受到过多的限制,因此这种情况下大部分还是会选择容器。

            因此,如果使用最近的JAVA版本,应该优先选择容器而不是数组。只有在已证明性能已成为问题,并且切换到数组可以提高性能时,才应该重构程序为数组。

     

    【初始化】

             JAVA对数组初始化有很严格的规定,这样可以有效地防止滥用数组。如果初始化错误,会直接得到CompileException而不是RuntimeException。在未对数组正确初始化之前,无法用此数组引用做任何事情。

            数组定义有int[] array 和int array[],一般采用第一种风格,可以将类型与变量名分开。

            数组的初始化有两种方式,静态初始化和动态初始化。初始化的时候必须指定长度,多维数组第一维的长度必须指出,同时必须由高维向低维定义。初始化动作可以在代码的任何地方,而用{}方式只能在创建数组的地方出现。具体初始化方式见程序:

    public class javaArrayInit{
        public static void main(String args[]){
            int[] arrayA; //未初始化
            int[] arrayB = new int[5]; //静态初始化
            //System.out.println(arrayA.length);  //CompileException
            System.out.println("arrayB length: " + arrayB.length); //无法得到实际保存的元素个数
            
            arrayA = new int[10]; //动态初始化
            System.out.println("arrayA length: " + arrayA.length);
            
            int[] arrayC = new int[]{1,2,3,4};
            System.out.println("arrayC length: " + arrayC.length);
            
            //int[] arrayD = new int[1]{1}; //错误的初始化,不能同时定义维和初始化值
            
            int[][] arrayE = new int[1][];
            System.out.println("arrayE length: " + arrayE.length);
            
            //int[][] arrayF = new int[][2]; //应先指定高维的长度
            
            int[][] arrayG = new int[][]{{1,2,3,4},{5,6,7},{7,24,23,24}};
            System.out.println("arrayG length: " + arrayG.length);
            
            int[][][] arrayH = new int[][][]{{{1,2,3},{4,5,6},{7,8,9},{10,11,12}}};
            System.out.println("arrayH length: " + arrayH.length);
            
            dummyArray[] arrayI = {new dummyArray(),new dummyArray()}; //自定义数组类型
            System.out.println("arrayI length: " + arrayI.length);
            System.out.println("arrayI[1]: " + arrayI[1].getValue());
            
            dummyArray[] arrayK = new dummyArray[5];
            System.out.println("arrayK[0]: " + arrayK[0]); //null
            for(int i = 0; i < arrayK.length; i++){
                arrayK[i] = new dummyArray();
            }
            System.out.println("arrayK[0]: " + arrayK[0].getValue()); //2
        }
    }
    
    class dummyArray{
        private static int temp;
        private final int arrayValue = temp++;
        public int getValue(){
            return arrayValue;
        }
    }
    
    
    输出:
    
    
    
    arrayB length: 5
    arrayA length: 10
    arrayC length: 4
    arrayE length: 1
    arrayG length: 3
    arrayH length: 1
    arrayI length: 2
    arrayI[1]: 1
    arrayK[0]: null
    arrayK[0]: 2

    【length】

            只读成员length是数组对象的一部分(虽然实际上API里面并没有声明这个变量,是运行时动态生成),这是唯一一个可以访问的字段或方法。而[]语法是访问数组对象的唯一方式,容器是通过get()方法访问。可以使用Array.length来得到数组的大小,注意与String类型的String.length()区分。Array使用的是成员变量的方式,而String使用的是成员方法的方式。同时,Array.length只能得到数组的大小,而无法得到数组实际有多少元素。多维数组的length只计算第一维的长度。

    public class javaArrayLength{
        public static void main(String args[]){
            int[] arrayA = new int[15];
            arrayA[1] = 1;
            arrayA[2] = 2;
            arrayA[3] = 3;
            System.out.println("arrayA length: " + arrayA.length);
            
            int[][] arrayB = new int[10][];
            System.out.println("arrayB length: " + arrayB.length);
            
            int[][] arrayC = new int[][]{{1,1,1,2,},{1,1,2,3,4,5},{4,5,6,7,7},};//注意后面的逗号
            System.out.println("arrayC length: " + arrayC.length);
            
            int[][] arrayD = new int[][]{{1,1,1,2,},{1,1,2,3,4,5},{4,5,6,7,7},{}};
            System.out.println("arrayD length: " + arrayD.length);
        }
    }
    输出:
    
    
    
    arrayA length: 15
    arrayB length: 10
    arrayC length: 3
    arrayD length: 4

    【Arrays.fill】

            Arrays.fill是一个作用十分有限的方法,因为它只能用同一个值填充各个位置(如果是对象,则复制同一个引用进行填充)。使用Arrays.fill可以填充整个数组或者数组的某一个区域,但是由于只能用单一的数值来调用Arrays.fill,因此作用并不是很大。

     

    【赋值与引用】

            JAVA数组初始化的时候拥有的只是对数组的引用,并没有给数组分配存储空间。因此,数组之间的复制不能简单地用“=”赋值,因为操作的是同一对象。如下程序:

    public class javaArrayQuote{
        public static void main(String args[]){
            String testA = "testA";
            String testB = "testB";
            String[] arrayA = new String[]{"arrayA"};
            String[] arrayB = new String[]{"arrayB"};
            testB = testA;
            testB = "testB change";
            System.out.println("I'm testA,I have no changed: " + testA);
            arrayB = arrayA;
            arrayB[0] = "arrayB have changed";
            System.out.println("I'm arrayA, I have no changed: " + arrayA[0]);
            
        }
    }
    输出:
    
    
    
    I'm testA,I have no changed:testA
    I'm arrayA, I have no changed:arrayB have changed

            可以看出,我们改变arrayB[0]的值,改变的是引用的数组,因此我们输出arrayA[0],其实和arrayB[0]一样。

     

    【数组复制】

            JAVA中复制数组的方法:

     

            1.使用FOR循环复制全部或指定元素,效率较低

            2.使用clone方法,得到数组的值,而不是引用。然而clone不能复制指定元素,灵活性较低

            3.使用System.arraycopy(src, srcPos, dest, destPos, length)方法,java标准类库提供有static方法 System.arraycopy(),用它复制数组要比for循环快很多,System.arraycopy()针对所有类型做了重载,基本类型数组和对象数组都可以用System.arraycopy()复制,但是对象数组只是复制引用,不会出现两份对象的拷贝。这被称作浅复制(shallowcopy)。

                   src:源数组;

                    srcPos:源数组要复制的起始位置;

                    dest:目的数组;

                    destPos:目的数组放置的起始位置;

                    length:复制的长度.

            注意:System.arraycopy()不会进行自动包装和自动拆包,因此两个数组必须是同类型或者可以转换为同类型的数组。同时,这个方法也可以用于复制数组本身。

            int[] test ={0,1,2,3,4,5,6};

            System.arraycopy(test,0,test,3,3);

            则结果为:{0,1,2,0,1,2,6};

            测试程序如下:

     

    public class javaArrayCopy{
        public static void main(String args[]){
            int[] array = {1,2,3,4,5,6,7,8,9};
            //for循环方法
            int[] arrayA = new int[9];
            for(int i = 0; i < arrayA.length; i++){
                arrayA[i] = array[i];
                System.out.print(arrayA[i] + ",");
            }
            //测试
            System.out.println("");
            arrayA[1] = 19;
            for(int i = 0; i < arrayA.length; i++){
                System.out.print(arrayA[i] + ",");
            }
            System.out.println("");
            for(int i = 0; i < array.length; i++){
                System.out.print(array[i] + ",");
            }
            System.out.println("");
            
            //clone方法
            int[] arrayB = new int[9];
            arrayB = array.clone();
            //测试
            arrayB[1] = 19;
            for(int i = 0; i < arrayB.length; i++){
                System.out.print(arrayB[i] + ",");
            }
            System.out.println("");
            for(int i = 0; i < array.length; i++){
                System.out.print(array[i] + ",");
            }
            System.out.println("");
            
            //System.arrayCopy 方法
            int[] arrayC = new int[9];
            System.arraycopy(array, 0, arrayC, 0, arrayC.length);
            //测试
            arrayC[1] = 19;
            for(int i = 0; i < arrayC.length; i++){
                System.out.print(arrayC[i] + ",");
            }
            System.out.println("");
            for(int i = 0; i < array.length; i++){
                System.out.print(array[i] + ",");
            }
        }
    }

    【数组比较】

            Arrays提供了重载后的equals()方法,针对所有类型和Object类型都做了重载,用来比较整个数组。数组相等的条件是元素个数必须相等,并且对应位置的元素也相等。而多维数组的比较用deepEquals()方法。Array.equals()方法比较的两个数组必须是同类型的数组。

    import java.util.Arrays;
    
    public class javaArrayEquals{
        public static void main(String args[]){
            int[] arrayA = {1,2,3};
            int[] arrayB = {1,2,3,};
            int[] arrayC = new int[4]; //if int[] arrayC = new int[3],return true
            arrayC[0] = 1;
            arrayC[1] = 2;
            arrayC[2] = 3;
            System.out.println(Arrays.equals(arrayA, arrayB));
            System.out.println(Arrays.equals(arrayA, arrayC));
            
            String[][] arrayD = {{"a","b"},{"c","d"}};
            String[][] arrayE = {{"a","b"},{"c","d"}};
            System.out.println(Arrays.deepEquals(arrayD, arrayE));
        }
    }

    【数组排序与查找】

            数组提供了内置的排序方法sort(),可以对任意基本类型数组或者对象数组进行排序(该对象必须实现Comparable接口或者具有相关联的Comparator)。JAVA对不同的类型提供了不同的排序方法----针对基本类型设计的快速排序,以及针对对象设计的“稳定归并排序”,所以无需担心数组排序的效率问题。

             binarySearch()用于在以排好序的数组中快速查找元素,如果对未排序的数组使用binarySearch(),那么将产生难以预料的结果。

     

    【返回数组】

            C和C++不能返回一个数组,只能返回指向数组的指针,因为返回数组使得控制数组的生命周期变得困难,并且容易造成内存泄漏。java允许直接返回一个数组,并且可以由垃圾回收机制回收。

     

    【数组与容器转换】【无法转换基本类型数组】

     

    数组转为List:

    import java.util.*;
    
    public class arrayToList{
        public static void main(String args[]){
            String[] arrayA = {"a","b","c"}; 
            List listA = java.util.Arrays.asList(arrayA);
            System.out.println("listA: " + listA);
            
            int[] arrayB = {1,2,3}; 
            List listB = java.util.Arrays.asList(arrayB);
            System.out.println("listB: " + listB);
            
            Integer[] arrayC = {1,2,3};
            List listC = java.util.Arrays.asList(arrayC);
            System.out.println("listC: " + listC);
        }
    }
    
    输出:
    
    
    
    
    
    listA: [a, b, c]
    listB: [[I@de6ced]
    listC: [1, 2, 3]

    为什么int和Integer输出会不同呢?

    List转为数组


    import java.util.*;
    
    public class listToArray{
        public static void main(String args[]){
            List<String> list = new ArrayList<String>();
            String[] array;
            list.add("testA");
            list.add("testB");
            list.add("testC");
            System.out.println("list: " + list);
            
            String[] strings = new String[list.size()];
            array = list.toArray(strings);
            for(int i = 0, j = array.length; i < j; i++){
                System.out.print(array[i] + ",");
            }
    
        }
    }
    
    输出为:
    
    
    
    list: [testA, testB, testC]
    testA,testB,testC

    【去除重复数据】

            利用数组和容器转换可以方便地去除数组重复数据,不过如果数组过大,效率是一个问题。

    import java.util.*;
    
    public class javaArrayUnique{
        public static void main(String args[]){
            String[] array = {"a","b","a","a","c","b"};
            arrayUnique(array);
            //test
            for(int i = 0, j = arrayUnique(array).length; i < j; i++){
                System.out.print(arrayUnique(array)[i] + ",");
            }
        }
        
        public static String[] arrayUnique(String[] array){
            List<String> list = new ArrayList<String>();
            for(int i = 0, j = array.length; i < j; i++){
                if(!list.contains(array[i])){
                    list.add(array[i]);
                }
            }
            String[] strings = new String[list.size()];
            String[] arrayUnique = list.toArray(strings);
            return arrayUnique;
        }
    }

          关于效率问题,我做了一个对比,在我电脑上运行十万数据的数组大概是577ms,而运行一百万数据的数据大约要5663ms。这还跟计算机的运行能力有关,但是明显是随着数组大小递增的。

    import java.util.*;
    
    public class javaArrayUnique{
        public static void main(String args[]){
            Double[] array = new Double[100000];
            for(int i = 0, j = array.length; i < j; i++){
                array[i] = Math.ceil(Math.random()*1000);
            }
            
            Double[] arrayB = new Double[1000000];
            for(int i = 0, j = arrayB.length; i < j; i++){
                arrayB[i] = Math.ceil(Math.random()*1000);
            }
            
            System.out.println("start");
            long startTime = System.currentTimeMillis();
            arrayUnique(array);
            long endTime = System.currentTimeMillis();
            System.out.println("array unique run time: " +(endTime - startTime) +"ms");
            
            long startTimeB = System.currentTimeMillis();
            arrayUnique(arrayB);
            long endTimeB = System.currentTimeMillis();
            System.out.println("arrayB unique run time: " +(endTimeB - startTimeB) +"ms");
        }
        
        public static Double[] arrayUnique(Double[] array){
            List<Double> list = new ArrayList<Double>();
            for(int i = 0, j = array.length; i < j; i++){
                if(!list.contains(array[i])){
                    list.add(array[i]);
                }
            }
            Double[] doubles = new Double[list.size()];
            Double[] arrayUnique = list.toArray(doubles);
            return arrayUnique;
        }
    }
    
    输出:
    
    
    
    start
    array unique run time: 577ms
    arrayB unique run time: 5663ms


    ----------------------------------------------------------------------------------------END---------------------------------------------------------------------------------------



  • 相关阅读:
    SQL GUID和自增列做主键的优缺点
    php 一维数组去重
    php + crontab 执行定时任务
    PHP内置函数生成随机数的方法汇总
    PHP替换回车换行的三种方法
    Yii2查询之where条件拼装
    yii2 使用阿里大鱼短信
    javascript对数据处理
    Vue 404页面处理
    vue 中view层中方法的使用
  • 原文地址:https://www.cnblogs.com/Kingle/p/2994682.html
Copyright © 2011-2022 走看看