java 泛型和集合_Java集合和泛型
集合
常用的集合有ArrayList,TreeSet,HashMap,HashSet.
ArrayList
最常用的集合,每次插入都在后面追加元素。
TreeSet
以有序狀態(tài)保持并可防止重復。當你需要set集合或元素按照一定的順序排列時,它會很好用。當然,這需要付出一定的成本,每當插入新項目時,它必須要花時間找到適當?shù)奈恢?#xff0c;而ArrayList只要把項目放在最后就行。
TreeSet的元素必須是Comparable的,你必須指出對象應該如何排序。我們已經在上面講過,方法有兩種,分別是:
實現(xiàn)Comparable類。
使用重載,取用Comparator參數(shù)的構造函數(shù)來創(chuàng)建TreeSet,就像sort()的使用一樣。
class ArtistCompare implements Comparator{
public int compare(Song one,Song two){
return one.getAtist().compareTo(two.getArtist());
}
}
ArtistCompare artCompare=new ArtistCompare();
TreeSet tree=new TreeSet(artCompare);
HashMap
針對經常插入或刪除中間元素所設計的高效率集合。
使用方法:
HashMap scores=new HashMap();
scores.put("Kathy",20);
scores.put("Jim",22);
System.out.println(scores.get("Jim"));
HashSet的遍歷方法:
Iterator iter = scores.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Object key = entry.getKey();
Object val = entry.getValue();
String relkey=(String)key;
Integer relval=(Integer) val;
doprocessing();
HashSet
防止重復的集合,可快速的尋找相符的元素。
這里有個問題,對象要怎樣才算相等?是引用到完全相同的對象,還是可以使不同的對象,但是我們所關心的值相等。于是,引出一個關鍵問題:引用相等性和對象相等性。
引用相等性 堆上同一對象的不同引用,如果對這兩個引用調用hashCode(),結果相同。如果沒有被覆蓋的話,hashCode()默認的行為會返回每個對象特定的序號,這個序號一般跟對象的內存位置有關,因此是唯一的。
如果想要知道兩個引用是否相等,可以使用==來比較變量上的字節(jié)組合,如果引用到相同的對象,字節(jié)組合也會一樣。
對象相等性 堆上的兩個不同對象在意義上是相等的,如果你想把兩個不同的對象視為相等,就必須override hashCode()和equals()函數(shù)。
hashCode()
HashSet使用hashcode來達到存取速度較快的存儲方法,如果你嘗試用對象來尋找ArrayList中的相同對象,(不用索引來找),ArrayList會從頭開始找起,但HashSet不是,它是根據(jù)hashcode來找的,不需要從頭找起。
重點在于hashcode相同并不一定保證對象時相等的,學過數(shù)據(jù)結構的同學肯定知道,hashCode()使用的雜湊算法很可能將多個對象傳回相同的雜湊值,越糟糕的雜湊算法越容易碰撞,而且也跟數(shù)據(jù)值域的分布特性有關,因此如果兩個對象的hashcode相同,并不能說它倆就相等,此時還需要使用equals()函數(shù)來進一步確認是否相等。你可以這樣認為,hashcode用來縮小尋找成本,但是最后還需要equals()來確定是否真的找到了相同的對象。
hashCode()的默認行為時對在heap上的對象產生獨特的值,如果你沒有override過,則該class的兩個對象永遠不可能被認為是相同的。
class Song implements Comparable{
String title;
String artist;
public boolean equals(Object aSong ){
Song s = (Song) aSong;
return getTitle.equals(s.getTitle()); //String覆蓋過equals(),我們可以調用。
}
public int hashCode(){
return title.hsahCode(); //String覆蓋過hashCode(),我們直接調用就可以了。
}
public int compareTo(Song s){
return title.compareTo(s.getTitle());
}
public getTitle(){
return title;
}
public getAtirst(){
return artist;
}
}
euqals()
equals()的默認行為是執(zhí)行==的比較,也就是說會去測試兩個引用是否堆上heap上同一個對象,如果eqauls沒有被覆蓋過,兩個對象永遠都不會被視為相同的,因為不同的對象有不同的字節(jié)組合。
toString()
toString()是定義在Object類里的,所以每個java類都會繼承到,且因為對象被System.out.println(anObject)列出來時會調用toString(),所以當你想用被System.out.println輸出你自定義的對象時,你需要重定義toString().
泛型
只要你再java程序或文件中看到<>這一組符號,就代表泛型正在起作用。泛型的主要目的是讓你寫出有類型安全性的集合,也就是,讓編譯器能夠幫忙防止你把Dog放到一群Cat中。
使用泛型的兩種方法:
使用定義在類聲明的類型參數(shù):
public class ArrayList extends AbstractList...{
public boolean add (E o)
...
}
使用未定義在類聲明的參數(shù) public void takeThing (ArrayListlist)
Collections.sort()
Collections.sort()是集合的常用方法,它只接受Comparable對象的list。因此,如果你自定義了一個類,然后生成了很多類對象,并存入集合中,如果你期望用Collections.sort()來對它們進行排序。你需要對你的自定義類做額外的工作。
你有兩種方法:
第一種,實現(xiàn)Comparable 類,并覆蓋它的int compareTo(T o)方法 java.lang.Comparable接口:
public interface Comparable{
int compareTo(T o);
}
class Song implements Comparable{
String title;
String artist;
public int compareTo(Song s){
return title.compareTo(s.getTitle());
}
public getTitle(){
return title;
}
public getAtirst(){
return artist;
}
}
第二種,自制Comparator
使用compareTo()方法時,list中的元素只能有一種將自己與同類型的另一元素相比較的方法。但Comparator是獨立于所比較元素類型之外的--它是獨立的類。因此,你可以有各種不同的比較方法。例如,除了按照title排序,你也可以按照artist排序。
因此,取用Comparator版的sort()方法會用Comparator而不是內置的 compareTo()方法。有如下規(guī)則:
調用單一參數(shù)的sort(List o)方法代表由list元素上的compareTo()方法來決定順序。因此元素必須實現(xiàn)Comparable這個接口。 調用sort(List o,Comparator c)方法代表不會調用list元素的compareTo()方法,而會使用Comparator的compare()方法,這也意味著list元素不用實現(xiàn)
Comparable.
class ArtistCompare implements Comparator{
public int compare(Song one,Song two){
return one.getAtist().compareTo(two.getArtist());
}
}
ArtistCompare artCompare=new ArtistCompare();
Collections.sort(songList,artCompare);
集合的多態(tài)
數(shù)組的多態(tài)
如果方法的參數(shù)是Animal的數(shù)組,它也能夠取用Animal次類型的數(shù)組。
Animal [] animals={new Dog(),new Cat(),new Dog()};
Dog [] dogs={new Dog(),new Dog(),new Dog()};
takeAnimals(animals);
//takeAnimals()能夠存取Animal[]或Dog[]參數(shù),因為Dog也是一個Animal,多態(tài)在此處起作用
takeAnimals(dogs);
public void takeAnimals(Animal [] animals){
for(Animal a : animals){
a.eat();}
}
abstract class Animal{
void eat(){}
}
class Dog extends Animal{
void bark(){}
}
class Cat extends Animal{
void meow(){}
}
ArrayList的多態(tài)
ArrayList animals= new ArrayList();
animals.add(new Dog());
animals.add(new Dog());
animals.add(new Dog());
takeAnimals(animals);
public void takeAnimals(ArrayList animals){
for(Animal a : animals){
a.eat();}
}
因為多態(tài)的關系,編譯器會讓Dog數(shù)組通過取用Animal數(shù)組參數(shù)的方法,這沒有問題,問題是ArrayList< Animal >參數(shù)能接受ArrayList< Dog >嗎,回答是,不行。如果我們在上面的程序里加上這一段,將出現(xiàn)編譯錯誤。
ArrayListdogs = new ArrayList();
dogs.add(new Dog());
dogs.add(new Dog());
takeAnimals(dogs);
可能很多同學會疑惑,畢竟多態(tài)的意義就在于Animal能做的事情,Dog也能做,但你想過嗎,如果我們的takeAnimals()是這樣的:
public void takeAnimals(ArrayList animals){
animals.add(new Cat());
}
這就會有問題了,理論上把Cat加到ArrayList< Animal >是合法的,這也是使用Animal的本意--讓各種Animal都可以加入到此ArrayList中。但是如果你傳入的是一個Dog的ArrayList給該方法,那么將會是Cat強行加入了一個Dog ArrayList中,編譯器當然不會讓這種事情發(fā)生。
所以,如果把方法聲明成ArrayList< Animal >,它只能接受ArrayList< Animal >的參數(shù),ArrayList< Dog>和ArrayList< Cat>都不行。
很多同學肯定又要問了,那為什么數(shù)組可以過關,而ArrayList卻不行,畢竟數(shù)組也會遇到這樣的問題啊。
其實這跟jvm有關,數(shù)組類型是在運行期間檢查的,但集合的類型檢查發(fā)生在編譯期間。
下面這段程序在編譯時不會出錯,但運行時出錯。
Dog [] dogs={new Dog(),new Dog(),new Dog()};
takeAnimals(dogs);
public void takeAnimals(Animal [] animals){
animals[0]=new Cat();
}
那有沒有一種方法,讓我們能夠使用多態(tài)化的集合參數(shù),就像數(shù)組那樣,這樣我們就可以傳入Cat,Dog的集合了,只要我們自己保證不會做出格的行為,比如往Cat集合中加入Dog等等。
萬能的java當然有辦法,使用這種聲明方式:
public void takeThing(ArrayListlist)
當你這樣聲明函數(shù)時,編譯器會阻止任何可能破壞引用參數(shù)所指集合的行為。也就是,你可以調用list中任何元素的方法,但是不能加入元素。
也就是說你可以操作集合元素,但是不能增加集合元素。如此才能保障執(zhí)行期間的安全性。編譯器會阻止執(zhí)行期的恐怖活動。
所以下面的程序是可行的:
for (Animal a :animals){a.eat();}
但這個就過不了編譯:
animals.add(new Cat());
總結
以上是生活随笔為你收集整理的java 泛型和集合_Java集合和泛型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: beatssolo2和3的区别
- 下一篇: JAVA期末考试工程部分_知到Java程