前一節主要介紹了陣列的基本概念,對什麼是數組稍微深入了一點點,在這篇博文中主要介紹數組的其他方面。
三、性能?請優先考慮數組
在java中有很多方式來儲存一系列數據,而且在操作上面比數組方便的多?但為什麼我們還需要使用數組,而不是取代它?陣列與其他種類的容器之間的差異有三個面向:效率、類型和保存基本類型的能力。 在java中,數組是一種效率最高的儲存和隨機存取物件引用序列的方式。
在項目設計中數組使用的越來越少了,而且它確實是沒有List、Set這些集合使用方便,但是在某些方面數組還是存在一些優勢的,例如:速度,而且集合類別的底層也都是透過數組來實現的。
--------这是ArrayList的add()------ public boolean add(E e) { ensureCapacity(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
下面利用陣列和list來做一些操作比較。
一、求和
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毫秒
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);
}
}
速率是集合的5倍左右。其實在list集合中,求和當中有一個致命的動作:list.get(i)。這個動作是進行拆箱動作,Integer物件透過intValue方法自動轉換成一個int基本型,在這裡就產生了不必要的效能消耗。
所以在效能要求較高的場景中請優先考慮陣列。
四、變長陣列?
陣列是定長的,一旦初始化宣告後是不可變更長度的。這對我們在實際開發中是非常不方便的,聰明的我們肯定是可以找到方法來實現的。就如java不能實作多重繼承一樣,我們一樣可以利用內部類別和介面來實作(請參考:java提高篇(九)-----實作多重繼承)。
那麼如何來實現變長數組呢?我們可以利用List集合add方法裡面的擴容思路來模擬實作。以下是ArrayList的擴容方法:
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 ); } }
這段程式碼對我們有用的地方就在於我們有用的地方就這樣。它的想法是將原始數組拷貝到新數組中,新數組是原始數組長度的1.5倍。所以模擬的陣列擴容程式碼如下:
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
透過這種迂迴的方式我們可以實現陣列的擴充。因此在專案中如果確實需要變長的資料集,數組也是在考慮範圍之內的,我們不能因為他是固定長度而排斥他!
五、數組複製問題
以前在做脆皮的時候由於集合非常乾的時間由於集合轉換成數組然後再通過Arrays.copyOf拷貝,在轉換成集合,個人覺得非常方便,殊不知我已經陷入了其中的陷進!我們知道若數組元素為對象,則數組裡面資料是對象引用
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
從結果中發現,persons1中的 從結果中發現,persons1中的值也發生了淺拷貝問題。所以透過Arrays.copyOf()方法產生的陣列是一個淺拷貝。同時數組的clone()方法也是,集合的clone()方法也是,所以我們在使用拷貝方法的同時一定要注意淺拷貝這問題。
🎜有关于深浅拷贝的博文,参考:
渐析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:是否包含某元素。
所以綜上所述,asList回傳的是長度不變的清單。數組是多長,轉換成的列表是多長,我們是無法透過add、remove來增加或減少其長度的。
以上就是java提高篇(十九)-----數組之二的內容,更多相關內容請關注PHP中文網(www.php.cn)!

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

本文解釋了用於構建分佈式應用程序的Java的遠程方法調用(RMI)。 它詳細介紹了接口定義,實現,註冊表設置和客戶端調用,以解決網絡問題和安全性等挑戰。

本文詳細介紹了用於網絡通信的Java的套接字API,涵蓋了客戶服務器設置,數據處理和關鍵考慮因素,例如資源管理,錯誤處理和安全性。 它還探索了性能優化技術,我

本文詳細介紹了創建自定義Java網絡協議。 它涵蓋協議定義(數據結構,框架,錯誤處理,版本控制),實現(使用插座),數據序列化和最佳實踐(效率,安全性,維護


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 Linux新版
SublimeText3 Linux最新版

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SublimeText3漢化版
中文版,非常好用

Safe Exam Browser
Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。