前面的學習,咱們知道數據多了,使用數組存放。並且數組中存放的都是基本類型的數據,而且數組是定長的。當在程序中建立的對象比較多的時候,須要對這些對象進行統一的管理和操做,那麼首先咱們就須要把這些對象存儲起來。使用數組是能夠存放對象的,咱們能夠定義對象數組來存放,可是數組這個容器存放對象,要對其中的對象進行更復雜操做時,數據就顯的很麻煩。那怎麼辦呢?java
Java中給咱們提供了另一類容器,專門用來存放對象,這個容器就是咱們要學習的集合。數組
集合和數組既然都是容器,它們有啥區別呢?數據結構
數組的長度是固定的。集合的長度是可變的。併發
數組中存儲的是同一類型的元素,能夠存儲基本數據類型值。集合存儲的都是對象。並且對象的類型能夠不一致。框架
集合貌似看起來比較強大,它啥時用呢?工具
當對象多的時候,先進行存儲。學習
集合自己是一個工具,它存放在java.util包中。測試
JDK最先的1.0版本中。提供的集合容器不多。升級到1.2版,爲了更多的需求,出現了集合框架。有了更多的容器。能夠完成不一樣的需求。this
這些容器怎麼區分?區分的方式:每個容器的數據結構(數據存儲到的一種方式)不同。編碼
不一樣的容器進行不斷的向上抽取,最後造成了一個集合框架,這個框架就是Collection接口。在Collection接口定義着集合框架中最最共性的內容。
在學習時:咱們須要看最頂層怎麼用, 建立底層對象便可。由於底層繼承了父類中的全部功能。
既然Collection接口是集合中的頂層接口,那麼它中定義的全部功能子類均可以使用。查閱API中描述的Collection接口。Collection 層次結構 中的根接口。Collection 表示一組對象,這些對象也稱爲 collection 的元素。一些 collection 容許有重複的元素,而另外一些則不容許。一些 collection 是有序的,而另外一些則是無序的。
其實咱們在使用ArrayList類時,該類已經把全部抽象方法進行了重寫。那麼,實現Collection接口的全部子類都會進行方法重寫。
繼續查閱API,發現Collection接口中不少集合的操做方法,那麼這些方法都具體能作什麼呢?
這裏咱們不關心具體建立的Collection中的那個子類對象,這裏重點演示的是Collection接口中的方法
Collection<String> coll = new ArrayList<String>();
//1,往集合中添加對象元素。add(Object);
coll.add("itcast1");
coll.add("itcast2");
coll.add("itcast3");
//2,刪除。
coll.remove("itcast2");
//3,判斷是否包含。
System.out.println(coll.contains("itcast11"));
//4,清除。
coll.clear();
//把集合打印一下。
System.out.println(coll);//[itcast1, itcast2, itcast3]
java中提供了不少個集合,它們在存儲元素時,採用的存儲方式不一樣。咱們要取出這些集合中的元素,可經過一種通用的獲取方式來完成。
Collection集合元素的通用獲取方式:在取元素以前先要判斷集合中有沒有元素,若是有,就把這個元素取出來,繼續在判斷,若是還有就再取出出來。一直把集合中的全部元素所有取出。這種取出方式專業術語稱爲迭代。
集合中把這種取元素的方式描述在Iterator接口中。Iterator接口的經常使用方法以下:
迭代集合元素圖解:
在Collection接口描述了一個抽象方法iterator方法,全部Collection子類都實現了這個方法,而且有本身的迭代形式。
進行代碼演示:
//1,建立集合對象。
Collection<String> coll = new ArrayList<String>();
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
coll.add("abc4");
//2.獲取容器的迭代器對象。經過iterator方法。
Iterator it = coll.iterator();
//3,使用具體的迭代器對象獲取集合中的元素。參閱迭代器的方法
while(it.hasNext()){
System.out.println(it.next());
}
/*
迭代器for循環的形式的使用
for (Iterator it = coll.iterator(); it.hasNext(); ) {
System.out.println(it.next());
}
*/
注意:在進行集合元素取出時,若是集合中已經沒有元素了,還繼續使用迭代器的next方法,將會發生java.util.NoSuchElementException沒有集合元素的錯誤。
下邊分別介紹以上內容:
方法聲明爲:
Iterator<集合中數據類型>iterator()
用來返回專屬於該集合對象的迭代器對象(Iterator的子類對象)。
該接口規定了迭代集合所須要的方法
Iterator規定了兩個方法,集合對象產生的迭代器對象正是經過這兩個方法幫助集合進行迭代工做的。
調用迭代器的hasNext方法判斷是否有下一個元素
調用迭代器的next獲取下一個元素
迭代的常規用法中咱們要儘可能避免在迭代過程當中爲集合添加/刪除數據。不然會報錯,緣由是Java拋出了併發修改異常。
迭代過程當中併發修改異常的緣由爲迭代器中」記憶」的集合長度與集合中實際長度不一樣,而致使出現索引與實際元素不符甚至無限循環的狀況發生。
因此在使用Iterator時,避免相似操做,for循環底層爲迭代器實現,因此也須要避免相似操做。
有些迭代器避免了這樣的問題,如ListIterator,但該類並不通用也不經常使用,實際開發中不多使用,只須要簡單瞭解。
java中提供了不少個集合,它們在存儲元素時,採用的存儲方式不一樣。咱們要取出這些集合中的元素,可經過一種通用的獲取方式來完成。
加強for循環是JDK1.5之後出來的一個高級for循環,專門用來遍歷數組和集合的。它的內部原理實際上是個Iterator迭代器,因此在遍歷的過程當中,不能對集合中的元素進行增刪操做。
格式:
for(元素的數據類型 變量 : Collection集合or數組){
}
它用於遍歷Collection和數組。一般只進行遍歷元素,不要在遍歷的過程當中對集合元素進行增刪操做。
練習一:遍歷數組
int[] arr = new int[]{11,22,33};
for (int n : arr) {//變量n表明被遍歷到的數組元素
System.out.println(n);
}
練習二:遍歷集合
Collection<String> coll = new ArrayList<String>();
coll.add("itcast1");
coll.add("itcast2");
coll.add("itcast3");
coll.add("itcast4");
for(String str : coll){//變量Str表明被遍歷到的集合元素
System.out.println(str);
}
加強for循環和老式的for循環有什麼區別?
注意:新for循環必須有被遍歷的目標。目標只能是Collection或者是數組。
建議:遍歷數組時,若是僅爲遍歷,可使用加強for若是要對數組的元素進行 操做,使用老式for循環能夠經過角標操做。
泛型用來靈活地將數據類型應用到不一樣的類、方法、接口當中。將數據類型做爲參數傳遞。
泛型是數據類型的一部分,咱們將類名與泛型合併一塊兒看作數據類型。
泛型的定義:定義泛型能夠在類中預支地使用未知的類型。
泛型的使用:通常在建立對象時,將未知的類型肯定具體的類型。當沒有指定泛型時,默認類型爲Object類型。
演示下列代碼:
publicclass GenericDemo {
publicstaticvoid main(String[] args) {
Collection<String> list = new ArrayList<String>();
list.add("abc");
list.add("itcast");
//list.add(5);//當集合明確類型後,存放類型不一致就會編譯報錯
//集合已經明確具體存放的元素類型,那麼在使用迭代器的時候,迭代器也一樣會知道具體遍歷元素類型
Iterator<String> it = list.iterator();
while(it.hasNext()){
String str = it.next();
//當使用Iterator<String>控制元素類型後,就不須要強轉了。獲取到的元素直接就是String類型
System.out.println(str.length());
}
}
}
咱們在集合中會大量使用到泛型,這裏來完整地學習泛型知識。
泛型,用來靈活地將數據類型應用到不一樣的類、方法、接口當中。將數據類型做爲參數進行傳遞。
定義格式:修飾符 class 類名<表明泛型的變量> { }
class ArrayList<E>{
public boolean add(E e){ }
public Eget(int index){ }
}
使用格式:建立對象時,肯定泛型的類型
此時,變量E的值就是String類型
class ArrayList<String>{
public boolean add(String e){ }
public Stringget(int index){ }
}
此時,變量E的值就是Integer類型
class ArrayList<Integer>{
public boolean add(Integer e){ }
public Integerget(int index){ }
}
舉例自定義泛型類
publicclass GenericClass<E>{//自定義的類中,能夠寫<>泛型
//E 表示未知的數據類型 調用者建立對象的時候,才能明確數據類型
private E e;
publicvoid setE(E e){
this.e = e;
}
public E getE(){
returne;
}
}
使用:
publicclass GenericClassTest {
publicstaticvoid main(String[] args) {
//對自定義的泛型類,進行測試
GenericClass<Integer> g = new GenericClass<Integer>();
//E傳遞什麼類型就是什麼類型
g.setE(100);
Integer i = g.getE();
System.out.println(i);
}
}
定義格式:修飾符 <表明泛型的變量> 返回值類型 方法名(參數){ }
例如,
publicclass GenericMethod <E>{
publicvoid show(E e){
System.out.println(e);
}
public<T>void function(T t){//自定義泛型的方法
//本身寫一個方法,方法中的數據類型,採用<>泛型
//若是方法中的泛型,和類上的泛型不一樣
// 在方法返回值前加入<>
System.out.println(t);
}
}
使用格式:調用方法時,肯定泛型的類型
publicclass GenericMethodTest {
publicstaticvoid main(String[] args) {
GenericMethod<Double> g = new GenericMethod<Double>();
g.show(1.1);
g.function(1.2F);//傳遞什麼類型就是什麼類型
}
}
定義格式:修飾符 interface接口名<表明泛型的變量> { }
publicinterface Inter <E>{
publicabstractvoid show(E e);
}
使用格式:
1、定義類時肯定泛型的類型
publicclass InterImpl implements Inter<Integer>{
publicvoid show(Integer i){
System.out.println(i);
}
}
此時,變量E的值就是Integer類型。
2、始終不肯定泛型的類型,直到建立對象時,肯定泛型的類型
InterImpl<String> imp= new InterImpl<String>();
此時,變量E的值就是String類型。
publicclass InterImpl<E>implements Inter<E>{
publicvoid show(E e){
System.out.println(e);
}
當使用泛型類或者接口時,傳遞的數據中,泛型類型不肯定,能夠經過通配符<?>表示。可是一旦使用泛型的通配符後,只能使用Object類中的共性方法,集合中元素自身方法沒法使用。
定義:(查看ArrayList的構造方法)沒法在類中使用
使用:調用方法時能夠給予任意類型。參照Arraylist的構造方法
? extends E表明只要是E類型的子類便可
? super E表明只要是E類型的父類便可
/*
* 泛型通配符?,表明任意的數據類型
*
* 定義:(查看ArrayList的構造方法)沒法在類中使用
*
* 使用:調用方法時能夠給予任意類型。參照Arraylist的構造方法
* public ArrayList(Collection<? extends E> c)
* 爲了便於?的理解,咱們將以上方法重寫爲public ArrayList(ArrayList<? extends E> c)
*
* 該方法的意思:建立集合對象A時,給於另一個集合對象B做爲參數,則建立好的集合A中包含了集合B中的元素
*
* ? extends E表明只要是E類型的子類便可
* ? super E表明只要是E類型的父類便可
*/
publicclass Demo01 {
publicstaticvoid main(String[] args) {
//定義集合b,包含3個元素
ArrayList<String> listB = new ArrayList<String>();
listB.add("Jack");
listB.add("Rose");
listB.add("Trump");
//使用集合b建立集合a
ArrayList<Object> listA = new ArrayList<Object>(listB);
listA.add("Obama");
//觀察集合A
System.out.println(listA);
}
按照鬥地主的規則,完成洗牌發牌的動做。
具體規則:
使用54張牌打亂順序
三個玩家參與遊戲,三人交替摸牌,每人17張牌,最後三張留做底牌。
牌能夠設計爲一個ArrayList<String>,每一個字符串爲一張牌。
每張牌由花色數字兩部分組成,咱們可使用花色集合與數字集合嵌套迭代完成每張牌的組裝。
牌由Collections類的shuffle方法進行隨機排序。
將每一個人以及底牌設計爲ArrayList<String>,將最後3張牌直接存放於底牌,剩餘牌經過對3取模依次發牌。
直接打印每一個集合。
修改文件編碼由GBK修改成UTF-8,由於GBK沒有咱們要的梅花、方片、黑桃、紅桃(♠♥♦♣)等字符。
publicclass Poker {
publicstaticvoid main(String[] args) {
//♠♥♦♣
//準備牌
ArrayList<String> poker = new ArrayList<String>();
//花色
ArrayList<String> color = new ArrayList<String>();
color.add("♠");
color.add("♥");
color.add("♦");
color.add("♣");
//數字
ArrayList<String> number = new ArrayList<String>();
for (int i = 2; i <= 10; i++) {
number.add(i+"");
}
number.add("J");
number.add("Q");
number.add("K");
number.add("A");
//完成新牌
for (String thisColor : color) {
for (String thisNumber : number) {
String thisCard = thisColor + thisNumber;
poker.add(thisCard);
}
}
poker.add("小☺");
poker.add("大☻");
//洗牌
Collections.shuffle(poker);
//發牌
//玩家1
ArrayList<String> player1 = new ArrayList<String>();
//玩家2
ArrayList<String> player2 = new ArrayList<String>();
//玩家3
ArrayList<String> player3 = new ArrayList<String>();
//底牌
ArrayList<String> secretCards = new ArrayList<String>();
for (int i = 0; i < poker.size(); i++) {
if(i>=51) {
//最後三張發給底牌
secretCards.add(poker.get(i));
}else {
//剩餘牌經過對3取模依次摸牌
if(i%3==0) {
player1.add(poker.get(i));
}elseif(i%3==1) {
player2.add(poker.get(i));
}else {
player3.add(poker.get(i));
}
}
}
//看牌
System.out.println(player1);
System.out.println(player2);
System.out.println(player3);
System.out.println(secretCards);
}
}