傳統的容器(數組)在進行增、刪等破壞性操做時,須要移動元素,可能致使性能問題;同時添加、刪除等算法和具體業務耦合在一塊兒,增長了程序開發的複雜度。java
Java集合框架提供了一套性能優良、使用方便的接口和類,它們位於java.util包中c++
Collection是java集合框架(collection-frame)中的頂層接口。程序員
Collection接口表示一個容器,容器中只能存儲引用數據類型,建議存同一類型的引用類型,方便後續遍歷等操做。算法
容器中的元素能夠是有序的、可重複的,稱爲List接口數組
也多是無序的、惟一的,稱爲Set接口。安全
public static void main(String[] args) {數據結構
/**併發 * 增:add/addAllapp * 刪:clear/remove/removeAll/retainAll框架 * 改: * 查:contains/containsAll/isEmpty/size */
Collection c1 = new ArrayList();
// 追加 c1.add("apple"); // Object object = new String("apple"); // c1.add(1); // Object object = new Integer(1); c1.add("banana"); System.out.println(c1);
// 追加一個集合 Collection c2 = new ArrayList(); c2.add("java"); c2.add("c++"); c1.addAll(c2); System.out.println(c1);
// clear //c1.clear();
// c1.remove("apple"); // c1.removeAll(c2); //c1.retainAll(c2); //System.out.println(c1);
System.out.println(c1.contains("apple")); c2.add("js"); System.out.println(c1.containsAll(c2)); // c1.clear(); System.out.println(c1.isEmpty()); // 返回集合元素的個數 System.out.println(c1.size());
System.out.println(c1.equals(c2));
} |
Iterable 可遍歷的接口,集合接口繼承於它,集合支持快速遍歷。
// 快速遍歷 // for-each // Object 表示元素類型 // item表示迭代變量 // c1表示集合 for (Object item : c1) { System.out.println(item.toString()); } |
快速遍歷的本質
Collection繼承Iterable接口,表示集合支持快速遍歷。Iterable接口定義了一個方法iterator()用於獲取集合的迭代器,是一個Iterator接口類型,iterator()內部返回一個實現類實現類Iterator接口。這個實現類必定具備hasNext和next方法用於判斷是否有下一個元素和獲取下一個元素。快速遍歷就是基於迭代器工做的。
public static void main(String[] args) {
Collection c1 = new ArrayList(); c1.add("apple"); c1.add("banana"); c1.add("coco");
// 快速遍歷 // for-each // Object 表示元素類型 // item表示迭代變量 // c1表示集合 for (Object item : c1) { System.out.println(item.toString()); }
// 迭代器遍歷(國內) Iterator it = c1.iterator(); while(it.hasNext()) { Object item = it.next(); System.out.println(item.toString()); }
// 國外 for(Iterator it2=c1.iterator();it2.hasNext();) { Object item = it2.next(); System.out.println(item.toString()); } } |
List 接口中的元素時有序的、可重複的。List接口中的元素經過索引(index)來肯定元素的順序。
有序的 collection(也稱爲序列)。能夠對列表中每一個元素的插入位置進行精確地控制。用戶能夠根據元素的整數索引(在列表中的位置)訪問元素,並搜索列表中的元素
public static void main(String[] args) {
/** * 增:add/addAll/add(index,el)/addAll(index,collection) * 刪:clear/remove/removeAll/remove(index) * 改:set(index,el) * 查:get(index)/indexOf/lastIndexOf() * 其餘:contains/containsAll/isEmpty/size */ List list1 = new ArrayList(); // 添加元素 list1.add("apple"); list1.add("banana"); // 在指定位置添加元素 list1.add(0, "coco");
System.out.println(list1);
List list2 = new ArrayList(); list2.add("java"); list2.add("c++");
list1.addAll(1, list2); System.out.println(list1);
// 刪除 list1.remove(0); System.out.println(list1);
// 修改 list1.set(0, "javax"); System.out.println(list1);
// 查 System.out.println(list1.get(0)); list1.add("apple"); list1.add("apple"); System.out.println(list1); System.out.println(list1.indexOf("apple")); System.out.println(list1.lastIndexOf("apple")); } |
ListIterator 繼承於Iterator,在Iterator的基礎上提供了以正向遍歷集合,也能夠以逆序遍歷集合。
hasNext/next 以正向遍歷
hasPrevious/previous 以逆序遍歷
public static void main(String[] args) {
List list1 = new ArrayList(); list1.add("apple"); list1.add("banana"); list1.add("coco");
// 【1】快速遍歷 System.out.println("--for each--"); for (Object item : list1) { System.out.println(item.toString()); }
// 【2】普通for System.out.println("--for--"); for(int i=0;i<list1.size();i++) { System.out.println(list1.get(i)); }
// 【3】集合迭代器 System.out.println("--iterator--"); Iterator it = list1.iterator(); while(it.hasNext()) { System.out.println(it.next()); }
System.out.println("--list iterator--"); // 正向遍歷 ListIterator it2 = list1.listIterator(); while(it2.hasNext()) { System.out.println(it2.next()); }
// 逆序遍歷 while(it2.hasPrevious()) { System.out.println(it2.previous()); }
System.out.println("--list iterator with index--"); ListIterator it3 = list1.listIterator(1); while(it3.hasNext()) { System.out.println(it3.next()); } } |
數據結構就是數據在內存中存儲結構。根據存儲的方式不一樣,分爲線性表、二叉樹、圖、棧、隊列等
線性表數據按照必定的邏輯順序存儲在內存中。線性表是有序的。線性表根據內存的物理結構分爲兩種:數組和鏈表
數組是一種邏輯上有序的線性表,物理上也連續。
鏈表是一種邏輯上有序的線性表,但物理上不連續。
數組和鏈表的區別
相同點
不一樣點
數組在查詢時效率高,在添加、刪除元素時效率低(涉及移動元素)
鏈表在查詢時效率低(每次從頭開始,不能跳躍訪問),在添加、刪除元素時效率高(不涉及移動元素)
特性:先進後出,後進先出
特性:先進先出
ArrayList 是List接口的實現類,底層數據結構是數組,實現大小可變的數組。
ArrayList 線程不安全,jdk1.2
ArrayList 底層數據結構是數組,默認數組大小是10,若是添加的元素個數超過默認容量,ArrayList會自動拓容,拓容原則:newCapacity = oldCapacity + oldCapacity / 2;
若是將來肯定序列的元素不在增長,經過調用trimToSize()調製容量至合適的空間。
ArrayList做爲List接口的實現類,經常使用方法和遍歷方法參考List接口。
Vector 是List接口的實現類,底層數據結構也是數組,也是大小可變的數組。
Vector是線程安全的,jdk1.0
Vector底層數據結構是數組,默認數組大小是10,若是添加的元素個數超過默認容量,Vector會自動拓容,拓容原則:newCapacity = oldCapacity +capacityIncrement(增加因子);若是將來肯定序列的元素不在增長,經過調用trimToSize()調製容量至合適的空間。
注意:Vector 在實現List接口的同時,同添加了自身特有的方法xxxElement,將來使用時爲了程序的可拓展性,必定要按照接口來操做Vector。
LinkedList是List接口的實現類,底層數據結構是鏈表。
LinekList經常使用方法和遍歷方法參照List接口。
LinkedList 線程不安全。
除了實現List接口, 還實現棧接口
|
push入棧操做 / pop出棧操做
public class Test01 { public static void main(String[] args) { LinkedList list = new LinkedList(); list.push("apple"); list.push("banana"); list.push("coco");
System.out.println(list.pop()); System.out.println(list.pop()); System.out.println(list.pop());
// java.util.NoSuchElementException System.out.println(list.pop()); } } |
隊列(Queue)接口
add/remove/element() 可能會出現NoSuchElementException異常
public static void main(String[] args) {
LinkedList queue = new LinkedList(); // 入隊 /** * 隊列頭 隊列尾 *<----- <----- * [apple, banana, coco] */ queue.add("apple"); queue.add("banana"); queue.add("coco"); System.out.println(queue);
// 出隊 System.out.println(queue.remove()); System.out.println(queue.remove()); System.out.println(queue.remove()); System.out.println(queue);
// java.util.NoSuchElementException System.out.println(queue.remove());
// 獲取表頭元素 System.out.println(queue.element()); } |
offer/poll/peek 可能會返回特殊值(null)
public static void main(String[] args) {
LinkedList queue = new LinkedList(); // 入隊 /** * 隊列頭 隊列尾 *<----- <----- * [apple, banana, coco] */ queue.offer("apple"); queue.offer("banana"); queue.offer("coco");
// 出隊列 //System.out.println(queue.poll()); //System.out.println(queue.poll()); //System.out.println(queue.poll()); System.out.println(queue);
//System.out.println(queue.poll());
// 獲取表頭元素 System.out.println(queue.peek());
} |
雙向隊列(Deque)接口
/** * 以雙向隊列形式操做LinkedList */ public class Test04 { public static void main(String[] args) {
LinkedList queue = new LinkedList(); // 入隊 /** *<----- <----- * [apple, banana, coco] * ----> -----> */
queue.addFirst("apple"); queue.addFirst("banana"); queue.addFirst("coco"); System.out.println(queue);
System.out.println(queue.removeLast()); System.out.println(queue.removeFirst()); System.out.println(queue.removeFirst()); System.out.println(queue);
// 獲取頭元素 System.out.println(queue.getFirst());
} } |
Iterator在迭代過程當中不容許向集合中添加元素
public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("apple"); list.add("banana"); list.add("coco");
Iterator it = list.iterator(); while(it.hasNext()) { String item = (String) it.next(); if(item.equals("banana")) { list.add("test"); } }
System.out.println(list); } |
當經過Iterator集合迭代器遍歷集合過程當中,不能再向集合彙總添加元素,不然出現ConcurrentModificationException 併發修改異常。
ListIterator容許程序員按任一方向遍歷列表、迭代期間修改列表,並得到迭代器在列表中的當前位置
public class Test01 { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("apple"); list.add("banana"); list.add("coco");
ListIterator it = list.listIterator(); while(it.hasNext()) { String item = (String) it.next(); if(item.equals("banana")) { it.add("test"); } }
System.out.println(list); } } |
熟悉Iterator實現類的源碼hasNext/next
泛型容許開發者在強類型程序設計語言(java)編寫代碼時定義一些可變部分,這些部分在使用前必須做出指明。
泛型就是將類型參數化
ArrayList<E> list表示聲明瞭一個列表list,列表的元素是E類型 |
ArrayList<String> list = new ArrayList<String>(); 聲明瞭一個列表list,列表的元素只能是String類型。 |
泛型在編譯器起做用,運行時jvm察覺不到泛型的存在。
泛型在運行時已經被擦除了。
public static void main(String[] args) { ArrayList<String> list = new ArrayList<String>(); list.add("apple"); System.out.println(list instanceof ArrayList); System.out.println(list instanceof ArrayList<String>); } |
Cannot perform instanceof check against parameterized type ArrayList<String>. Use the form ArrayList<?> instead since further generic type information will be erased at runtime |
當一個類中屬性的數據類型不肯定時,具體是什麼類型由使用者來肯定時,使用泛型。泛型類的形式
public class 類名<T> {
} |
定義一個泛型類
public class FanClass<T> { private T t;
public T getT() { return t; }
public void setT(T t) { this.t = t; }
public FanClass(T t) { super(); this.t = t; }
public FanClass() { super(); } }
|
public class Test01 { public static void main(String[] args) { FanClass<String> fan = new FanClass<String>(); fan.setT("apple");
FanClass<Integer> fan2 = new FanClass<Integer>(); fan2.setT(1); } }
|
當一個方法的參數類型不肯定時,具體是什麼類型由使用者來肯定,能夠考慮使用泛型方法。形式:
public <T> void xxx(T a) { System.out.println(a); } |
public class Student {
/*public void showInfo(int a) { System.out.println(a); }
public void showInfo(float a) { System.out.println(a); }
public void showInfo(String a) { System.out.println(a); }*/
public <T> void showInfo(T a) { System.out.println(a); } }
|
public static void main(String[] args) {
Student stu = new Student(); stu.showInfo(1); stu.showInfo("apple"); stu.showInfo(1.0f); } |
泛型方法在調用時肯定(指明)類型。
泛型方法在必定程度上優化了方法重載。
泛型方法能夠定義多個泛型類型
// 能夠定義多個泛型的類型 public <A,B> void showInfo(A a,B b) { System.out.println(a); System.out.println(b); } |
多個泛型類型進一步優化了方法重載。
多個同類型的泛型
// 多個同類型的泛型 /*public <A> void print(A a) { System.out.println(a); } public <A> void print(A a,A b) { System.out.println(a); System.out.println(b); }*/
public <A> void print(A...a) { System.out.println(a); } |
A… a 表示方法能夠接受多個參數。當調用方法傳遞多個參數時,多個參數被放到a數組中,a是什麼類型的數組由開發者調用處傳參決定。
stu.print(1); stu.print(1,2);
stu.print("apple"); stu.print("apple","banana"); |
print(A...a) 方法稱爲可變參數的泛型形式。
若是接口中的方法的參數(形參、返回值)不肯定時,能夠考慮使用泛型接口。形式
public interface FanInterface<T> { public void showInfo(T t); } |
[1]實現類能肯定泛型接口的類型
public class ImplClass implements FanInterface<String>{
public void showInfo(String t) { // TODO Auto-generated method stub
} } |
[2]實現類不能肯定泛型接口的類型->繼續泛。
public class ImplClass2<T> implements FanInterface<T>{
public void showInfo(T t) {
} } |
public static void print(ArrayList<? extends Pet> list) { for (Pet pet : list) { pet.showInfo(); } } |
泛型的上限ArrayList(? extends Pet) list 聲明瞭一個容器,容器中的元素類型必定要繼承於Pet,咱們稱這種形式叫作泛型的上限。
泛型的下限ArrayList(? super Pet) list 聲明瞭一個容器,容器中的元素類型必定要是Pet的父類,咱們稱這個形式爲泛型的下限。
Set接口表示一個惟1、無序的容器(和添加順序無關)
public static void main(String[] args) { /** * 增:add/addAll * 刪:clear/remove/removeAll/retainAll * 改: * 查:contains/containsAll * 遍歷:iterator * 其餘:size/isEmpty */
Set<Integer> set = new HashSet<Integer>(); // [1]添加 // 無序 set.add(10); set.add(3); set.add(20); set.add(0); // 不能添加劇復元素 boolean r = set.add(1); System.out.println(set);
// 【2】刪除 // set.remove(1); // set.clear(); // System.out.println(set);
// 【3】查看是否包含 System.out.println(set.contains(1));
// 【4】其餘 System.out.println(set.size()); System.out.println(set.isEmpty()); } |
public static void main(String[] args) {
Set<String> set = new HashSet<String>(); set.add("banana"); set.add("apple"); set.add("coco");
// 快速遍歷 for (String item : set) { System.out.println(item); }
// 迭代器 Iterator<String> it = set.iterator(); while(it.hasNext()) { String item = it.next(); System.out.println(item); } } |
Set接口的實現類常見的有HashSet、LinkedHashSet、TreeSet
HashSet是Set接口的實現類,底層數據結構是哈希表。
HashSet是線程不安全的(不保證同步)
根據哈希表的工做原理,請存儲一個自定義對象到HashSet中。
package cn.sxt03.hashset;
public class Student { private String id; private String name; private int age;
// …
public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((id == null) ? 0 : id.hashCode()); result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; }
public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; }
public String toString() { return "Student [id=" + id + ", name=" + name + ", age=" + age + "]"; }
}
|
總結
[1]若是向HashSet中存儲元素時,元素必定要實現hashCode方法和equals方法。
[2] 優勢:添加、刪除、查詢效率高;缺點:無序
LinkedHashSet是Set接口的實現類,底層數據結構哈希表+鏈表
哈希表用於散列元素;鏈表用於維持添加順序。
若是要添加自定義對象元素,也須要重寫hashCode和equals方法。
TreeSet 是Set接口的實現類,底層數據結構是二叉樹。
TreeSet 存儲的數據按照必定的規則存儲。存儲規則讓數據表現出天然順序。
添加一個新元素t的存儲的步驟
[1] 若是集合無元素,t直接加入;若是集合有元素,t和根節點比較;
[2] 若是t小於根節點;把t放到根節點的左子樹上;重複1-3步驟
[3] t大於根節點;把t放到根節點的右子樹上;重複1-3步驟
輸出時按照必定的規則:左子樹->根節點->右子樹
根據TreeSet的工做原理,向TreeSet添加自定義元素?
向TreeSet中添加元素時,必定要提供比較策略,不然會出現ClassCastException。
比較策略分兩種:內部比較器和外部比較器
當一個自定義對象實現Comparable並實現compareTo方法時,經過指定具體的比較策略,此時稱爲內部比較器。
package cn.sxt05.treeset;
public class Student implements Comparable<Student>{ private String id; private String name; private int age;
// 。。。
@Override public String toString() { return "Student [id=" + id + ", name=" + name + ", age=" + age + "]"; }
@Override public int compareTo(Student o) { if(this.getAge()<o.getAge()) { return -1; }else if(this.getAge() == o.getAge()) { return 0; }else { return 1; } }
}
|
比較策略的幾種狀況
[1]比較策略通常當前對象寫在前面,待比較對象也在後面,比較結果默認升序
return this.getAge() - o.getAge() ; |
若是想要降序,改變兩個比較對象的位置便可。
[2] 多種比較因素
@Override public int compareTo(Student o) { /*if(this.getAge()<o.getAge()) { return -1; }else if(this.getAge() == o.getAge()) { return 0; }else { return 1; }*/
// return this.getAge() - o.getAge() ;
if(this.getAge()<o.getAge()) { return -1; }else if(this.getAge() == o.getAge()) { return this.getName().compareTo(o.getName()); }else { return 1; } } |
當實際開發過程當中不知道添加元素的源代碼、無權修改別人的代碼,此時能夠使用外部比較器。
Comparator 位於java.util包中,定義了compare(o1,o2) 用於提供外部比較策略。
TreeSet接受一個指定比較策略的構造方法,這些比較策略的實現類必須實現Comparator
接口。
需求:按照字符串的長度比較
public class Test01 { public static void main(String[] args) {
LenComparator lenComparator = new LenComparator(); TreeSet<String> set2 = new TreeSet<String>(lenComparator);
set2.add("banana"); set2.add("coco"); set2.add("apple");
set2.add("apple"); System.out.println(set2);
} }
class LenComparator implements Comparator<String>{
@Override public int compare(String o1, String o2) { return o1.length() - o2.length(); } } |
使用匿名內部類優化
public class Test02 { public static void main(String[] args) {
TreeSet<String> set2 = new TreeSet<String>(new Comparator<String>() {
@Override public int compare(String o1, String o2) { return o1.length() - o2.length(); }
});
set2.add("banana"); set2.add("coco"); set2.add("apple");
set2.add("apple"); System.out.println(set2);
} } |
Map接口稱爲鍵值對集合或者映射集合,其中的元素(entry)是以鍵值對(key-value)的形式存在。
Map 容器接口中提供了增、刪、改、查的方式對集合進行操做。
Map接口中都是經過key來操做鍵值對,通常key是已知。經過key獲取value。
public static void main(String[] args) {
/** * 增:put/putAll * 刪:clear/remove * 改:put * 查:get/containsKey/containsValue * 其餘:isEmpty/size */
Map<String, String> map = new HashMap<String,String>();
// 【1】put map.put("A", "apple"); map.put("B", "banana"); map.put("C", "coco");
// 【2】刪除 // map.clear(); // smap.remove("A");
// 【3】修改 //map.put("A", "apple x");
// 【4】查看 String val = map.get("A"); System.out.println(map.containsKey("D"));
System.out.println(map); } |
經過keySet() 返回map中鍵的set集合。
public static void main(String[] args) {
Map<String, String> map = new HashMap<String,String>();
map.put("B", "banana"); map.put("A", "apple"); map.put("C", "coco"); // map無序 // 能夠根據key的天然順序 讓map有序 => 通常用string做爲key System.out.println(map);
// 遍歷 Set<String> keys = map.keySet(); for (String key : keys) { System.out.println(key+"=>"+map.get(key)); }
Iterator<String> it = keys.iterator(); while(it.hasNext()) { String key = it.next(); System.out.println(key+"=>"+map.get(key)); } } |
map中以鍵值對做爲元素,鍵值對在map中稱爲entry,entrySet返回鍵值對的set集合。
public static void main(String[] args) {
Map<String, String> map = new HashMap<String,String>();
map.put("B", "banana"); map.put("A", "apple"); map.put("C", "coco"); // map無序 // 能夠根據key的天然順序 讓map有序 => 通常用string做爲key System.out.println(map);
// entrySet Set<Entry<String, String>> entrySet = map.entrySet(); for (Entry<String, String> entry : entrySet) { System.out.println(entry.getKey()+"=>"+entry.getValue()); }
Iterator<Entry<String, String>> it2 = entrySet.iterator(); while(it2.hasNext()) { Entry<String, String> entry = it2.next(); System.out.println(entry.getKey()+"=>"+entry.getValue()); } } |
Map接口的實現類HashMap、LinkedHashMap、TreeMap
HashMap 是Map的實現類,key以HashSet存儲。
public static void main(String[] args) {
/* HashMap<String, Object> map = new HashMap<String,Object>();
ArrayList<String> list1 = new ArrayList<String>(); list1.add("alex"); list1.add("alice"); list1.add("allen"); map.put("A", list1);
ArrayList<String> list2 = new ArrayList<String>(); list2.add("ben"); list2.add("bill"); map.put("B", list2);
System.out.println(map); */
HashMap<Student, Object> map = new HashMap<Student,Object>();
ArrayList<String> list1 = new ArrayList<String>(); list1.add("alex"); list1.add("alice"); list1.add("allen"); Student s1 = new Student("001", "大狗", 20); map.put(s1, list1);
ArrayList<String> list2 = new ArrayList<String>(); list2.add("ben"); list2.add("bill"); Student s2 = new Student("001", "大狗", 20); // 修改 map.put(s2, list2); System.out.println(map);
} |
總結:
[1] 向HashMap中存儲元素時,key必定要實現hashCode和equals
[2] 通常建議使用String做爲Map接口的key
LinkedHashMap是Map接口的實現類,key以LinkedHashSet存儲。
哈希表散列key,鏈表維持key的添加順序。
public static void main(String[] args) {
/*LinkedHashMap<String, Object> map = new LinkedHashMap<String,Object>();
ArrayList<String> list2 = new ArrayList<String>(); list2.add("ben"); list2.add("bill"); map.put("B", list2);
ArrayList<String> list1 = new ArrayList<String>(); list1.add("alex"); list1.add("alice"); list1.add("allen"); map.put("A", list1);
System.out.println(map);*/
HashMap<Student, Object> map = new HashMap<Student,Object>();
ArrayList<String> list1 = new ArrayList<String>(); list1.add("alex"); list1.add("alice"); list1.add("allen"); Student s1 = new Student("001", "大狗", 20); map.put(s1, list1);
ArrayList<String> list2 = new ArrayList<String>(); list2.add("ben"); list2.add("bill"); Student s2 = new Student("001", "大狗", 20); // 修改 map.put(s2, list2); System.out.println(map);
} |
TreeMap是Map的實現類,key以TreeSet存儲。
public static void main(String[] args) {
/*TreeMap<String, Object> map = new TreeMap<String,Object>(new Comparator<String>() {
@Override public int compare(String o1, String o2) { return o1.length() - o2.length(); } });
ArrayList<String> list2 = new ArrayList<String>(); list2.add("ben"); list2.add("bill"); map.put("Aa", list2);
ArrayList<String> list1 = new ArrayList<String>(); list1.add("alex"); list1.add("alice"); list1.add("allen"); map.put("B", list1);
System.out.println(map);*/
TreeMap<Student, Object> map = new TreeMap<Student,Object>(new Comparator<Student>() {
@Override public int compare(Student o1, Student o2) { return o1.getAge() - o2.getAge(); } });
ArrayList<String> list1 = new ArrayList<String>(); list1.add("alex"); list1.add("alice"); list1.add("allen"); Student s1 = new Student("001", "大狗", 20); map.put(s1, list1);
ArrayList<String> list2 = new ArrayList<String>(); list2.add("ben"); list2.add("bill"); Student s2 = new Student("001", "2狗", 20); // 修改 map.put(s2, list2); System.out.println(map);
} |
總結