java面向对象编程集合边框_Java学习系列(七)Java面向对象之集合框架详解(上)
Java集合
有時也將集合稱為容器類,它的作用就是用來“裝對象”的。這里要注意的是集合也可以是對象。下面先看一張圖:
HashSet:底層用一個數組存元素 --而且這個數組的長度永遠是2的N次方。
HashSet底層就是HashMap實現的。
HashSet的構造器:HashSet(int initialCapacity, float loadFactor)
--initialCapacity:控制底層數組的長度。
如果傳入數組長度不是2的N次方,HashSet會自動擴展到2的N次方。
--loadFactory:當HashSet感覺到底層數組快滿時,它會再次創建一個長度是原來數組長度2倍的數組。原有的數組就變成垃圾,并且要把原有數組中的元素復制到新數組中,這個過程也叫“重hash”。loadFactory越小,越耗內存;loadFactory越大,性能越低。
舉例說明1:
public class Test {
public static void main(String[] args) {
//沒有泛型限制的集合
Collection c1 = new HashSet();
c1.add(1);//本來1不是對象,無法裝入集合,但由于jdk提供的自動裝箱功能,它會將1包裝成對象
c1.add(new Date());
//加入泛型限制的集合,意味著該集合只能裝“指定類型”的對象。
//jdk1.7可使用"菱形語法"將new HashSet換成new HashSet<>
Collection c2 = new HashSet();
//c2.add(1);錯誤:只能裝String類型的對象
c2.add("張三");
c2.add("李四");
c2.add("王五");
//判斷集合是否包含指定元素
System.out.println(c2.contains("張三"));
System.out.println(c2.contains("趙六"));
//遍歷Set集合,有兩種方式:1)foreach循環,2)迭代器
System.out.print("使用foreach循環遍歷:");
for(String e : c2){
System.out.print(e+" ");
}
Iterator it = c2.iterator();
System.out.print("\n使用迭代器遍歷:");
while(it.hasNext()){
System.out.print(it.next()+" ");
}
System.out.println();
Collection c3 = new HashSet();
c3.add("張三");
c3.add("王五");
c3.add("趙六");
//求差集c2-c3
//c2.removeAll(c3);
//System.out.println("c2與c3差集:"+c2);
//求并集
//c2.addAll(c3);
//System.out.println("c2與c3并集"+c2);
//求交集
c2.retainAll(c3);
System.out.println("c2與c3交集:"+c2);
}
}
舉例說明2:
public class TestHashSet {
public static void main(String[] args) {
HashSet hs = new HashSet(3);//底層數組容量會自動會展到4(注意:2的N次方)
hs.add("1");
hs.add("2");
hs.add("3");
hs.add("4");
hs.add("5");
//當HashSet感覺到底層數組快滿時,它會再次創建一個長度是原來數組長度2倍的數組,此時新的數組長度為8
System.out.println(hs);
}
}
HashSet存入機制:
1)當有元素加進來時,HashSet會調用該對象的hashCode()方法,得到一個int值;
2)根據hashCode()返回的int值,計算出它在HashSet的存儲位置(數組中的索引);
3)如果要加入的位置是空的,直接方法即可。如果要加入的位置已經有元素,此處就會形成“鏈表”,數組越滿,就越有可能出現鏈表。
HashSet取元素機制:
1)當有元素加進來時,HashSet會調用該對象的hashCode()方法,得到一個int值;
2)根據hashCode()返回的int值,計算出它在HashSet的存儲位置(數組中的索引);
3)如果該位置恰好是要找的元素,直接取出即可。如果該位置有“鏈表”,HashSet要“挨個”地搜索鏈表里的元素。
HashSet怎么才會認為兩個對象是相等的?(要求自定義類的hashCode()和equals()方法是一致的,即方法中所用到的關鍵屬性要一致)
1、兩個對象的hashCode()返回值相等;
2、兩個對象通過equals比較返回true。
LinkedHashSet(HashSet的一個子類):它與HashSet的存儲機制相似,但LinkedHashSet額外地有一個鏈表,這個鏈表可以保證LinkedHashSet能記住元素的添加順序。
TreeSet(sortedset接口的實現類):它保證Set里添加的元素后是“大小排序”的。底層用一個“紅黑樹”存放元素。
舉例說明(使用TreeSet要求集合元素必須是可以比較大小的):
public class TestTreeSet1 {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
ts.add(3);
ts.add(1);
ts.add(2);
ts.add(5);
ts.add(4);
System.out.println(ts);
}
}
public class TestTreeSet2 {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
ts.add("t");
ts.add("r");
ts.add("e");
ts.add("e");
System.out.println(ts);//字符串的大小
}
}
TreeSet元素存入、檢索的性能也比較好。
Java的比較大小有兩種方式:
A. --自然排序。所有集合元素要實現Comparable接口。
B. --定制排序。要求創建TreeSet時,提供一個Comparator對象(負責比較元素大小)。
舉例說明:
class Apple implements Comparable {
private double weight;// 規定:蘋果重量大的蘋果越大
public Apple(double weight) {
this.weight = weight;
}
@Override //自然排序
public int compareTo(Apple obj) {
return this.weight > obj.weight ? 1 : this.weight < obj.weight ? -1 : 0;
}
@Override
public String toString() {
return "Apple[weight=" + this.weight + "]";
}
}
public class TreeSetTest {
public static void main(String[] args) {
TreeSet set = new TreeSet();
set.add(new Apple(2.3));
set.add(new Apple(1.2));
set.add(new Apple(3.5));
for (Apple ele : set) {
System.out.println(ele);
}
}
}
class Bird {
private String name;
public String getName() {
return name;
}
public Bird(String name) {
this.name = name;
}
@Override
public String toString() {
return "Bird[name=" + name + "]";
}
}
public class TreeSetTest2 {
public static void main(String[] args) {
// 如果集合元素本身沒有實現Comparable接口
// 那就要求創建TreeSet時傳入一個Comparator對象
TreeSet set = new TreeSet(new Comparator() {
@Override
public int compare(Bird o1, Bird o2) {
if (o1.getName().compareTo(o2.getName()) > 0) {
return -1;
} else if (o1.getName().compareTo(o2.getName()) < 0) {
return 1;
} else {
return 0;
}
}
});
set.add(new Bird("aabc"));
set.add(new Bird("abc"));
set.add(new Bird("Z"));
set.add(new Bird("dx"));
System.out.println(set);
}
}
ArrayList(JDK1.2)與Vector(JDK1.0,已經過時)都是基于數組實現的,它們的區別如下:
ArrayList(可根據索引來存取元素)是線程不安全的,Vector是線程安全的。
--ArrayList的性能比Vector要好,即使在多線程環境下,可以使用Collections集合工具類的synchronizedXxx方法把ArrayList包裝成線程安全的。
而LinkedList底層是基于鏈表實現的,通常認為它的性能比不上ArrayList,它們的區別如下:
ArrayList:由于可以根據底層數組的索引存取元素,所以性能非常快,但當插入元素、刪除元素時性能低。
LinkedList:由于底層采用了鏈表來存儲元素,因此根據索引存取元素性能較慢,但當插入、刪除元素時性能非常快。
舉例說明:
public class Test {
public static void main(String[] args) {
List list = new ArrayList();
list.add("2");
list.add("1");
list.add("5");
list.add("3");
System.out.println(list);
list.add(2,"在索引2處插入元素");
System.out.println(list);
list.set(2,"在索引2處替換的元素");
System.out.println(list);
list.remove(2);
System.out.println(list);
//遍歷list(類似數組)
for(int i =0;i
System.out.print(list.get(i)+" ");
}
}
}
Deque集合:功能被限制的線性表。
//把Deque當成棧用
public class Test {
public static void main(String[] args) {
//把Deque當成棧用
Deque dq = new ArrayDeque();
//進棧(壓棧):后進先出
dq.push("a");
dq.push("b");
dq.push("c");
dq.push("d");
//打印首先出棧的元素
System.out.println(dq.pop());
//打印訪問棧頂的元素
System.out.println(dq.peek());
}
}
//把Deque當成隊列用:先進先出
public class Test2 {
public static void main(String[] args) {
//把Deque當成隊列用:先進先出
Deque dq = new ArrayDeque();
//從隊列尾部入隊
dq.offer("a");
dq.offer("b");
dq.offer("c");
dq.offer("d");
//從隊列頭部出隊
System.out.println(dq.poll());
//打印訪問隊頭元素
System.out.println(dq.peek());
}
}
Collections集合工具類:
public class TestCollections {
public static void main(String[] args) {
List list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
System.out.println(list);
//對集合進行反轉
Collections.reverse(list);
System.out.println(list);
//把b, c位置進行交換
Collections.swap(list, 1, 2);
System.out.println(list);
//將list集合元素進行隨機排列
Collections.shuffle(list);
System.out.println(list);
}
}
結束語
今天內容比較多,而且有些和數據結構相關,所以理解起來可能會有些困難。編程我覺得還是要多練,只要你肯多練,就不會那么難了。今天就講到這,明天開始講Map。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的java面向对象编程集合边框_Java学习系列(七)Java面向对象之集合框架详解(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ubuntu java 编译器_Ubun
- 下一篇: java迭代器 异常_java.util