- 把數(shù)組轉(zhuǎn)成ArrayList
為了將數(shù)組轉(zhuǎn)換為ArrayList擎颖,開發(fā)者經(jīng)常會這樣做:
List<String> list = Arrays.asList(arr);
使用Arrays.asList()方法可以得到一個ArrayList,但是得到這個ArrayList其實是定義在Arrays類中的一個私有的靜態(tài)內(nèi)部類旱爆。這個類雖然和java.util.ArrayList同名,但是并不是同一個類鄙信。java.util.Arrays.ArrayList類中實現(xiàn)了set(), get(), contains()等方法译荞,但是并沒有定義向其中增加元素的方法瓤的。也就是說通過Arrays.asList()得到的ArrayList的大小是固定的。
如果在開發(fā)過程中吞歼,想得到一個真正的ArrayList對象(java.util.ArrayList的實例)圈膏,可以通過以下方式:
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));
java.util.ArrayList中包含一個可以接受集合類型參數(shù)的構(gòu)造函數(shù)。因為java.util.Arrays.ArrayList這個內(nèi)部類繼承了AbstractList類浆熔,所以本辐,該類也是Collection的子類桥帆。
- 判斷一個數(shù)組是否包含某個值
在判斷一個數(shù)組中是否包含某個值的時候医增,開發(fā)者經(jīng)常這樣做:
Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);
以上方式雖然可以實現(xiàn)功能,但是效率卻比較低老虫。因為將數(shù)組壓入Collection類型中叶骨,首先要將數(shù)組元素遍歷一遍,然后再使用集合類做其他操作祈匙『龉簦可以使用下面方式實現(xiàn):
Arrays.asList(arr).contains(targetValue);
或者
for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
- 在循環(huán)中刪除列表中的元素
先看看下面這段循環(huán)中移除元素的代碼:
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));
for(int i=0;i<list.size();i++){
list.remove(i);
}
System.out.println(list);
輸出結(jié)果:
[b,d]
這個方法出現(xiàn)了1個嚴重的問題天揖,當一個元素被刪除時,列表的大小縮小并且下標也會隨之變化跪帝,所以當你想要在一個循環(huán)中用下標刪除多個元素的時候今膊,它并不會正常的生效。
也有些人知道以上代碼的問題就由于數(shù)組下標變換引起的伞剑。所以斑唬,他們想到使用增強for循環(huán)的形式:
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a","b","c","d"));
for(String s:list){
if(s.equals("a")){
list.remove(s);
}
}
但是,很不幸的是黎泣,以上代碼會拋出ConcurrentModificationException
恕刘。
想實現(xiàn)這個功能,可以使用如下代碼:
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
String s = iter.next();
if (s.equals("a")) {
iter.remove();
}
}
next()
方法必須在調(diào)用remove()
方法之前調(diào)用抒倚。第1個示例褐着,使用了foreach,編譯器會調(diào)用.next()
方法托呕,正是這個方法拋出的ConcurrentModificationException
含蓉,感興趣的可以看一下 ArrayList.iterator()
的源碼。
- HashTable 和 HashMap 的選擇
了解算法的人可能對HashTable比較熟悉项郊,因為他是一個數(shù)據(jù)結(jié)構(gòu)的名字谴餐。但在Java里邊,用HashMap來表示這樣的數(shù)據(jù)結(jié)構(gòu)呆抑。Hashtable和 HashMap的一個關鍵性的不同是岂嗓,HashTable是同步的,而HashMap不是鹊碍。所以通常不需要HashTable厌殉,HashMap用的更多。
- 使用原始集合類型
在Java里邊侈咕,原始類型和無界通配符類型很容易混合在一起公罕。以Set為例,Set是一個原始類型耀销,而Set< ? >是一個無界通配符類型楼眷。 (可以把原始類型理解為沒有使用泛型約束的類型)
考慮下面使用原始類型List作為參數(shù)的代碼:
public static void add(List list, Object o){
list.add(o);
}
public static void main(String[] args){
List<String> list = new ArrayList<String>();
add(list, 10);
String s = list.get(0);
}
上面的代碼將會拋出異常:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
使用原始集合類型是很危險的,因為原始集合類型跳過了泛型類型檢查熊尉,是不安全的罐柳。Set、Set< ? >和Set< Object >之間有很大差別狰住。
- 訪問級別
程序員們經(jīng)常使用public
作為類中的字段的修飾符张吉,因為這樣可以很簡單的通過引用得到值,但這并不是好的設計催植,按照經(jīng)驗肮蛹,分配給成員變量的訪問級別應該盡可能的低勺择。
ArrayList
與LinkedList
的選擇
當程序員們不知道ArrayList
與LinkedList
的區(qū)別時,他們經(jīng)常使用ArrayList伦忠,因為它看起來比較熟悉省核。然而,它們之間有巨大的性能差別昆码。簡而言之芳撒,如果有大量的增加刪除操作并且沒有很多的隨機訪問元素的操作,應該首先LinkedList
未桥。(LinkedList
更適合從中間插入或者刪除(鏈表的特性))
- 可變與不可變
不可變對象有許多的優(yōu)點笔刹,比如簡單,安全等等冬耿。同時舌菜,也有人提出疑問:既然不可變有這么多好處,為什么不把所有類都搞成不可變的呢亦镶?
通常情況下日月,可變對象可以用來避免產(chǎn)生過多的中間對象。一個經(jīng)典的實例就是連接大量的字符串缤骨,如果使用不可變的字符串爱咬,將會產(chǎn)生大量的需要進行垃圾回收的對象。這會浪費CPU大量的時間绊起,使用可變對象才是正確的方案(比如StringBuilder
)精拟。
String result="";
for(String s: arr){
result = result + s;
}
StackOverflow中也有關于這個的討論。
- 父類和子類的構(gòu)造函數(shù)
class Super {
String s;
public Super(String s) {
this.s = s;
}
}
public class Sub extends Super {
int x = 200;
public Sub(String s) {
}
public Sub() {
System.out.println("Sub");
}
public static void main(String[] args) {
Sub s = new Sub();
}
}
上面的代碼中有兩處編譯時錯誤虱歪,原因其實很簡單蜂绎,主要和構(gòu)造函數(shù)有關。首先笋鄙,我們都知道:
- 如果一個類沒有定義構(gòu)造函數(shù)师枣,編譯器將會插入一個無參數(shù)的默認構(gòu)造函數(shù)。
- 如果一個類中定義了一個帶參數(shù)的構(gòu)造函數(shù)萧落,那么編譯器就不會再幫我們創(chuàng)建無參的構(gòu)造函數(shù)践美。
上面的Super類中定義了一個帶參數(shù)的構(gòu)造函數(shù)。編譯器將不會插入默認的無參數(shù)構(gòu)造函數(shù)找岖。
我們還應該知道:
- 子類的所有構(gòu)造函數(shù)(無論是有參還是無參)在執(zhí)行時陨倡,都會調(diào)用父類的無參構(gòu)造函數(shù)。
所以宣增,編譯器試圖調(diào)用Super類中的無參構(gòu)造函數(shù)玫膀。但是父類默認的構(gòu)造函數(shù)未定義矛缨,編譯器就會報出這個錯誤信息爹脾。
要解決這個問題帖旨,可以簡單的通過
-
在父類中添加一個Super()構(gòu)造方法,就像這樣:
public Super(){}
移除自定義的父類構(gòu)造函數(shù)
在子類的構(gòu)造函數(shù)中調(diào)用父類的super(value)灵妨。
- ""還是構(gòu)造函數(shù)
創(chuàng)建 String 對象有2種方式:
//1. use double quotes
String x = "abc";
//2. use constructor
String y = new String("abc");
2種方式有什么不同? 下面的例子也許對你有所幫助:
String a = "abcd";
String b = "abcd";
System.out.println(a == b); // True
System.out.println(a.equals(b)); // True
String c = new String("abcd");
String d = new String("abcd");
System.out.println(c == d); // False
System.out.println(c.equals(d)); // True
如果你只需要創(chuàng)建一個字符串解阅,你可以使用雙引號的方式,如果你需要在堆中創(chuàng)建一個新的對象泌霍,你可以選擇構(gòu)造函數(shù)的方式货抄。
英文原文中有很多擴展鏈接,這里并沒給出朱转,后面我會挑選一些翻譯一下蟹地。