Heim  >  Artikel  >  Java  >  Java-Verbesserung Kapitel (19)-----Array 2

Java-Verbesserung Kapitel (19)-----Array 2

黄舟
黄舟Original
2017-02-10 11:51:331037Durchsuche

Im vorherigen Abschnitt wurden hauptsächlich die Grundkonzepte von Arrays vorgestellt und ein wenig tiefer darauf eingegangen, was ein Array ist. In diesem Blogbeitrag stellen wir hauptsächlich andere Aspekte von Arrays vor.

3. Leistung? Bitte geben Sie Arrays Vorrang.

Es gibt viele Möglichkeiten, eine Reihe von Daten in Java zu speichern. Sind sie viel bequemer zu bedienen als Arrays? Aber warum müssen wir immer noch Arrays verwenden, anstatt sie zu ersetzen? Arrays unterscheiden sich von anderen Arten von Containern in drei Bereichen: Effizienz, Typ und die Fähigkeit, primitive Typen zu speichern. In Java ist ein Array die effizienteste Möglichkeit, eine Folge von Objektreferenzen zu speichern und zufällig darauf zuzugreifen.

Arrays werden im Projektdesign immer seltener verwendet und sind in der Tat nicht so praktisch wie List und Set. Arrays haben in einigen Aspekten immer noch einige Vorteile, z. B. in Bezug auf die Geschwindigkeit, und die unterste Ebene der Sammlungsklassen wird ebenfalls durch Arrays implementiert.

--------这是ArrayList的add()------
    public boolean add(E e) {
    ensureCapacity(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
    }

 Im Folgenden werden Arrays und Listen verwendet, um einige Vergleichsoperationen durchzuführen.

1. Summierung


Long time1 = System.currentTimeMillis();
        for(int i = 0 ; i < 100000000 ;i++){
            sum += arrays[i%10];
        }
        Long time2 = System.currentTimeMillis();
        System.out.println("数组求和所花费时间:" + (time2 - time1) + "毫秒");
        Long time3 = System.currentTimeMillis();
        for (int i = 0; i < 100000000; i++) {
            sum  += list.get(i%10);
        }
        Long time4 = System.currentTimeMillis();
        System.out.println("List求和所花费时间:" + (time4 - time3) + "毫秒");
--------------Output:
数组求和所花费时间:696毫秒
List求和所花费时间:3498毫秒


Aufgrund des oben genannten Zeitaufwands beträgt die Geschwindigkeit des Arrays von Grundtypen etwa das Fünffache der Sammlung. Tatsächlich gibt es in der Listensammlung eine schwerwiegende Aktion in der Summierung: list.get(i). Bei dieser Aktion handelt es sich um eine Unboxing-Aktion. Das Integer-Objekt wird durch die intValue-Methode automatisch in einen int-Basistyp konvertiert, was zu unnötigem Leistungsverbrauch führt.

Geben Sie also bitte dem Array in der Szene mit hohen Leistungsanforderungen Vorrang.

 

4. Array variabler Länge?

 Arrays haben eine feste Länge und die Länge kann nach der Initialisierung und Deklaration nicht mehr geändert werden. Dies ist für uns in der tatsächlichen Entwicklung sehr unbequem. Wenn wir schlau sind, können wir definitiv einen Weg finden, dies zu erreichen. So wie Java keine Mehrfachvererbung implementieren kann, können wir dies auch mithilfe interner Klassen und Schnittstellen erreichen (siehe: Java-Verbesserung, Kapitel (9) ----- Mehrfachvererbung implementieren).

 Wie implementiert man also ein Array variabler Länge? Wir können die Erweiterungsidee in der List-Collection-Add-Methode verwenden, um die Implementierung zu simulieren. Das Folgende ist die Erweiterungsmethode für ArrayList:

public void ensureCapacity(int minCapacity) {
        modCount++;  
        int oldCapacity = elementData.length;
        /**
         * 若当前需要的长度超过数组长度时进行扩容处理
         */
        if (minCapacity > oldCapacity) {
            Object oldData[] = elementData;    
            int newCapacity = (oldCapacity * 3) / 2 + 1;    //扩容
            if (newCapacity < minCapacity)
                newCapacity = minCapacity;
            //拷贝数组,生成新的数组
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
    }

nach der if-Anweisung. Die Idee besteht darin, das ursprüngliche Array in ein neues Array zu kopieren. Das neue Array ist 1,5-mal so lang wie das ursprüngliche Array. Der simulierte Array-Erweiterungscode lautet also wie folgt:

public class ArrayUtils {
    /**
     * @desc 对数组进行扩容
     * @author chenssy
     * @data 2013-12-8
     * @param <T>
     * @param datas 原始数组
     * @param newLen 扩容大小
     * @return T[]
     */
    public static <T> T[] expandCapacity(T[] datas,int newLen){
        newLen = newLen < 0 ? datas.length :datas.length + newLen;   
        //生成一个新的数组
        return Arrays.copyOf(datas, newLen);
    }
    
    /**
     * @desc 对数组进行扩容处理,1.5倍
     * @author chenssy
     * @data 2013-12-8
     * @param <T>
     * @param datas  原始数组
     * @return T[]
     */
    public static <T> T[] expandCapacity(T[] datas){
        int newLen = (datas.length * 3) / 2;      //扩容原始数组的1.5倍
        //生成一个新的数组
        return Arrays.copyOf(datas, newLen);
    }
    
    /**
     * @desc 对数组进行扩容处理,
     * @author chenssy
     * @data 2013-12-8
     * @param <T>
     * @param datas 原始数组
     * @param mulitiple 扩容的倍数
     * @return T[]
     */
    public static <T> T[] expandCapacityMul(T[] datas,int mulitiple){
        mulitiple = mulitiple < 0 ? 1 : mulitiple;
        int newLen = datas.length * mulitiple;
        return Arrays.copyOf(datas,newLen );
    }
}

Auf diesem Umweg können wir dies erreichen Array-Erweiterung. Wenn Sie in Ihrem Projekt also wirklich einen Datensatz variabler Länge benötigen, kommen auch Arrays in Betracht. Wir können sie nicht ausschließen, da sie eine feste Länge haben!

5. Array-Kopierproblem

Das Kopieren einzeln ist sehr mühsam, daher verwende ich einfach List.toArray() Methode, um es in ein Array zu konvertieren und es dann über Arrays.copyOf zu kopieren. Ich persönlich finde es sehr praktisch, aber ich weiß nicht, dass ich in die Falle getappt bin! Wir wissen, dass, wenn das Array-Element ein Objekt ist, die Daten im Array eine Objektreferenz sind

public class Test {
    public static void main(String[] args) {
        Person person_01 = new Person("chenssy_01");
        
        Person[] persons1 = new Person[]{person_01};
        Person[] persons2 = Arrays.copyOf(persons1,persons1.length);
        
        System.out.println("数组persons1:");
        display(persons1);
        System.out.println("---------------------");
        System.out.println("数组persons2:");
        display(persons2);
        //改变其值
        persons2[0].setName("chessy_02");
        System.out.println("------------改变其值后------------");
        System.out.println("数组persons1:");
        display(persons1);
        System.out.println("---------------------");
        System.out.println("数组persons2:");
        display(persons2);
    }
    public static void display(Person[] persons){
        for(Person person : persons){
            System.out.println(person.toString());
        }
    }
}
-------------Output:
数组persons1:
姓名是:chenssy_01
---------------------
数组persons2:
姓名是:chenssy_01
------------改变其值后------------
数组persons1:
姓名是:chessy_02
---------------------
数组persons2:
姓名是:chessy_02
Aus dem Ergebnis wurde festgestellt, dass sich auch der Wert in Personen1 geändert hat, was ein typisches Problem mit flachem Kopieren darstellt. Das von der Methode Arrays.copyOf() generierte Array ist also eine flache Kopie. Gleichzeitig ist auch die clone()-Methode für Arrays und die clone()-Methode für Sammlungen dieselben. Wenn wir also die Kopiermethode verwenden, müssen wir auf das Problem der flachen Kopie achten.

       有关于深浅拷贝的博文,参考:

      渐析java的浅拷贝和深拷贝:http://www.php.cn/

      使用序列化实现对象的拷贝:http://www.php.cn/

       六、数组转换为List注意地方

       我们经常需要使用到Arrays这个工具的asList()方法将其转换成列表。方便是方便,但是有时候会出现莫名其妙的问题。如下:

public static void main(String[] args) {
        int[] datas = new int[]{1,2,3,4,5};
        List list = Arrays.asList(datas);
        System.out.println(list.size());
    }
------------Output:
1

       结果是1,是的你没有看错, 结果就是1。但是为什么会是1而不是5呢?先看asList()的源码

public static <T> List<T> asList(T... a) {
        return new ArrayList<T>(a);
    }

       注意这个参数:T…a,这个参数是一个泛型的变长参数,我们知道基本数据类型是不可能泛型化的,也是就说8个基本数据类型是不可作为泛型参数的,但是为什么编译器没有报错呢?这是因为在java中,数组会当做一个对象来处理,它是可以泛型的,所以我们的程序是把一个int型的数组作为了T的类型,所以在转换之后List中就只会存在一个类型为int数组的元素了。所以我们这样的程序System.out.println(datas.equals(list.get(0)));输出结果肯定是true。当然如果将int改为Integer,则长度就会变成5了。

       我们在看下面程序:

enum Week{Sum,Mon,Tue,Web,Thu,Fri,Sat}
    public static void main(String[] args) {
        Week[] weeks = {Week.Sum,Week.Mon,Week.Tue,Week.Web,Week.Thu,Week.Fri};
        List<Week> list = Arrays.asList(weeks);
        list.add(Week.Sat);
    }

       这个程序非常简单,就是讲一个数组转换成list,然后改变集合中值,但是运行呢?

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(AbstractList.java:131)
    at java.util.AbstractList.add(AbstractList.java:91)
    at com.array.Test.main(Test.java:18)

       编译没错,但是运行竟然出现了异常错误!UnsupportedOperationException ,当不支持请求的操作时,就会抛出该异常。从某种程度上来说就是不支持add方法,我们知道这是不可能的!什么原因引起这个异常呢?先看asList()的源代码:

public static <T> List<T> asList(T... a) {
        return new ArrayList<T>(a);
    }

       这里是直接返回一个ArrayList对象返回,但是注意这个ArrayList并不是java.util.ArrayList,而是Arrays工具类的一个内之类:

private static class ArrayList<E> extends AbstractList<E>
    implements RandomAccess, java.io.Serializable{
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;
        ArrayList(E[] array) {
            if (array==null)
                throw new NullPointerException();
        a = array;
    }
       /** 省略方法 **/
    }

       但是这个内部类并没有提供add()方法,那么查看父类:

public boolean add(E e) {
    add(size(), e);
    return true;
    }
    public void add(int index, E element) {
    throw new UnsupportedOperationException();
    }

       这里父类仅仅只是提供了方法,方法的具体实现却没有,所以具体的实现需要子类自己来提供,但是非常遗憾

这个内部类ArrayList并没有提高add的实现方法。在ArrayList中,它主要提供了如下几个方法:

       1、size:元素数量

       2、toArray:转换为数组,实现了数组的浅拷贝。

       3、get:获得指定元素。

       4、contains:是否包含某元素。

Zusammenfassend lässt sich sagen, dass asList eine Liste mit unveränderlicher Länge zurückgibt. Wie lang ist das Array und wie lang ist die konvertierte Liste? Wir können seine Länge nicht durch Hinzufügen oder Entfernen vergrößern oder verkleinern.

Das Obige ist der Inhalt von Java Improvement Chapter (19)-----Array 2. Weitere verwandte Inhalte finden Sie unter die chinesische PHP-Website (www.php.cn)!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn