Java(23)集合
集合
Java集合類存放於Java.util
包中,是一個用來存放物件的容器。
- 集合只能用來存放物件。如果存放一個
int
整型資料進入集合中,會自動將int轉換成Integer
包裝類。 - 集合存放的是多個物件的引用,物件本身存放在堆記憶體中。
- 集合可以存放不同型別,不同數量的資料型別。
jdk5
之後,Java提供了泛型,可以限制集合中的資料型別。
陣列其實是一種特殊的集合,為什麼還要有集合呢?
這是因為陣列有如下限制:
- 陣列初始化後大小不可變;
- 陣列只能按索引順序存取。
因此,我們需要各種不同型別的集合類來處理不同的資料,例如:
- 可變大小的順序連結串列;
- 保證無重複元素的集合;
- ...
Java集合主要分為三大體系:
Set
:無序、不可重複的集合List
:有序,可重複的集合Map
:具有對映關係的集合(key-value
)
Set
HashSet類
HashSet
是Set
介面的實現類。HashSet
按照Hash演算法來儲存集合中的元素,因此具有很好的儲存和查詢效能。
HashSet
特點:
- 不能保證元素的排序:存入一個物件時會呼叫該物件的
hashCode()
方法得到hashCode
值,再根據hashCode
值決定元素儲存位置。 - 不可重複:不可重複的意思是
hashCode
不能相同。 HashSet
不是執行緒安全的。- 集合元素可以是
null
。
案例1:
package day01; import java.util.HashSet; import java.util.Set; public class DayB { public static void main(String[] args) { Set sa= new HashSet(); //新增元素 sa.add("I love you"); sa.add(34); System.out.println(sa); //[34, I love you] //判斷是否包含元素 System.out.println(sa.contains(34)); //true //移除元素 sa.remove(34); System.out.println(sa); //[I love you] //獲取集合中元素個數: System.out.println(sa.size());//1 //清空元素 sa.clear(); System.out.println(sa); //[] } }
案例2:遍歷集合
package day01; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class DayB { public static void main(String[] args) { Set sb= new HashSet(); sb.add("a"); sb.add("b"); sb.add("c"); //使用迭代器遍歷: Iterator it=sb.iterator(); while(it.hasNext()){ System.out.println(it.next()); } //使用For each迴圈遍歷: for(Object a:sb){ System.out.println(a); } } }
補充知識點(迭代器):
迭代器是一種設計模式,它是一個物件,它可以遍歷並選擇序列中的物件。使用方法
iterator()
可要求容器(集合等)返回一個Iterator
。iterator()
方法是java.lang.Iterable
介面,被Collection
繼承。
Iterator
介面主要用於遍歷Collection
集合中的元素,Iterator物件
稱為迭代器。
使用`Iterator`的`next()`可獲得序列中的下一個元素。第一次呼叫`next()`方法時,它返回序列的第一個元素。
使用`Iterator`的`hasNext()`可檢查序列中是否還有元素。
使用`remove()`將迭代器新返回的元素刪除。
案例3:泛型---將集合設定為只能存放某型別物件
package day01;
import java.util.HashSet;
import java.util.Set;
public class DayB {
public static void main(String[] args) {
Set <String>sc= new HashSet<String>();
sc.add("Hello");
sc.add(24); //編譯會報錯,只能存放字串型別物件
Set sd=new HashSet();//相當於: Set<Object>sd=new HashSet<>();
}
}
//後面會詳細將泛型
TreeSet類
TreeSet
是SortedSet
介面的實現類:
-
HashSet
是無序的,因為它實現了Set
介面,並沒有實現SortedSet
介面 -
TreeSet
是有序的,因為它實現了SortedSet
介面。
TreeSet
支援兩種排序:自然排序(預設採用)和定製排序
- 自然排序:
TreeSet
會呼叫集合元素的CompareTo(Object obj)方法比較元素間大小關係,並將集合元素按升序排序。TreeSet
集合裡,建議必須放入同樣型別的物件(因為預設會進行排序),否則可能發生型別轉換異常,可以通過泛型進行限制。 - 定製排序:若定製排序,需要存放到集合中的物件對應的類實現
Comparator
介面,並重寫int Compare()
方法。
案例1:自然排序
package day01;
import java.util.Set;
import java.util.TreeSet;
public class DayB {
public static void main(String[] args) {
Set <Integer>sg= new TreeSet<Integer>();
sg.add(234);
sg.add(7);
sg.add(34);
for (Integer a:sg){
System.out.println(a);
}
}
}
/*執行結果為:
7
34
234
*/
案例2:定製排序----將Person
類的物件存到集合中,並按照物件的age
值來進行排序。
package day01;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class DayB { //執行類
public static void main(String[] args) {
Set<Person> sk=new TreeSet<Person>(new Person()); //這裡的泛型限制一定要加上,並且要將Person物件作為引數
Person p1=new Person("krystal",20);
Person p2=new Person("Jimmy",21);
Person p3=new Person("anna",14);
Person p4=new Person("bob",63);
sk.add(p1);
sk.add(p2);
sk.add(p3);
sk.add(p4);
for(Person a:sk){
System.out.println(a.getName()+" : "+a.getAge());
}
}
}
class Person implements Comparator<Person>{ //這裡一定要加上泛型限制,不然報錯
private int age;
private String name;
public Person(){
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
@Override
public int compare(Person o1, Person o2) { //注意這裡的引數要是Person類
if(o1.getAge() > o2.getAge()){ //將>和<調換即可反向排序
return 1;
}else if(o1.getAge()<o2.getAge()){
return -1;
}else {
return 0;
}
}
}
/*執行結果為:
anna : 14
krystal : 20
Jimmy : 21
bob : 63
*/
List
ArrayList類
ArrayList
是List
介面的實現類。ArrayList
是執行緒不安全的。
List
是有序可重複的集合,集合中的元素都有對應的索引。List
可以通過索引來訪問集合指定位置的元素List
將元素新增順序設定為預設索引List
添加了一些通過索引操作集合的方法,如上圖
Vector
(執行緒安全)也是List
介面的實現類,雖然是執行緒安全的,但是比較古老了,不推薦使用。
案例1
import java.util.ArrayList;
import java.util.List;
public class DayB{
public static void main(String[] args) {
List<Integer> la=new ArrayList<Integer>();
la.add(3); //索引下標為0
la.add(53); //索引下標為1
la.add(21); //索引下標為2
System.out.println(la);
System.out.println(la.get(2)); //訪問索引為2的元素
la.add(2,44); //在索引為2的位置新增元素44
System.out.println(la);
List lb=new ArrayList();
lb.add(99);
lb.add(100);
la.addAll(2,lb); //在索引位置新增另一個List集合
System.out.println(la);
la.add(99);
System.out.println(la);
System.out.println(la.indexOf(99)); //檢視元素第一次出現的索引
System.out.println(la.lastIndexOf(99)); //檢視元素最後一次出現的索引
la.remove(4);//移除索引4對應的元素
la.set(2,1024); //將索引為2的元素的值改為1024
List subl=la.subList(1,4);
//將1到3索引的元素作為子集subl,sublist()的作用是返回一個子集物件,左閉右開
System.out.println(subl);
}
}
Map
HashMap類
HashMap是Map介面的實現類,Map介面比較特別,它並沒有去繼承Collection介面。
- Map儲存對映關係資料(key-value)
- Map中的Key不允許重複
案例1:常用方法
package day01;
import java.util.HashMap;
import java.util.Map;
public class DayB{
public static void main(String[] args) {
Map mp=new HashMap();
mp.put("krystal",20); //新增元素
mp.put("Jimmy",21);
System.out.println(mp);
Map<String,Integer> mp2=new HashMap<String,Integer>(); //給Map設定泛型
mp2.put("kobe",41);
mp2.put("gigi",13);
mp2.put("James",35);
mp2.remove("James"); //根據Key移除元素
System.out.println(mp2.size()); //返回map集合的長度
System.out.println(mp2.containsKey("kobe"));//判斷是否包含某key
System.out.println(mp2.containsValue("41")); //判斷是否包含某value
mp2.clear();//清空集合
}
}
/*執行結果為:
{krystal=20, Jimmy=21}
2
true
false
*/
案例2:遍歷map集合
package day01;
import org.omg.PortableInterceptor.INACTIVE;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class DayB{
public static void main(String[] args) {
Map<String,Integer> mp2=new HashMap<String,Integer>(); //給Map設定泛型
mp2.put("kobe",41);
mp2.put("gigi",13);
mp2.put("James",35);
//方法1:建立key集合
Set<String> keys=mp2.keySet(); //建立key集合,keySet()可以返回key集合
for(String s:keys){
System.out.println(s+" : "+ mp2.get(s));
}
//方法2:使用entrySet()方法:
Set<Map.Entry<String, Integer>> a=mp2.entrySet();
for(Map.Entry<String,Integer> en:a){
System.out.println(en.getKey()+" : "+en.getValue());
}
}
}
HashMap與HashTable
HashMap和Hashtable是Map介面的兩個典型實現類,兩者區別:
- Hashtable是一個古老實現類,不推薦使用
- Hashtable執行緒安全,HashMap執行緒不安全
- Hashtable允許使用null作為key和value,HashMap可以
- Hashtable與HashMap都不能保證key-value的順序
- Hashtable與HashMap判斷兩個key相同的標準都是equals()返回true,hashCode值也相等
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
public class DayB{
public static void main(String[] args) {
Map<String,Integer>ma=new HashMap<String,Integer>();
ma.put(null,null); //執行不會報錯
Map<String,Integer>mt=new Hashtable<String,Integer>();
ma.put(null,null); //執行會報錯
}
}
TreeMap類
TreeMap
和TreeSet
一樣,是有序的。
TreeMap
的Key
的排序:
- 自然排序:
TreeMap
的所有Key
必須實現Comparable
介面,且所有的Key
應該是同一個類的物件,否則會丟擲異常ClassCastException
- 定製排序:
Map
的Key
不需要實現Comparable
介面,但是要實現Comparator
介面。
案例1:TreeMap
自然排序
package day01;
import java.util.Map;
import java.util.TreeMap;
public class DayB{
public static void main(String[] args) {
Map<Integer,String> mL=new TreeMap<Integer, String>();
mL.put(3,"apple");
mL.put(2,"banana");
mL.put(5,"grape");
System.out.println(mL);
}
}
/*執行結果為:
{2=banana, 3=apple, 5=grape}
*/
//所有的基本資料型別的包裝類都實現了Comparable介面,例如,Integer的原始碼如下:
public final class Integer extends Number implements Comparable<Integer>{}
案例2:TreeMap
定製排序
package day01;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class DayB {
public static void main(String[] args) {
Map<Shoe,String> mS = new TreeMap<Shoe, String>(new Shoe());
Shoe s1=new Shoe("Jimmy",21);
Shoe s2=new Shoe("Krystal",20);
Shoe s3=new Shoe("who",31);
mS.put(s1,"第一個人");
mS.put(s2,"第二個人");
mS.put(s3,"第三個人");
System.out.println(mS);
Set<Shoe> a= mS.keySet();
for(Shoe i:a){
System.out.println(i.age);
}
}
}
class Shoe implements Comparator<Shoe> {
public int age;
public String name;
public Shoe() {
}
public Shoe(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compare(Shoe o1, Shoe o2) {
if (o1.age > o2.age) {
return 1;
} else if (o1.age < o2.age) {
return -1;
} else {
return 0;
}
}
}
工具類Collections
注意這裡說的是Collections
類,是有s
的,不是Collection
介面。