摘要:迭代器解決了這個(gè)問題。刪除后于是我們可以寫一個(gè)方法,接受一個(gè)類型,然后讓他調(diào)用方法,這就不需要考慮這個(gè)是個(gè)還是了,也就是說,可以將遍歷容器的操作與序列底層的結(jié)構(gòu)分離,迭代器統(tǒng)一了對(duì)容器類的訪問方式。十二和兩種遍歷的方法,與迭代器方法。
一、泛型和類型安全的容器
package tij.hoding; import java.util.ArrayList; public class Test { @SuppressWarnings("unchecked") public static void main(String[] args) { ArrayList apples=new ArrayList(); for(int i=0;i<2;i++){ apples.add(new Apple()); } apples.add(new Orange()); for(int i=0;i在運(yùn)行期的類型轉(zhuǎn)換時(shí)會(huì)出現(xiàn)問題,因?yàn)槭褂胓et方法的時(shí)候取出來的其實(shí)object類型,之前程序中放進(jìn)去了一個(gè)orange卻要將他轉(zhuǎn)成一個(gè)apple。
因此需要使用類型參數(shù)來指定這個(gè)容器實(shí)例可以保存的類型,通過使用類型參數(shù),就可以在編譯期放置將錯(cuò)誤的類型放在容器中,上面的代碼改成下面類型package tij.hoding; import java.util.ArrayList; public class Test { public static void main(String[] args) { ArrayListapples=new ArrayList<>(); for(int i=0;i<2;i++){ apples.add(new Apple()); } for(int i=0;i 同樣,可以將容器的類型參數(shù)的指定類型以及其子類類型的實(shí)例變量放進(jìn)這個(gè)容器中,例子略
二、基本概念Java容器類可以劃分為兩個(gè)不同的概念
Collection
一個(gè)存儲(chǔ)獨(dú)立元素的序列,不同序列有不同的規(guī)則:List必須按照插入順序保存元素;Set不能有重復(fù)元素;Queue按照排隊(duì)規(guī)則確定對(duì)象產(chǎn)生的順序。Map
一組成對(duì)的簡直對(duì)對(duì)象然而大多數(shù)情況在編寫代碼的時(shí)候都是與接口打交道,唯一需要精確指定使用的容器類型的地方就是創(chuàng)建的時(shí)候,如下
Listapples=new ArrayList (); 就是說多數(shù)情況我們是面向接口編程的,但也并不都是這樣,比如如果我們要使用LinkedList里的特有的功能,就不能用這種方法了。
三、添加一組元素Collections和Arrays類中提供了很多與序列相關(guān)的方法,有啥自己去找API看去就行了。
注明package tij.hoding; import java.util.Arrays; import java.util.List; public class Test { public static void main(String[] args) { Listsnow1=Arrays.asList(new Crusty(),new Slush(),new Powder(),new Light()); List snow2=Arrays.asList(new Light(),new Heavy()); } } class Snow{} class Powder extends Snow{} class Light extends Powder{} class Heavy extends Powder{} class Crusty extends Snow{} class Slush extends Snow{} 書上說snow2是創(chuàng)建不了的,我用的是JDK1.8發(fā)現(xiàn)是可以創(chuàng)建的。
四、容器的打印沒啥說的,數(shù)組的打印可以用Arrays.toString方法
五、ListList接口在Collection基礎(chǔ)上添加了大量方法
基本的ArrayList,訪問快,中間插入和移除較慢
LinkedList,進(jìn)行中間的插入刪除代價(jià)低
六、迭代器
方法找API看對(duì)于List,add方法是插入元素的方法,get方法是去除元素的方法,但是這是有弊端的,如果使用容器,如果需要對(duì)元素進(jìn)行操作,就必須要針對(duì)容器的確切類型進(jìn)行編程,舉個(gè)例子,如果要從一個(gè)List里取出元素,我們寫了一些方法,但如果希望將這些方法再運(yùn)用到同是Collection類的set類上,就不行了,因?yàn)閟et根本沒有g(shù)et方法。迭代器解決了這個(gè)問題。
package tij.hoding; import java.util.ArrayList; import java.util.Iterator; public class Test { public static void main(String[] args) { ArrayListstr_list = new ArrayList (); for (int i = 0; i < 10; i++) str_list.add("123134"); Iterator it = str_list.iterator(); while (it.hasNext()) { System.out.println(it.next()); } it = str_list.iterator(); for (int i = 0; i < 5; i++) { it.next(); it.remove(); } System.out.println("----刪除后"); it = str_list.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } 于是我們可以寫一個(gè)方法,接受一個(gè)collection類型,然后讓他調(diào)用iterator()方法,這就不需要考慮這個(gè)collection是個(gè)list還是set了,也就是說,可以將遍歷容器的操作與序列底層的結(jié)構(gòu)分離,迭代器統(tǒng)一了對(duì)容器類的訪問方式。
1.ListIterator這是個(gè)List專用的迭代器,他可以雙向移動(dòng),可以生成索引,可以使用set方法對(duì)元素進(jìn)行替換,而且在創(chuàng)建的時(shí)候還可以指從哪開始迭代,具體看API
七、LinkedListLinkedList里有很多功能類似的方法,比如peek、element、getFirst,這是因?yàn)槌R詌inkedList為基礎(chǔ)制作堆棧等數(shù)據(jù)結(jié)構(gòu),在這種數(shù)據(jù)結(jié)構(gòu)中使用push啊pop啊更合適,雖然我覺得有一些= =額= =恩。。。。
八、Stack沒啥好說的,就是用Linkedlist實(shí)現(xiàn),LIFO
九、SetSet保證集合內(nèi)元素的唯一性,同時(shí)Set也有不同的類型:HashSet使用了散列函數(shù);TreeSet將元素存儲(chǔ)在紅黑樹數(shù)據(jù)結(jié)構(gòu)中,可以完成元素按比較方法的排序;LinkedHashSet也使用了散列,但它通過使用鏈表維護(hù)了元素插入順序
十、Map存儲(chǔ)映射關(guān)系的數(shù)據(jù)結(jié)構(gòu)
十一、QueueFIFO的容器
1.PriorityQueue
看API挺簡單的優(yōu)先級(jí)隊(duì)列聲明下一個(gè)彈出的元素是最需要的元素(優(yōu)先級(jí)最高)。當(dāng)用PriorityQueue上調(diào)用offer方法插入一個(gè)對(duì)象時(shí),這個(gè)對(duì)象會(huì)在隊(duì)列中被排序,可以使用對(duì)象的自然排序也可以提供自己的Comparator來修改排序規(guī)則。PriorityQueue可以確保調(diào)用各種方法時(shí),根據(jù)優(yōu)先級(jí)進(jìn)行操作。
package tij.hoding; import java.util.Arrays; import java.util.List; import java.util.PriorityQueue; import java.util.Queue; import java.util.Random; public class Test { public static void main(String[] args) { PriorityQueue十二、Collection和IteratorpriorityQueue = new PriorityQueue (); Random rand = new Random(47); for (int i = 0; i < 10; i++) { priorityQueue.offer(rand.nextInt(i + 10)); } printQ(priorityQueue); List ints = Arrays.asList(25, 22, 20, 18, 14, 9, 3, 1, 1, 2, 3, 9, 14, 18, 21, 23, 25); priorityQueue = new PriorityQueue (ints); printQ(priorityQueue); } @SuppressWarnings("rawtypes") static void printQ(Queue queue) { while (queue.peek() != null) { System.out.print(queue.remove() + " "); } System.out.println(); } } 兩種遍歷的方法,foreach與迭代器方法。
十三、Foreach與迭代器
同時(shí)有一種默認(rèn)的AbstractCollection,繼承他可以較為簡單的將自己的類變成Collection類型而不用實(shí)現(xiàn)原Collection全部的方法因?yàn)橛辛说?,所以有了Foreach功能,這個(gè)功能真的很強(qiáng)大
package tij.hoding; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; public class Test { public static void main(String[] args) { Collectioncs = new LinkedList (); Collections.addAll(cs, "Take the long way home".split(" ")); for (String s : cs) { System.out.print(s + " "); } } } 而這是因?yàn)镴ava se5引入了Iterable幾口,實(shí)現(xiàn)了Iterable接口的類都可應(yīng)用于Foreach之中。比如下面
package tij.hoding; import java.util.Iterator; public class Test { public static void main(String[] args) { for (String s : new IterableClass()) { System.out.print(s + " "); } } } class IterableClass implements Iterable{ protected String[] words = "And that is how we know the Earth to be banana-shaped" .split(" "); @Override public Iterator iterator() { return new Iterator () { private int index = 0; @Override public boolean hasNext() { return index < words.length; } @Override public String next() { return words[index++]; } }; } } 首先要搞懂Foreach語句中for(element:container)里的container要是iterable類型的才可以,foreach在遍歷時(shí),首先調(diào)用container的iterator方法得到這個(gè)iterator,然后就是在調(diào)用這個(gè)iterator的的hasNext和next方法
1.適配器方法慣用法假如現(xiàn)在有一個(gè)類記錄了一串兒單詞,希望能運(yùn)用Foreach方法將他遍歷,只要讓他實(shí)現(xiàn)Iterable接口實(shí)現(xiàn)Iterator功能就可以了,但是現(xiàn)在希望他既能順向遍歷,又能逆向遍歷,這就不好辦了,因?yàn)槟阒荒苤貙慖terator一次啊。
一種解決方案就是所謂的適配機(jī)器方法,當(dāng)你有一個(gè)接口并需要另一個(gè)接口的時(shí)候,編寫適配器就可以解決問題。package tij.hoding; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; public class Test { public static void main(String[] args) { ReversibleArrayListral = new ReversibleArrayList ( Arrays.asList("To be or not to be".split(" "))); for (String s : ral) { System.out.print(s + " "); } System.out.println(); for (String s : ral.reversed()) { System.out.print(s + " "); } } } @SuppressWarnings("serial") class ReversibleArrayList extends ArrayList { public ReversibleArrayList(Collection c) { super(c); } public Iterable reversed() { return new Iterable () { @Override public Iterator iterator() { return reversed_iterator(); } private Iterator reversed_iterator() { return new Iterator () { int current = size() - 1; public boolean hasNext() { return current > -1; } public T next() { return get(current--); } }; } }; } } 其實(shí)這個(gè)程序我看了半天才看懂,首先要搞懂Foreach語句中for(element:container)里的container要是iterable類型的才可以,foreach在遍歷時(shí),首先調(diào)用container的iterator方法得到這個(gè)iterator,然后就是在調(diào)用這個(gè)iterator的的hasNext和next方法。然后再順序遍歷的時(shí)候,傳入的是ral,然后調(diào)用ral自身的iterator本身的hasNext和next方法,就是順序遍歷了;在逆向遍歷的時(shí)候,傳入的是一個(gè)新的iterable,得到的也是一個(gè)新的iterator,然后調(diào)用的就是這個(gè)新的iteratoriterator的兩個(gè)方法。
另外我想了一下next方法里的get方法是誰的,然后用了內(nèi)部類訪問外部的方法也能調(diào)用ReversibleArrayList.this.get()于是我們就可以弄很多很多不同的遍歷規(guī)則了,比如隨機(jī)遍歷啊
package tij.hoding; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Random; public class Test { public static void main(String[] args) { ReversibleArrayListral = new ReversibleArrayList ( Arrays.asList("To be or not to be".split(" "))); for (String s : ral) { System.out.print(s + " "); } System.out.println(); for (String s : ral.reversed()) { System.out.print(s + " "); } System.out.println(); for (String s : ral.randomized()) { System.out.print(s + " "); } } } @SuppressWarnings("serial") class ReversibleArrayList extends ArrayList { public ReversibleArrayList(Collection c) { super(c); } public Iterable reversed() { return new Iterable () { @Override public Iterator iterator() { return reversed_iterator(); } private Iterator reversed_iterator() { return new Iterator () { int current = size() - 1; public boolean hasNext() { return current > -1; } public T next() { return ReversibleArrayList.this.get(current--); } }; } }; } public Iterable randomized(){ return new Iterable (){ @Override public Iterator iterator() { List shuffle= ReversibleArrayList.this; Collections.shuffle(shuffle,new Random(47)); return shuffle.iterator(); } }; } } 可以注意到在隨機(jī)遍歷的時(shí)候,實(shí)際返回了一個(gè)新的序列的iterator這是為了不打亂原始的序列的順序
附一張簡單的容器分類
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/67583.html
摘要:內(nèi)部類中也可以取得這個(gè)外部類對(duì)象引用。創(chuàng)建成員內(nèi)部類對(duì)象的時(shí)候需要外部類對(duì)象。另外在方法中的內(nèi)部類不能加等權(quán)限修飾符,只能加和修飾符??梢栽诮涌趦?nèi)部定義內(nèi)部類,而且他們即使沒有修飾,也會(huì)自動(dòng)變成的。 Thinking in Java撈干貨,寫筆記 一、成員內(nèi)部類 1.最基本使用 public class Demo { class Contents{ privat...
摘要:四上的操作看五格式化輸出運(yùn)用和語言很相似和是等價(jià)的喲類格式化說明符轉(zhuǎn)換六正則表達(dá)式網(wǎng)上教程學(xué)七掃描輸入新增了類。 一、不可變String String類型的對(duì)象是不可變的,所有的改變實(shí)際上都是創(chuàng)建了一個(gè)新的String對(duì)象,另外當(dāng)String作為傳入?yún)?shù)的時(shí)候,其實(shí)實(shí)際上傳入的是這個(gè)引用的一個(gè)拷貝,這個(gè)方法結(jié)束了之后這個(gè)傳入的引用也就消失了,原來的那個(gè)String不會(huì)受到方法內(nèi)的影響而...
摘要:基類導(dǎo)出類導(dǎo)出類繼承了基類的特點(diǎn),基類和導(dǎo)出類具有相同的基礎(chǔ)接口,形成兩者差異的做法在導(dǎo)出類中添加新方法在導(dǎo)出類型中添加新的接口元素,擴(kuò)展了接口。覆蓋在導(dǎo)出類用創(chuàng)建方法的新定義,覆蓋基類中的方法定義純粹替代,只覆蓋。 一、抽象過程 建?;谟?jì)算機(jī)的結(jié)構(gòu) 解空間的解 匯編語言:對(duì)底層機(jī)器的輕微抽象 命令式語言:匯編語言的抽象 建?;诖鉀Q問題 問題空間的元素 面向?qū)ο? 二、每個(gè)...
摘要:通過運(yùn)行時(shí)類型信息,程序能夠使用基類的指針或引用來檢查這些指針或引用所指的對(duì)象的實(shí)際派生類型。編程應(yīng)該盡量面向接口編程,應(yīng)該對(duì)類型信息盡量的少了解二對(duì)象看書,書上寫得好靜態(tài)語句塊在這個(gè)類被加載的時(shí)候運(yùn)行。 一、為什么需要RTTI Run-Time Type Information。通過運(yùn)行時(shí)類型信息,程序能夠使用基類的指針或引用來檢查這些指針或引用所指的對(duì)象的實(shí)際派生類型。編程應(yīng)該盡量...
摘要:而這可以通過注解辦到,在代碼中以指令語言的形式化方法來為代碼提供更多信息。有注解的說明這個(gè)成員變量是一個(gè)列名,然后根據(jù)注解信息來生成相應(yīng)的語句。也就是說把注解信息提取了出來。 注解是向代碼中添加信息的一種方法,并且在之后還可以使用這些數(shù)據(jù)就比如這個(gè)方法是用來剝香蕉的,但是我們看就是一串代碼,我們沒辦法在代碼里寫一段指令說我這個(gè)程序是用來剝香蕉的,當(dāng)然除了注釋。而這可以通過注解辦到,在代...
閱讀 1090·2021-11-22 15:33
閱讀 3395·2021-11-08 13:20
閱讀 1414·2021-09-22 10:55
閱讀 2075·2019-08-29 11:08
閱讀 800·2019-08-26 12:24
閱讀 3101·2019-08-23 17:15
閱讀 2260·2019-08-23 16:12
閱讀 1971·2019-08-23 16:09