java arraylist排序_最全Java集合笔记
集合概述
集合框架:用于存儲(chǔ)數(shù)據(jù)的容器。
集合框架是為表示和操作集合而規(guī)定的一種統(tǒng)一的標(biāo)準(zhǔn)的體系結(jié)構(gòu)。任何集合框架都包含三大塊內(nèi)容:對(duì)外的接口、接口的實(shí)現(xiàn)和對(duì)集合運(yùn)算的算法。
接口:表示集合的抽象數(shù)據(jù)類型。接口允許我們操作集合時(shí)不必關(guān)注具體實(shí)現(xiàn),從而達(dá)到“多態(tài)”。在面向?qū)ο缶幊陶Z(yǔ)言中,接口通常用來(lái)形成規(guī)范。
實(shí)現(xiàn):集合接口的具體實(shí)現(xiàn),是重用性很高的數(shù)據(jù)結(jié)構(gòu)。
算法:在一個(gè)實(shí)現(xiàn)了某個(gè)集合框架中的接口的對(duì)象身上完成某種有用的計(jì)算的方法,例如查找、排序等。這些算法通常是多態(tài)的,因?yàn)橄嗤姆椒梢栽谕粋€(gè)接口被多個(gè)類實(shí)現(xiàn)時(shí)有不同的表現(xiàn)。事實(shí)上,算法是可復(fù)用的函數(shù)。它減少了程序設(shè)計(jì)的辛勞。
集合框架通過(guò)提供有用的數(shù)據(jù)結(jié)構(gòu)和算法使你能集中注意力于你的程序的重要部分上,而不是為了讓程序能正常運(yùn)轉(zhuǎn)而將注意力于底層設(shè)計(jì)上。通過(guò)這些在無(wú)關(guān)API之間的簡(jiǎn)易的互用性,使你免除了為改編對(duì)象或轉(zhuǎn)換代碼以便聯(lián)合這些API而去寫大量的代碼。 它提高了程序速度和質(zhì)量。
集合的特點(diǎn)
集合的特點(diǎn)主要有如下兩點(diǎn):
- 對(duì)象封裝數(shù)據(jù),對(duì)象多了也需要存儲(chǔ)。集合用于存儲(chǔ)對(duì)象。
- 對(duì)象的個(gè)數(shù)確定可以使用數(shù)組,對(duì)象的個(gè)數(shù)不確定的可以用集合。因?yàn)榧鲜强勺冮L(zhǎng)度的。
集合和數(shù)組的區(qū)別
- 數(shù)組是固定長(zhǎng)度的;集合可變長(zhǎng)度的。
- 數(shù)組可以存儲(chǔ)基本數(shù)據(jù)類型,也可以存儲(chǔ)引用數(shù)據(jù)類型;集合智能存儲(chǔ)引用數(shù)據(jù)類型。
- 數(shù)組存儲(chǔ)的元素必須是同一個(gè)數(shù)據(jù)類型;集合存儲(chǔ)的對(duì)象可以是不同數(shù)據(jù)類型。
使用集合框架的好處
- 容量自增長(zhǎng);
- 提供了高性能的數(shù)據(jù)結(jié)構(gòu)和算法,使編碼更輕松,提高了程序速度和質(zhì)量;
- 允許不同 API 之間的互操作,API之間可以來(lái)回傳遞集合;
- 可以方便地?cái)U(kuò)展或改寫集合,提高代碼復(fù)用性和可操作性。
- 通過(guò)使用JDK自帶的集合類,可以降低代碼維護(hù)和學(xué)習(xí)新API成本。
常用的集合類有哪些?
Map接口和Collection接口是所有集合框架的父接口:
Collection接口的子接口包括:Set接口和List接口Map接口的實(shí)現(xiàn)類主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及Properties等Set接口的實(shí)現(xiàn)類主要有:HashSet、TreeSet、LinkedHashSet等List接口的實(shí)現(xiàn)類主要有:ArrayList、LinkedList、Stack以及Vector等
List,Set,Map三者的區(qū)別?List、Set、Map 是否繼承自 Collection 接口?List、Map、Set 三個(gè)接口存取元素時(shí),各有什么特點(diǎn)?
集合框架底層數(shù)據(jù)結(jié)構(gòu)
Collection
- Arraylist: Object數(shù)組
- Vector: Object數(shù)組
- LinkedList: 雙向循環(huán)鏈表
- HashSet(無(wú)序,唯一):底層采用 HashMap 來(lái)保存元素
- LinkedHashSet: LinkedHashSet 繼承于HashSet,并且其內(nèi)部是通過(guò) LinkedHashMap 來(lái)實(shí)現(xiàn)的。
- TreeSet(有序,唯一): 紅黑樹(自平衡的排序二叉樹。)
Map
- HashMap: JDK1.8之前HashMap由數(shù)組+鏈表組成的;JDK1.8以后鏈表+紅黑樹;
- LinkedHashMap:LinkedHashMap 繼承自 HashMap,所以它的底層仍然是基于拉鏈?zhǔn)缴⒘薪Y(jié)構(gòu)即由數(shù)組和鏈表或紅黑樹組成。另外,LinkedHashMap 在上面結(jié)構(gòu)的基礎(chǔ)上,增加了一條雙向鏈表,使得上面的結(jié)構(gòu)可以保持鍵值對(duì)的插入順序。同時(shí)通過(guò)對(duì)鏈表進(jìn)行相應(yīng)的操作,實(shí)現(xiàn)了訪問(wèn)順序相關(guān)邏輯。
- HashTable: 數(shù)組+鏈表組成的,數(shù)組是 HashMap 的主體,鏈表則是主要為了解決哈希沖突而存在
- TreeMap: 紅黑樹(自平衡的排序二叉樹)
哪些集合類是線程安全的?
- vector:就比arraylist多了個(gè)同步化機(jī)制(線程安全),因?yàn)樾瘦^低,現(xiàn)在已經(jīng)不太建議使用。在web應(yīng)用中,特別是前臺(tái)頁(yè)面,往往效率(頁(yè)面響應(yīng)速度)是優(yōu)先考慮的。
- statck:堆棧類,先進(jìn)后出。
- hashtable:就比hashmap多了個(gè)線程安全。
- enumeration:枚舉,相當(dāng)于迭代器。
Java集合的快速失敗機(jī)制 “fail-fast”?
是java集合的一種錯(cuò)誤檢測(cè)機(jī)制,當(dāng)多個(gè)線程對(duì)集合進(jìn)行結(jié)構(gòu)上的改變的操作時(shí),有可能會(huì)產(chǎn)生 fail-fast 機(jī)制。
例如:假設(shè)存在兩個(gè)線程(線程1、線程2),線程1通過(guò)Iterator在遍歷集合A中的元素,在某個(gè)時(shí)候線程2修改了集合A的結(jié)構(gòu)(是結(jié)構(gòu)上面的修改,而不是簡(jiǎn)單的修改集合元素的內(nèi)容),那么這個(gè)時(shí)候程序就會(huì)拋出
ConcurrentModificationException 異常,從而產(chǎn)生fail-fast機(jī)制。
原因:迭代器在遍歷時(shí)直接訪問(wèn)集合中的內(nèi)容,并且在遍歷過(guò)程中使用一個(gè) modCount 變量。集合在被遍歷期間如果內(nèi)容發(fā)生變化,就會(huì)改變modCount的值。每當(dāng)?shù)魇褂胔ashNext()/next()遍歷下一個(gè)元素之前,都會(huì)檢測(cè)modCount變量是否為expectedmodCount值,是的話就返回遍歷;否則拋出異常,終止遍歷。
解決辦法:
在遍歷過(guò)程中,所有涉及到改變modCount值的地方全部加上synchronized。
使用CopyOnWriteArrayList來(lái)替換ArrayList
怎么確保一個(gè)集合不能被修改?
可以使用 Collections. unmodifiableCollection(Collection c) 方法來(lái)創(chuàng)建一個(gè)只讀集合,這樣改變集合的任何操作都會(huì)拋出 Java. lang.
UnsupportedOperationException 異常。
Collection接口
List接口
迭代器 Iterator 是什么?
Iterator 接口提供遍歷任何 Collection 的接口。迭代器取代了 Java 集合框架中的 Enumeration,迭代器允許調(diào)用者在迭代過(guò)程中移除元素。
Iterator 怎么使用?有什么特點(diǎn)?
Iterator 的特點(diǎn)是只能單向遍歷,但是更加安全,因?yàn)樗梢源_保,在當(dāng)前遍歷的集合元素被更改的時(shí)候,就會(huì)拋出
ConcurrentModificationException 異常。
如何邊遍歷邊移除 Collection 中的元素?
邊遍歷邊修改 Collection 的唯一正確方式是使用 Iterator.remove() 方法
Iterator 和 ListIterator 有什么區(qū)別?
- Iterator 可以遍歷 Set 和 List 集合,而 ListIterator 只能遍歷 List。
- Iterator 只能單向遍歷,而 ListIterator 可以雙向遍歷(向前/后遍歷)。
- ListIterator 實(shí)現(xiàn) Iterator 接口,然后添加了一些額外的功能,比如添加一個(gè)元素、替換一個(gè)元素、獲取前面或后面元素的索引位置。
遍歷一個(gè) List 有哪些不同的方式?每種方法的實(shí)現(xiàn)原理是什么?Java 中 List 遍歷的最佳實(shí)踐是什么?
推薦的做法就是,支持 Random Access 的列表可用 for 循環(huán)遍歷,否則建議用 Iterator 或 foreach 遍歷。
說(shuō)一下 ArrayList 的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):隨機(jī)訪問(wèn)快
缺點(diǎn):插入刪除需復(fù)制,耗費(fèi)性能
如何實(shí)現(xiàn)數(shù)組和 List 之間的轉(zhuǎn)換?
- 數(shù)組轉(zhuǎn) List:使用 Arrays. asList(array) 進(jìn)行轉(zhuǎn)換。
- List 轉(zhuǎn)數(shù)組:使用 List 自帶的 toArray() 方法。
ArrayList 和 LinkedList 的區(qū)別是什么?
數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn):ArrayList 動(dòng)態(tài)數(shù)組,而 LinkedList 雙向鏈表隨機(jī)訪問(wèn)效率:ArrayList 更好增加和刪除效率:LinkedList 更好內(nèi)存空間占用:LinkedList 比 ArrayList 更占內(nèi)存,因?yàn)?LinkedList 的節(jié)點(diǎn)除了存儲(chǔ)數(shù)據(jù),還存儲(chǔ)了兩個(gè)應(yīng)用線程安全:都不保證線程安全;綜合來(lái)說(shuō),在需要頻繁讀取集合中的元素時(shí),更推薦使用 ArrayList,而在插入和刪除操作較多時(shí),更推薦使用 LinkedList。
ArrayList 和 Vector 的區(qū)別是什么?
- 線程安全:Vector 使用了 Synchronized 來(lái)實(shí)現(xiàn)線程同步,是線程安全的,而 ArrayList 是非線程安全的。
- 性能:ArrayList 在性能方面要優(yōu)于 Vector。
- 擴(kuò)容:ArrayList 和 Vector 都會(huì)根據(jù)實(shí)際的需要?jiǎng)討B(tài)的調(diào)整容量,只不過(guò)在 Vector 擴(kuò)容每次會(huì)增加 1 倍,而 ArrayList 只會(huì)增加 50%。
插入數(shù)據(jù)時(shí),ArrayList、LinkedList、Vector誰(shuí)速度較快?闡述 ArrayList、Vector、LinkedList 的存儲(chǔ)性能和特性?
ArrayList、Vector 底層數(shù)組方式存儲(chǔ)數(shù)據(jù)。
LinkedList 雙向鏈表,LinkedList 插入速度較快。
多線程場(chǎng)景下如何使用 ArrayList?
ArrayList 不是線程安全的,如果遇到多線程場(chǎng)景,可以通過(guò) Collections 的 synchronizedList 方法將其轉(zhuǎn)換成線程安全的容器后再使用
為什么 ArrayList 的 elementData 加上 transient 修飾?
每次序列化時(shí),先調(diào)用 defaultWriteObject() 方法序列化 ArrayList 中的非 transient 元素,然后遍歷 elementData,只序列化已存入的元素,這樣既加快了序列化的速度,又減小了序列化之后的文件大小。
List 和 Set 的區(qū)別
list: 有序 元素可重復(fù) 多個(gè)null 有索引 for和iterator 檢索低效 插入刪除高效
set: 無(wú)序 不可重復(fù) 一個(gè)null iterator 查找高效 插入刪除低效
Set接口
說(shuō)一下 HashSet 的實(shí)現(xiàn)原理?
HashSet: 底層HashMap hashmap的value統(tǒng)一為PRESENT 底層調(diào)用hashmap的方法 hashset不允許重復(fù)
HashSet如何檢查重復(fù)?HashSet是如何保證數(shù)據(jù)不可重復(fù)的?
檢查重復(fù),不僅比較hash值,還要結(jié)合equals方法
值作為hashmap的key,所以不會(huì)重復(fù)
Queue
BlockingQueue是什么?
阻塞隊(duì)列 在進(jìn)行檢索或移除一個(gè)元素的時(shí)候,它會(huì)等待隊(duì)列變?yōu)榉强?#xff1b;當(dāng)在添加一個(gè)元素時(shí),它會(huì)等待隊(duì)列中的可用空間
在 Queue 中 poll()和 remove()有什么區(qū)別?
相同點(diǎn):返回第一元素,并刪除
不同點(diǎn):沒(méi)有元素,poll返回null remove拋出異常NoSuchElementException
Map接口
說(shuō)一下 HashMap 的實(shí)現(xiàn)原理?
概述: HashMap是基于哈希表的Map接口的非同步實(shí)現(xiàn)
數(shù)組和鏈表的結(jié)合體
1.用key的hashcode作hash計(jì)算下標(biāo)
2.(1)key相同,覆蓋原始值;(2)key不同(出現(xiàn)沖突),key-value放入鏈表
Jdk 1.8中對(duì)HashMap的實(shí)現(xiàn)做了優(yōu)化,當(dāng)鏈表中的節(jié)點(diǎn)數(shù)據(jù)超過(guò)八個(gè)之后,該鏈表會(huì)轉(zhuǎn)為紅黑樹來(lái)提高查詢效率,從原來(lái)的O(n)到O(logn)
HashMap在JDK1.7和JDK1.8中有哪些不同?HashMap的底層實(shí)現(xiàn)
JDK1.8之前: 數(shù)據(jù)+鏈表; 之后:鏈表長(zhǎng)度大于閾值(默認(rèn)為8),鏈表轉(zhuǎn)為紅黑樹
HashMap的put方法的具體流程?
①.判斷鍵值對(duì)數(shù)組table是否為空或?yàn)閚ull,否則執(zhí)行resize()進(jìn)行擴(kuò)容;
②.根據(jù)鍵值key計(jì)算hash值得到插入的數(shù)組索引i,如果table[i]==null,直接新建節(jié)點(diǎn)添加,轉(zhuǎn)向⑥,如果table[i]不為空,轉(zhuǎn)向③;
③.判斷table[i]的首個(gè)元素是否和key一樣,如果相同直接覆蓋value,否則轉(zhuǎn)向④,這里的相同指的是hashCode以及equals;
④.判斷table[i] 是否為treeNode,即table[i] 是否是紅黑樹,如果是紅黑樹,則直接在樹中插入鍵值對(duì),否則轉(zhuǎn)向⑤;
⑤.遍歷table[i],判斷鏈表長(zhǎng)度是否大于8,大于8的話把鏈表轉(zhuǎn)換為紅黑樹,在紅黑樹中執(zhí)行插入操作,否則進(jìn)行鏈表的插入操作;遍歷過(guò)程中若發(fā)現(xiàn)key已經(jīng)存在直接覆蓋value即可;
⑥.插入成功后,判斷實(shí)際存在的鍵值對(duì)數(shù)量size是否超過(guò)了最大容量threshold,如果超過(guò),進(jìn)行擴(kuò)容。
HashMap的擴(kuò)容操作是怎么實(shí)現(xiàn)的?
①.在jdk1.8中,resize方法是在hashmap中的鍵值對(duì)大于閥值時(shí)或者初始化時(shí),就調(diào)用resize方法進(jìn)行擴(kuò)容;
②.每次擴(kuò)展的時(shí)候,都是擴(kuò)展2倍;
③.擴(kuò)展后Node對(duì)象的位置要么在原位置,要么移動(dòng)到原偏移量?jī)杀兜奈恢谩?/p>
HashMap是怎么解決哈希沖突的?
什么是哈希:就是把任意長(zhǎng)度的輸入通過(guò)散列算法,變換成固定長(zhǎng)度的輸出,該輸出就是散列值(哈希值)
基本特性:根據(jù)同一散列函數(shù)計(jì)算出的散列值如果不同,那么輸入值肯定也不同。但是,根據(jù)同一散列函數(shù)計(jì)算出的散列值如果相同,輸入值不一定相同
什么是哈希沖突:當(dāng)兩個(gè)不同的輸入值,根據(jù)同一散列函數(shù)計(jì)算出相同的散列值的現(xiàn)象,我們就把它叫做碰撞(哈希碰撞)
HashMap的數(shù)據(jù)結(jié)構(gòu):數(shù)組的特點(diǎn)是:尋址容易,插入和刪除困難;鏈表的特點(diǎn)是:尋址困難,但插入和刪除容易
hash()函數(shù):與自己右移16位進(jìn)行異或運(yùn)算(高低位異或)
能否使用任何類作為 Map 的 key?
可以,考慮一下幾點(diǎn):
1.重寫了 equals() 方法,也應(yīng)該重寫 hashCode() 方法。
2.遵循與 equals() 和 hashCode() 相關(guān)的規(guī)則。
3.用戶自定義 Key 類最佳實(shí)踐是使之為不可變的
為什么HashMap中String、Integer這樣的包裝類適合作為Key?
1.都是final類型,即不可變性,保證key的不可更改性,不會(huì)存在獲取hash值不同的情況
2.內(nèi)部已重寫了equals()、hashCode()等方法,遵守了HashMap內(nèi)部的規(guī)范
如果使用Object作為HashMap的Key,應(yīng)該怎么辦呢?
重寫hashCode()和equals()方法
HashMap為什么不直接使用hashCode()處理后的哈希值直接作為table的下標(biāo)?
hashCode()方法返回的是int整數(shù)類型,其范圍為-(2 ^ 31)~(2 ^ 31 - 1),約有40億個(gè)映射空間;哈希值可能不在數(shù)組大小范圍內(nèi),進(jìn)而無(wú)法匹配存儲(chǔ)位置
HashMap 的長(zhǎng)度為什么是2的冪次方
hash%length==hash&(length-1)的前提是 length 是2的 n 次方;
HashMap 與 HashTable 有什么區(qū)別?
1.線程安全 hashtable用synchronized修飾
2.效率 hashmap效率高
3.對(duì)null key的支持 hashmap可以 hashtable報(bào)錯(cuò)
4.Hashtable 默認(rèn)大小11,之后擴(kuò)充,容量為原來(lái)2n+1。HashMap 默認(rèn)大小16。擴(kuò)充,原來(lái)的2倍
如何決定使用 HashMap 還是 TreeMap?
對(duì)于在Map中插入、刪除和定位元素,HashMap最好。然而,對(duì)一個(gè)有序的key集合進(jìn)行遍歷,TreeMap更好
HashMap 和 ConcurrentHashMap 的區(qū)別
1.JDK1.8之后ConcurrentHashMap啟用了一種全新的方式實(shí)現(xiàn),利用CAS算法。
2.hashmap允許null
ConcurrentHashMap 和 Hashtable 的區(qū)別?
1.底層數(shù)據(jù)結(jié)構(gòu),ConcurrentHashMap:數(shù)組+鏈表/紅黑二叉樹;Hashtable:數(shù)組+鏈表
2.實(shí)現(xiàn)線程安全的方式(重要):① 在JDK1.7的時(shí)候,ConcurrentHashMap(分段鎖) 對(duì)整個(gè)桶數(shù)組進(jìn)行了分割分段(Segment),每一把鎖只鎖容器其中一部分?jǐn)?shù)據(jù),多線程訪問(wèn)容器里不同數(shù)據(jù)段的數(shù)據(jù),就不會(huì)存在鎖競(jìng)爭(zhēng),提高并發(fā)訪問(wèn)率。(默認(rèn)分配16個(gè)Segment,比Hashtable效率提高16倍。) 到了 JDK1.8 的時(shí)候已經(jīng)摒棄了Segment的概念,而是直接用 Node 數(shù)組+鏈表+紅黑樹的數(shù)據(jù)結(jié)構(gòu)來(lái)實(shí)現(xiàn),并發(fā)控制使用 synchronized 和 CAS 來(lái)操作。(JDK1.6以后 對(duì) synchronized鎖做了很多優(yōu)化) 整個(gè)看起來(lái)就像是優(yōu)化過(guò)且線程安全的 HashMap,雖然在JDK1.8中還能看到 Segment 的數(shù)據(jù)結(jié)構(gòu),但是已經(jīng)簡(jiǎn)化了屬性,只是為了兼容舊版本;② Hashtable(同一把鎖) :使用 synchronized 來(lái)保證線程安全,效率非常低下。當(dāng)一個(gè)線程訪問(wèn)同步方法時(shí),其他線程也訪問(wèn)同步方法,可能會(huì)進(jìn)入阻塞或輪詢狀態(tài),如使用 put 添加元素,另一個(gè)線程不能使用 put 添加元素,也不能使用 get,競(jìng)爭(zhēng)會(huì)越來(lái)越激烈效率越低。
ConcurrentHashMap 底層具體實(shí)現(xiàn)知道嗎?實(shí)現(xiàn)原理是什么?
JDK1.7: ConcurrentHashMap采用Segment + HashEntry的方式進(jìn)行實(shí)現(xiàn)
JDK1.8: synchronized只鎖定當(dāng)前鏈表或紅黑二叉樹的首節(jié)點(diǎn)
Array 和 ArrayList 有何區(qū)別?
Array 存儲(chǔ)基本數(shù)據(jù)類型和對(duì)象,ArrayList 只能存儲(chǔ)對(duì)象。Array 是指定固定大小的,而 ArrayList 大小是自動(dòng)擴(kuò)展的。Array 內(nèi)置方法沒(méi)有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。
如何實(shí)現(xiàn) Array 和 List 之間的轉(zhuǎn)換?
- Array 轉(zhuǎn) List: Arrays. asList(array) ;
- List 轉(zhuǎn) Array:List 的 toArray() 方法。
comparable 和 comparator的區(qū)別?
- comparable接口實(shí)際上是出自java.lang包,它有一個(gè) compareTo(Object obj)方法用來(lái)排序
- comparator接口實(shí)際上是出自 java.util 包,它有一個(gè)compare(Object obj1, Object obj2)方法用來(lái)排序
Collection 和 Collections 有什么區(qū)別?
- java.util.Collection 是一個(gè)集合接口(集合類的一個(gè)頂級(jí)接口)。它提供了對(duì)集合對(duì)象進(jìn)行基本操作的通用接口方法。Collection接口在Java 類庫(kù)中有很多具體的實(shí)現(xiàn)。Collection接口的意義是為各種具體的集合提供了最大化的統(tǒng)一操作方式,其直接繼承接口有List與Set。
- Collections則是集合類的一個(gè)工具類/幫助類,其中提供了一系列靜態(tài)方法,用于對(duì)集合中元素進(jìn)行排序、搜索以及線程安全等各種操作。
TreeMap 和 TreeSet 在排序時(shí)如何比較元素?Collections 工具類中的 sort()方法如何比較元素?
第一種要求傳入的待排序容器中存放的對(duì)象比較實(shí)現(xiàn) Comparable 接口以實(shí)現(xiàn)元素的比較;
第二種不強(qiáng)制性的要求容器中的元素必須可比較,但是要求傳入第二個(gè)參數(shù),參數(shù)是Comparator 接口的子類型(需要重寫 compare 方法實(shí)現(xiàn)元素的比較),相當(dāng)于一個(gè)臨時(shí)定義的排序規(guī)則,其實(shí)就是通過(guò)接口注入比較元素大小的算法,也是對(duì)回調(diào)模式的應(yīng)用(Java 中對(duì)函數(shù)式編程的支持)。
面試造火箭,工作擰螺絲,希望對(duì)你有所幫助
多多分享、點(diǎn)贊、評(píng)論、收藏、謝謝大家,讓更多人受益!!!
總結(jié)
以上是生活随笔為你收集整理的java arraylist排序_最全Java集合笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 铂金钻戒多少钱啊?
- 下一篇: java try catch_Java捕