一、集合框架類概述
- 接口:即表示集合的抽象數據類型。接口提供了讓我們對集合所表示的內容進行單獨操作的可能。
- 實現:也就是集合框架中接口的具體實現。實際它們就是那些可複用的數據結構。
- 算法:在一個實現了某個集合框架中的接口對象上完成某種有用的計算方法,例如查找、排序等等。
1、集合類的由來
2、集合和數組的異同
- 集合和數組都是容器。
- 集合和數組中存儲的都是對象的引用(內存地址值)。
- 數組雖然也可以存儲對象,但長度是固定的;集合長度的可變的。
- 數組只能存儲一種類型的對象,集合可以存儲任意類型的對象。
- 數組中可以存儲基本數據類型,集合只能存儲對象。
3、集合框架體系的內容
- 集合接口:6個接口,(短虛線表示),表示不同類型的集合,是集合框架的基礎。
- 抽象類:5個抽象類,(長虛線表示),對幾個接口的部分實現,可擴展爲自定義集合類。
- 實現類:8個實現類,(實現表示),對接口的具體實現。
- Collection接口是一組允許重複的對象。
- Set接口繼承了Collection,但不允許重複,元素是無序的,使用自己內部的一個排列機制。
- List接口繼承了Collection,允許重複,元素是有序的,以元素安插的順序來放置元素,不會重新排列。
- Map接口是一組成對的鍵-值對象,Map中的鍵是唯一的,不允許重複,擁有自己的內部排列機制。
- 注:容器中的元素都爲Object類型,從容器取得元素時,必須把它轉換成原來的類型。
二、Collection<E>接口
1、Collection接口中的常用方法:
- boolean add(E e) 添加一個元素。add方法的參數類型是 Object 。以便於接收任意類型對象。
- boolean
addAll(Collection<? extends E> c) 添加另一集合內所有元素
- boolean remove(Object
o);刪除一個元素
- boolean
removeAll(Collection<?> c)僅移除本集合中另一集合也有的元素,即移除本集合中與另一集合的交集
- void
clear();清空集合
- boolean contains(Object
o) 判斷是否包含某個元素
- boolean
containsAll(Collection<?> c)判斷是否包含另一集合中的所有元素
- boolean
isEmpty()判斷集合是否爲空 //其實它是在調用size方法
- Iterator<E> iterator()迭代。返回在此集合的元素上進行迭代的迭代器。
- int
size()獲取集合長度
- boolean
retainAll(Collection<?> c)僅保留此集合中另一集合也有的元素,即保留本集合與另一集合的交集
- Object[] toArray() :返回一個內含集合所有元素的array
- Object[]
toArray(Object[] a) :返回一個內含集合所有元素的array。運行期返回的array和參數a的型別相同,需要轉換爲正確型別。
- 此外,我們還可以把集合轉換成其它任何類型的數組。但是,我們不能直接把集合轉換成基本數據類型的數組,因爲集合必須持有對象。
import java.util.*;
/*Collection集合常用方法演示*/
class CollectionDemo
{
public static void main(String[] args)
{
method_get();
}
public static void method_get()
{
Collection list1 = new ArrayList();
/*==================1、添加方法演示==================*/
//添加元素。add()
list1.add("huangxiang01");
list1.add("huangxiang02");
list1.add("huangxiang03");
list1.add("huangxiang04");
//添加另一集合的所有元素。addAll()
Collection list2 = new ArrayList();
list2.add("huang55");
list2.add("huang56");
list2.add("huang57");
list2.add("huangxiang04");
//將list2集合的中元素全部添加到list1集合中。
//list1.addAll(list2);
/*==================2、刪除方法演示==================*/
//刪除元素。remove()
//list1.remove("huangxiang01");
//刪除本集合中另一集合也有的元素
//list1.removeAll(list2);
//清空集合
//list1.clear();
/*==================3、判斷方法演示==================*/
//判斷是否包含某個元素
Sop(list1.contains("huangxiang03"));
//判斷是否包含另一集合中的所有元素
Sop(list1.containsAll(list2));
//判斷集合是否爲空
Sop(list1.isEmpty());
/*==================4、獲取方法演示==================*/
//迭代器
Iterator it = list1.iterator();
while(it.hasNext()){
Sop(it.next());
}
//獲取集合長度
Sop(list1.size());
//獲取本集合與另一集合的交集
Sop(list1.retainAll(list2));
/*==================5、數組轉換方法演示==================*/
//返回一個內含集合所有元素的array
list1.toArray();
//
}
public static void Sop(Object obj){
System.out.println(obj);
}
}
2、迭代器Iterator
- hasNext():如果有下一個元素,返回真
- next():取出下一個元素
- remove():移除
- 注意:在迭代循環中,next每調用一次,就要用hasNext()判斷一次。
- 迭代器在Collection接口中是通用的,他替代了Vector類中的枚舉。
- 迭代器的next()方法是自動向下取元素,要避免出現NoSuchElementException。
- 迭代器的next()方法返回值類型是Object,要注意類型轉換。
三、List<E>接口
1、List接口的常用子類對象
- ArrayList:底層的數據結構使用的是數組。特點:查詢速度很快。但是增刪稍慢,線程不同步。
- LinkedList:底層使用的是鏈表數據結構。特點:增刪速度很快。查詢較慢。
- Vector:底層是數組數據結構。線程同步。被ArrayList替代。
2、List接口的特有方法
- void add(int index,E element)在列表的指定位置插入指定元素。
- boolean
addAll(int index, Collection<? extends E> c) 將指定 collection 中的所有元素都插入到列表中的指定位置。
- E
remove(int index) 移除列表中指定位置的元素。
- E
set(int index, E element) 用指定元素替換列表中指定位置的元素,返回以前在指定位置的元素。
- E
get(int index) 返回列表中指定位置的元素。
- List<E>
subList(int fromIndex, int toIndex) 返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之間的部分列表。
- ListIterator<E>
listIterator() 返回此列表元素的列表迭代器。
- ListIterator<E>
listIterator(int index) 從列表的指定位置開始返回列表中元素的列表迭代器。
3、ArrayList類
import java.util.*;
//ArrayList 最基本的用法
public class ArrayListTest1{
public static void main(String[]args){
//如何創建對象
List<Integer> list = new ArrayList<Integer>();
//向ArrayList中添加元素
list.add(25);
list.add(26);
list.add(12);
list.add(28);
//得到Arraylist中添加了多少個元素
System.out.println(list.size());
System.out.println("===================華麗的分割線================");
//如何得到集合當中的第幾個元素
Integer num = list.get(1);
System.out.println(num);
System.out.println("===================華麗的分割線================");
//如何遍歷ArrayList。
//第一種方法:for循環
for(int i = 0;i < list.size();i++){
System.out.println(list.get(i));
}
System.out.println("===================華麗的分割線================");
//第二種方法,迭代器
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
Integer data = it.next();
System.out.println(data);
}
System.out.println("==========================華麗的分割線==========================");
//第三種方法:foreach循環
for(Integer i : list)
System.out.println(i);
}
}
import java.util.*;
//ArrayList提供了remove(int index),remove(Object obj)兩個方法刪除
public class ArrayListTest2{
public static void main(String[] args){
ArrayList<Integer> list = new ArrayList<>(5);
/*list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);*///list集合中的添加方法,逐個添加
Collections.addAll(list,1,2,3,4,5);//Collections提供的addAll方法
//addAll(list,1,2,3,4,5);//自定義的批量添加addAll方法
System.out.println(list);
//刪除元素:方法1
list.remove(2);//明確的刪除第幾個元素
System.out.println(list);
System.out.println("==================華麗的分割線===================");
//刪除元素:方法2
list.remove(new Integer(4));//明確的刪除哪一個元素
System.out.println(list);
System.out.println("====================華麗的分割線=================");
//刪除所有元素:用循環
/*while(list.size()!=0)
list.remove(0);
System.out.println(list);*/
//刪除所有元素:用clear()方法
list.clear();
System.out.println(list);
}
public static void addAll(List<Integer> list,Integer...data){
for(Integer i : data)
list.add(i);
}
}
import java.util.*;
//remove(Object obj)是如何找到元素的,如何刪除你的元素的
public class ArrayListTest3{
public static void main(String[] args){
ArrayList<Integer> list = new ArrayList<>();
Integer i1 = new Integer(5);
Integer i2 = new Integer(5);
list.add(i1);
System.out.println(list.size());//結果是1
list.remove(i2);
System.out.println(list.size());//結果是0
//結果:說明ArrayList的remove(Object obj) 完全尊重equals比較返回的結果。
System.out.println("===================華麗的分割線====================");
ArrayList<Teacher> list2 = new ArrayList<>();
Teacher tea1 = new Teacher("zhangsan",25);
Teacher tea2 = new Teacher("zhangsan",25);
list2.add(tea1);
System.out.println(list2.size());//結果爲1
list2.remove(tea2);
System.out.println(list2.size());//結果爲1
//在複寫之前結果爲1,即相同的元素沒有被刪除。這是因爲在Object中的eaquls方
//法其實就是==運算
//複寫equals方法之後,相同的元素被刪除。
}
}
class Teacher{
private String name;
private int age;
public Teacher(String name,int age){
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj){
System.out.println("我被執行啦");
//做一些健壯性判斷
if(obj == null) return false;
if(!(obj instanceof Teacher)) return false;
if(obj == this) return true;
Teacher t1 = this;
Teacher t2 = (Teacher)obj;
return t2.name.equals(t2.name) && (t1.age == t2.age);
}
}
import java.util.*;
public class ArrayListTest4{
public static void main(String[] args){
List<Integer> list = new ArrayList<>();
Collections.addAll(list,1,2,3,4,5);
//需求:刪除所有小於3的數
Iterator<Integer> it = list.iterator();
/*
java.util.ConcurrentModificationException併發修改異常。
按照下面這種寫法會發生該異常。在迭代器遍歷ArrayList的過程當中,絕對不允許
對集合整體進行任何添加刪除操作。(除了刪除不成功的)
while(it.hasNext()){
Integer num = it.next();
if(num<3)
list.remove(num);
}
*/
while(it.hasNext()){
Integer num = it.next();
if(num<3)
it.remove();
}
System.out.println(list.size());
}
}
//模擬ArrayList的主要方法底層實現
public class ArrayListTest5{
public static void main(String[] args){
MyList list = new MyList();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
System.out.println(list.getSize());
}
}
class MyList{
private Object[] data;
private int size;//用戶存放了多少元素進來
//根據用戶指定的容量,初始化底層的數組的構造方法
public MyList(int length){
data = new Object[length];
}
//默認的構造方法,它共享了有參的構造方法,默認10個空
public MyList(){
this(10);
}
//用來得到已經存放的元素個
public int getSize(){
return size;
}
//得到第幾個元素的方法
public Object get(int i){
return data[i];
}
//添加元素的方法
public void add(Object obj){
//如果底層的數組存儲空間已經滿了
if(data.length == size){
Object[] temp = new Object[size*3/2+1]; //找到一個更大的新筐
System.arraycopy(data,0,temp,0,size);//將老筐裏面的棒子放到新筐裏
data = temp;//背上新筐(老筐留給收垃圾的)
}
data[size++] = obj;
}
//刪除第幾個元素的方法
public void remove(int x){
System.arraycopy(data,x+1,data,x,size-x-1);
size--;
/*
0 1 2 3 4 要刪除的是下標2,那麼其實就是從下標3開始向下標2複製元素
0 1 3 4 總共複製5-2-1.
*/
}
//刪除指定的那個元素的方法
public void remove(Object obj){
for(int i = 0;i<size;i++){
if(obj.equals(data[i]))
remove(i);
}
}
}
4、LinkedList類
- void addFirst(Object o): 將對象o添加到列表的開頭
- void
addLast(Object o):將對象o添加到列表的結尾
- Object
getFirst(): 返回列表開頭的元素
- Object
getLast(): 返回列表結尾的元素
- Object
removeFirst(): 刪除並且返回列表開頭的元素
- Object
removeLast():刪除並且返回列表結尾的元素
- LinkedList():
構建一個空的鏈接列表
- LinkedList(Collection
c): 構建一個鏈接列表,並且添加集合c的所有元素
- offFirst();替代addFirst
- offLast();替代addLast
- peekFirst();替代getFirst
- peekLast();替代getLast
- pollFirst();替代removeFirst
- pollLast();替代removeLast
/*
使用LinkedList模擬一個堆棧或者隊列數據結構。
堆棧:先進後出 如同一個杯子。
隊列:先進先出 First in First out FIFO 如同一個水管。
*/
import java.util.*;
class LinkedListTest
{
public static void main(String[] args)
{
LinkedList l=new LinkedList();
l.addFirst("java01");
l.addFirst("java02");
l.addFirst("java03");
l.addFirst("java04");
l.addFirst("java05");
//堆棧輸出
// stack(l);
//隊列輸出
queue(l);
}
//堆棧
public static void stack(LinkedList l)
{
while (!l.isEmpty())
{
sop(l.removeFirst());
}
}
//隊列
public static void queue(LinkedList l)
{
while(!l.isEmpty())
{
sop(l.removeLast());
}
}
//輸出
public static void sop(Object obj)
{
System.out.println(obj);
}
}
5、ListIterator
- add(obj); 將obj添加到當前位置的前面
- set(obj); 用obj替代next或者previous方法訪問的上一個元素。如果上次調用後列表結構被修改了。將拋出異常。
- hasPrevious(); 判斷前面有沒有元素
- previous(); 返回上一個元素對象
“我們還需要稍微再解釋一下 add() 操作。添加一個元素會導致新元素立刻被添加到隱式光標的前面。因此,添加元素後調用 previous() 會返回新元素,而調用 next() 則不起作用,返回添加操作之前的下一個元素。”
6、Vector類
- addElement(obj);//添加元素,相當於add(obj);
- Enumerationelements();//Vector特有取出方式(枚舉)
- hasMoreElements();//相當於Iterator的hasNext()方法
- nextElements();//相當於Iterator的next()方法
Vector v=new Vector();
for(Enumeration e=v.elements();e.hasMoreElements();)
{
System.out.println(e.nextElements());
}
四、Set<E>接口
1、散列表(哈希表)
2、樹集
3、Set概述
- HashSet:底層數據結構是哈希表,線程不同步。其保證元素唯一性的原理是:判斷元素的hashCode是否相同,如果相同會繼續判斷元素的equals方法。
- TreeSet:可以對Set集合中的元素進行排序。默認按照字母的自然順序排序。底層數據結構是二叉樹。保證元素唯一性的依據是:compareTo方法返回true。當compareTo方法無法滿足需求時,可以採用自定義比較器,實現Comparator接口並覆蓋其中的compare()方法來實現。
4、Comparable接口和Comparator接口
- Compareable接口
在java.lang包中,Comparable接口適用於一個類有自然順序的時候。假定對象集合是同一類型,該接口允許您把集合排序成自然順序。
a、int compareTo(Object o): 比較當前實例對象與對象o,如果位於對象o之前,返回負值,如果兩個對象在排序中位置相同,則返回0,如果位於對象o後面,則返回正值
在 Java 2 SDK版本1.4中有二十四個類實現Comparable接口。下表展示了8種基本類型的自然排序。雖然一些類共享同一種自然排序,但只有相互可比的類才能排序。
類 | 排序 |
BigDecimal,BigInteger,Byte, Double, Float,Integer,Long,Short |
按照數字大小排序 |
Character |
按 Unicode 值的數字大小排序 |
String |
按字符串中字符 Unicode 值排序 |
利用Comparable接口創建您自己的類的排序順序,只是實現compareTo()方法的問題。通常就是依賴幾個數據成員的自然排序。同時類也應該覆蓋equals()和hashCode()以確保兩個相等的對象返回同一個哈希碼。
b、Comparator接口
若一個類不能用於實現java.lang.Comparable,或者您不喜歡缺省的Comparable行爲並想提供自己的排序順序(可能多種排序方式),你可以實現Comparator接口,從而定義一個比較器。
- int compare(Object o1, Object o2): 對兩個對象o1和o2進行比較,如果o1位於o2的前面,則返回負值,如果在排序順序中認爲o1和o2是相同的,返回0,如果o1位於o2的後面,則返回正值
“與Comparable相似,0返回值不表示元素相等。一個0返回值只是表示兩個對象排在同一位置。由Comparator用戶決定如何處理。如果兩個不相等的元素比較的結果爲零,您首先應該確信那就是您要的結果,然後記錄行爲。” - boolean equals(Object obj): 指示對象obj是否和比較器相等。“該方法覆寫Object的equals()方法,檢查的是Comparator實現的等同性,不是處於比較狀態下的對象。”
5、HashSet類
- HashSet():構造一個新的空 set,其底層 HashMap 實例的默認初始容量是 16,加載因子是 0.75。
- HashSet(Collection<? extendsE> c):構造一個包含指定
collection 中的元素的新 set。
- HashSet(int initialCapacity): 構造一個新的空 set,其底層 HashMap 實例具有指定的初始容量和默認的加載因子(0.75)。
- HashSet(int initialCapacity, float loadFactor):構造一個新的空 set,其底層 HashMap 實例具有指定的初始容量和指定的加載因子。
import java.util.*;
/*
需求:往HashSet中存入自定義對象。姓名和年齡相同是同一個人。爲重複元素。應去除。
思路:1、對人進行描述,將人的一些屬性等封裝
2、定義一個HashSet集合,存儲對象
3、取出。
*/
public class HashSetTest2{
public static void main(String[]args){
//創建一個HashSet集合
HashSet<Person> hs = new HashSet<Person>();
//向集合中添加元素,這裏添加了兩個相同元素
hs.add(new Person("zhangsan",25));
hs.add(new Person("lisi",25));
hs.add(new Person("wangwu",25));
hs.add(new Person("zhangsan",25));
hs.add(new Person("wangwu",25));
//返回迭代器
Iterator<Person> it = hs.iterator();
//迭代取出元素
while(it.hasNext()){
Person p = it.next();
System.out.println(p.getName()+"......."+p.getAge());
}
}
}
//自定義類
class Person{
private String name;
private int age;
//構造方法初始化
public Person(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
//複寫hashCode方法
@Override
public int hashCode(){
return name.hashCode()+age;
}
//複寫Obeject類中的equals方法
public boolean equals(Object obj){
//健壯性判斷
if(obj == null) return false;
if(!(obj instanceof Person)) return false;
if(obj == this) return true;
Person p = (Person)obj;
//這裏的equals方法是字符串的equals方法。
return this.name.equals(p.name) && this.age == p.age;
}
}
6、TreeSet
- TreeSet():構造一個新的空 set,該 set 根據其元素的自然順序進行排序。
- TreeSet(Collection<? extendsE> c):構造一個包含指定
collection 元素的新 TreeSet,它按照其元素的自然順序進行排序。
- TreeSet(Comparator<? superE> comparator):構造一個新的空
TreeSet,它根據指定比較器進行排序。
- TreeSet(SortedSet<E> s):構造一個與指定有序 set
具有相同映射關係和相同排序的新 TreeSet。
import java.util.*;
/*
創建兩個Item對象的樹集。第一個按照部件編號排序,這是Item對象的默認順序,
第二個通過使用一個定製的比較器來按照描述信息排序。
*/
public class TreeSetTest1{
public static void main(String[] args){
//第一個TreeSet集合,按照默認排序編號進行排序。compareTo()
SortedSet<Item> parts = new TreeSet<Item>();
parts.add(new Item("Tosater",1234));
parts.add(new Item("Widget",4562));
parts.add(new Item("Modem",9912));
System.out.println(parts);
//第二個Set集合,按照自定義比較器按照描述信息排序
SortedSet<Item> sortByDescription = new TreeSet<Item>(new
Comparator<Item>(){
//匿名內部類實現Comparator接口
public int compare(Item a,Item b){
String descrA = a.getDescription();
String descrB = b.getDescription();
return descrA.compareTo(descrB);
}
});
//打印排序後的結果
sortByDescription.addAll(parts);
System.out.println(sortByDescription);
}
}
/*
創建一個待描述信息和部件編號的類
*/
class Item implements Comparable<Item>{
private String description;
private int partNumber;
/**
構造器初始化
@aDescription Item的description
@aPartNumber Item的部件編號(part number)
*/
public Item(String aDescription,int aPartNumber){
description = aDescription;
partNumber = aPartNumber;
}
/**
獲取Item的描述信息
@return description 返回值
*/
public String getDescription(){
return description;
}
@Override
public String toString(){
return "[description=" + description + ",partNumber" + partNumber+"]";
}
@Override
public boolean equals(Object otherObject){
//健壯性判斷
if(this == otherObject) return true;
if(otherObject == null) return false;
if(getClass() != otherObject.getClass()) return false;
Item other = (Item)otherObject;
return
description.equals(other.description) && partNumber == other.partNumber;
}
//複寫hashCOde()方法
@Override
public int hashCode(){
return 13*description.hashCode()+17*partNumber;
}
//複寫compareTo方法
@Override
public int compareTo(Item other){
return partNumber - other.partNumber;
}
}
c、TreeSet的小練習(自定義比較器)
import java.util.*;
/*
按照字符串長度排序
分析:字符串本身具有比較性,但不符合題目的需求,所以需要重寫一個比較器。
*/
public class TreeSetTest4{
public static void main(String[] args){
TreeSet<String> set = new TreeSet<>(new strLenComparetor());
set.add("dadadwd");
set.add("dasd");
set.add("dsd");
set.add("ddsdsdwd");
set.add("daddsdswedcs");
set.add("dsddd");
set.add("da");
Iterator<String> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
class strLenComparetor implements Comparator{
public int compare(Object o1,Object o2){
//將Object型強轉爲String型
String s1 = (String)o1;
String s2 = (String)o2;
//比較
int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
//當比較結果爲0時,將再次進行比較,以保證比較的準確性
if(num == 0)
s1.compareTo(s2);
//不爲0時,返回num的值
return num;
}
}
d、TreeSet實現兩種比較方式的應用實例二:
import java.util.*;
public class TreeSetTest3{
public static void main(String[] args){
TreeSet<Student> set = new TreeSet<>(new MyCompare());
set.add(new Student("zhangsan",25));
set.add(new Student("lisi",23));
set.add(new Student("wangwu",30));
set.add(new Student("zhaoliu",19));
set.add(new Student("zhaoliu2",19));
set.add(new Student("zhuqi",28));
set.add(new Student("zhuqi2",28));
Iterator<Student> it = set.iterator();
while(it.hasNext()){
Student stu = it.next();
System.out.println(stu.getName()+"........"+stu.getAge());
}
}
}
//自定義比較器
class MyCompare implements Comparator{
public int compare(Object o1,Object o2){
Student s1 = (Student)o1;
Student s2 = (Student)o2;
int num = s1.getName().compareTo(s2.getName());
if(num == 0)
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
return num;
}
}
//繼承Compareable,讓其具有比較性
class Student implements Comparable{
private String name;
private int age;
public Student(String name,int age){
this.name = name;
this.age = age;
}
@Override
public int compareTo(Object obj){
//健壯性判斷
if(obj == null) return -1;
if(obj == this) return 0;
if(!(obj instanceof Student))
throw new RuntimeException("類型不一致");
Student s = (Student)obj;
System.out.println(this.name+"......compareTo...."+s.name);
if(this.age>s.age) return 1;
if(this.age==s.age) {
this.name.compareTo(s.name);
}
return -1;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}