声明:以下笔记来源于韩顺平视频https://www.bilibili.com/video/BV1fh411y7R8?p=1,笔记为楼主亲手劳动,劳动不易,转载请标明谢谢。
Collection
集合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n1bsaFQp-1648481078868)(D:\Typora Data\Img/image-20220306163403688.png)]
集合的好处与理解
- 数组
- 长度开始时必须指定,而且一旦指定, 不能更改
- 保存的必须为同一类型的元素
- 使用数组进行增加元素的示意代码-比较麻烦
- 集合
- 可以动态保存任意多个对象,使用比较方便!
- 提供了一系列方便的操作对象的方法: add、 remove、 set、 get等
- 使用集合添加,删除新元素的示意代码-简洁了
集合简介
- 集合主要是两组(单列集合,双列集合)
- ColLection接口有两个重要的子接口
List Set
,他们的实现 子类都是单列集合
Map
接口的实现子类是双列集合
,存放的K-V
Collection 接口实现类的特点
public interface Collection<E> extendsIterable<E>
collection实现子类可以存放多个元素,每个元素可以是Object
有些Collection的实现类,可以存放重复的元素,有些不可以
有些Collection的实现类,有些是有序的(List),有些不是有序(Set)
Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的
Collection接口和常用方法(ArrayList 子类实现)
add:添加单个元素
remove:删除指定元素
contains:查找元素是否存在
size:获取元素个数
isEmpty:判断是否为空
clear:清空
addAll:添加多个元素
containsAll:查找多个元素是否都存在
removeAll:删除多个元素
@SuppressWarnings("all") public class CollectionMethods_ { public static void main(String[] args) { List list = new ArrayList(); //添加单个元素 boolean flag = list.add("jack"); list.add(10); list.add(true); //删除指定元素 boolean flag1 = list.remove("jack"); list.remove(0); //查找元素是否存在 boolean flag3 = list.contains(10); //获取元素个数 System.out.println(list.size()); //判断是否为空 System.out.println(list.isEmpty()); //清空 list.clear();//void List list1 = new ArrayList(); list1.add("老韩"); list1.add("狂神"); list1.add("字节跳动"); //添加多个元素 list.addAll(list1); System.out.println(list); //查找多个元素是否都存在 boolean flag4 = list.containsAll(list1); //删除多个元素 boolean flag5 = list.removeAll(list1); } }
Collection接口遍历元素方式
Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。
所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。
迭代器的执行原理
Iterator iterator = coll.iterator(); //得到一个集合的迭代器
//hasNext():判断是否还有下一个元素
while(iterator.hasNext(){
//next()作用:1.下移2.将下移以后集合位置上的元素返回
System. out.println(iterator.next();}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XW7FMY06-1648481078873)(D:\Typora Data\Img/image-20220308173705958.png)]
Iterator仅用于遍历集合,Iterator 本身并不存放对象。
注意:在调用it.next(方法之前必须要调用it.hasNext()进行检测。若不调用,且下一条记录无效,直接调用it.next()会抛出NoSuchElementException。
public class CollectionIteration { public static void main(String[] args) { Collection col = new ArrayList(); col.add(new BooK("三国演义","罗贯中",10.1)); col.add(new BooK("小李飞刀","古龙",5.1)); col.add(new BooK("红楼梦","曹雪芹",34.6)); Iterator iterator = col.iterator();//绘制迭代器 for (Object book : col) {//增强for遍历 System.out.println(book); } while (iterator.hasNext()) {//迭代遍历 Object obj = iterator.next(); System.out.println(obj); } iterator = col.iterator();//重置迭代器指针(游标) } } class BooK{ private String name; private String author; private double price; public BooK(String name, String author, double price) { this.name = name; this.author = author; this.price = price; } @Override public String toString() { return "BooK{" + "name='" + name + '\'' + ", author='" + author + '\'' + ", price=" + price + '}'; } }
增强for遍历
- 增强for底层仍然是Iterator
快捷键 I (在Idea中)
@SuppressWarnings({"all"}) public class CollectionFor_ { public static void main(String[] args) { Collection col = new ArrayList(); col.add(new BooK("三国演义","罗贯中",10.1)); col.add(new BooK("小李飞刀","古龙",5.1)); col.add(new BooK("红楼梦","曹雪芹",34.6)); for (Object book : col) { System.out.println("book=" + book); } } }
List
List 接口的基本介绍
- List 接口是Collection接口的子接口
- List集合类中元素
有序(即添加顺序和取出顺序一致)、 且可重复
- List集合中的每个元素都有其对应的顺序索引,即
支持索引
。- JDK API中List接口的实现类有很多,但常用的有
ArrayList,LinkedList,Vector
List 接口常用的方法
void add(int index, Object ele):在index位置插入ele元素
boolean addAl(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
Object get(int index):获取指定index位置的元素
int indexOf(Object obj):返回obj在集合中首次出现的位置
int lastlndexOf(object obj):返回obj在当前集合中末次出现的位置
Object remove(int index):移除指定index位置的元素,并返回此元素
Object set(int index, Object ele):设置指定index位置的元素为ele ,相当于是替换.
List subList(int fromIndex, int tolndex): 返回从fromIndex到tolndex位置的子集合
@SuppressWarnings({"all"}) public class ListMethods_ { public static void main(String[] args) { List list = new ArrayList(); list.add("张三丰"); list.add("贾宝玉"); //void add(int index, Object ele):在index位置插入ele元素 list.add(1,"老天师"); List list1 = new ArrayList(); list1.add("jack"); list1.add("tom"); //boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来 list.addAll(1,list1); //Object get(int index):获取指定index位置的元素 System.out.println(list.get(2)); //int indexOf(Object obj):返回obj在集合中首次出现的位置 System.out.println(list.indexOf("tom")); list.add("老天师"); //int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置 System.out.println(list.lastIndexOf("老天师")); //Object remove(int index):移除指定index位置的元素,并返回此元素 list.remove(0); //1. Object set(int index, Object ele):设置指定index位置的元素为ele ,相当于是替换. list.set(1,"玛丽"); //List subList(int fromIndex, int tolndex):返回从fromIndex到tolndex位置的子集合 List list2 = list.subList(1, 3);//[ , ) } }
List 三种遍历方式 (Iterator 增强for 普通for)
@SuppressWarnings({"all"}) public class ListFor { public static void main(String[] args) { List list = new ArrayList(); // 向上转型的好处 // List list = new Vector(); // List list = new LinkedList(); list.add("jack"); list.add("Tom"); list.add("鱼香肉丝"); list.add("北京烤鸭子"); System.out.println("===迭代器遍历list==="); Iterator iterator = list.iterator(); while (iterator.hasNext()) { Object next = iterator.next(); System.out.println(next); } System.out.println("===增强for遍历list==="); for (Object o :list) { System.out.println("obj =" + o); } System.out.println("===普通for遍历list==="); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } } }
ArrayList
ArrayList注意事项
- permits all elements, including null , ArrayList可以加入null,并且多个
- ArrayList是由
数组来实现数据存储
的- ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高)看源码.
- 在多线程情况下,不建议使用ArrayList
ArrayList源码分析结论
- ArrayList中维护了一一个Object类型的数组elementData.
- transient Object[] elementData; //transient表示瞬间,短暂的,表示该属性不会被序列化
- 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,
第1次添加,则扩容elementData为10
,如需要再次扩容,则扩容elementData为1.5倍
。
如果使用的是指定大小的构造器,则初始elementData容量为指定大小, 如果需要扩容,
则直接扩容elementData为1.5倍。
ArrayList .add()方法底层扩容步骤
创建一个空的elementData数组 = {}
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; }
执行list.add()
- 先确定是否扩容
- 然后执行赋值
- ensureCapacityInternal方法中如果第一次就找最小容量minCapacity10,不是则扩容。
- modCount++记录集合被修改的次数,如果elementData的大小不够,就调用grow()去扩容
- 在grow()中真的扩容
- 使用扩容机制来确定要扩容到多大
- 第一 次newCapacity =10
- 第次及其以后,按照1.5倍扩容
- 扩容使用的是:Arrays.copyOf()
- 特别说明的是
不同的jdk版本方法体有所修改
注意事项
- 注意,注意,注意,Idea默认情况下,Debug显示的数据是简化后的,如果希望看到完整的数据需要做设置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Ig3kotz-1648481078875)(D:\Typora Data\Img/image-20220310092912059.png)]
- 还有就是要自己去动手,看着会了,脑子一下记住,但很快就会忘,多动手,多回顾,东西才是自己的!!!
Vector
Vector的基本介绍
Vector底层也是一 个
对象数组
,protected Object[] elementData;
Vector是线程同步的
,即线程安全,Vector类的操作方法带有synchronizedpublic synchronized E get(int index) { if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index); return elementData(index); }
在开发中,
需要线程同步安全时,考虑使用Vector
.结构
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {}
Vector 和 ArrayList的比较
底层结构 版本 线程安全,同步效率 扩容倍数 ArrayList 可变数组 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; jdk1.2 不安全,效率高 如果有参构造1.5倍如果是无参
1.第一 次10
2.从第二次开始安1.5扩容Vector 可变数组 protected Object[] elementData; jdk1.0 安全,效率不高 如果是无参,默认10
满后,就按2倍扩容
如果指定大小,则每次直
接按2倍扩容
//测试代码 debug使用 @SuppressWarnings({"All"}) public class Vector_ { public static void main(String[] args) { Vector vector = new Vector(); // Vector vector = new Vector(8); for (int i = 0; i < 10; i++) { vector.add(i); } vector.add(100); System.out.println("vector =" + vector); } }
LinkedList
linkedList 的全面说明
- LinkedList
实现了双向链表和双端队列
特点可以添加任意元素(元素可以重复),包括null
线程不安全
,没有实现同步.- LinkedList
底层维护了一个双向链表
.- LinkedList中维护了两个属性
first和last分别指向首节点和尾节点
- 每个
节点(Node对象) ,里面又维护了prev、next. item三个属性
,其中通过prev指向前一个,通过next指向后一个节点。 最终实现双向链表.- 所以
LinkedList的元素的添加和删除
,不是通过数组完成的,相对来说效率较高
。
双向链表模拟
@SuppressWarnings({"all"}) public class LinkedList01 { public static void main(String[] args) { Node jack = new Node("jack"); Node tom = new Node("tom"); Node shruad = new Node("shruad"); jack.next = tom; tom.next = shruad; shruad.pre = tom; tom.pre = jack; Node first = jack; Node last = shruad; while (true) { if (first == null) { break; } System.out.println(first); first = first.next; } Node swith = new Node("swith"); tom.next = swith; swith.next = shruad; shruad.pre = swith; swith.pre = tom; System.out.println("====分界===="); while (true) { if (last == null) { break; } System.out.println(last); last = last.pre; } } } class Node { public Object item; public Node next; public Node pre; public Node(Object item) { this.item = item; } @Override public String toString() { return "Node name=" + item; } }
linkedList 的 CRUD
@SuppressWarnings({"all"}) public class LinkedListCRUD { public static void main(String[] args) { LinkedList linkedList = new LinkedList(); //默认添加到尾部 linkedList.add(1); linkedList.add(2); linkedList.add(3); //默认删除第一个 linkedList.remove(); for (Object o :linkedList) { System.out.println(o); } System.out.println(linkedList.get(0));//查 linkedList.set(1,999);//改 Iterator iterator = linkedList.iterator(); while (iterator.hasNext()) {//迭代器遍历 Object obj = iterator.next(); System.out.println(obj); } for (Object o :linkedList) {//增强for遍历 System.out.println(o); } for (int i = 0; i < linkedList.size(); i++) {//普通for遍历 System.out.println(linkedList.get(i)); } } }
ArrayList 和 LinkedList 的比较
底层结构 增删的效率 查改的效率 ArrayList 可变数组 较低
数组扩容较高 LinkedList 双向链表 较高
通过链表追加较低 对于选择ArrayList 和 LinkedList 方面:
- 如果我们
改查
的操作多,选择ArrayList
- 如果我们
增删
的操作多,选择LinkedList
- 一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList
- 在个项目中, 根据业务灵活选择,也可能这样,-个模块使用的是ArrayList,另外一个模块是LinkedList,也就是说,要根据业务来进行选择
Set
Set 接口的基本介绍
- 无序(添加和取出的顺序不一-致),没有索引,(
不能使用索引的方式进行迭代
)- 不允许重复元素,所以最多包含一个null
- JDK API中Set接口的实现类有: HashSet,TreeSet
HashSet
HashSet 全面说明
HashSet实现了
Set接口
HashSet实际上是HashMap
public HashSet() { map = new HashMap<>(); }
HashSet底层是HashMap,HashMap底层是(数组+ 链表 + 红黑树)
HashSet 底层添加元素分析(hash() + equals())
- HashSet底层是HashMap
- 添加一个元素时,先得到hash值-会转成->索引值
- 找到存储数据表table ,看这个索引位置是否已经存放的有元素
- 如果没有,直接加入
- 如果有,调用equals比较,如果
相同
,就放弃添加
,如果不相同,则添加到最后- 在Java8中,如果一条链表的元素个数超过TREEIFY_THRESHOLD(默认是8),并且table的大小 >=MIN__TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)
- size++ 不只是table表的第一个,只要增加一个对象就会增加。
- TREEIFY_THRESHOLD 加到8时,但MIN__TREEIFY_CAPACITY没到64之前,还是会加到对应链表的后面,不会在另一条链表加,因为hash值对应的是那个table[i]的位置
HashSet 练习题
创建3个Employee对象放入HashSet中
当name和age的值相同时,认为是相同员工,不能添加到HashSet集合中
public class HashSetExercise_ { public static void main(String[] args) { HashSet hashSet = new HashSet(); hashSet.add(new Employee("milan",18)); hashSet.add(new Employee("smith",28)); hashSet.add(new Employee("milan",18)); System.out.println("hashSet = " + hashSet); } } class Employee { private String name; private int age; public Employee(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Employee employee = (Employee) o; return age == employee.age && Objects.equals(name, employee.name); } @Override public int hashCode() { return Objects.hash(name, age); } @Override public String toString() { return "Employee{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
LinkedHashSet
LinkedHashSet (父类是HashSet)
- 在LinkedHastSet中维护了一个
hash表和双向链表
( LinkedHashSet有head和tail )- 每一个节点有 before 和after属性,这样可以形成双向链表
- 在添加一个元素时,
先求hash值,在求索引
.确定该元素在hashtable的位置,然后将添加的元素加入到双向链表(如果已经存在,不添加[原则和hashset-样])- 这样的话,我们遍历LinkedHashSet也能确保插入顺序和遍历顺序一致
Map
Map接口说明
Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value
Map中的key和value 可以是任何引用类型的数据,会封装到HashMap$Node对象中
Map中的key
不允许重复
,原因和HashSet -一样,前面分析过源码.Map中的value可以重复
Map的key可以为null, value也可以为null,注意key为null,只能有一个,value为null ,可以多个.
常用String类作为Map的key
key和value之间存在单向一对一关系,即通过指定的key总能找到对应的value
Map存放数据的key-value,一对k-v是放在一个Node中的,有因为
Node实现了Entry 接口
,有些书上也说一-对k-v就是-个Entry(Map.Entry>>Node)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8JKLvI38-1648481078878)(D:\Typora Data\Img\image-20220306172147294.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EkoaBtch-1648481078878)(D:\Typora Data\Img\image-20220306163452566.png)]
Map接口常用方法
- put:添加
- remove:根据键删除映射关系
- get:根据键获取值
- size:获取元素个数
- isEmpty:判断个数是否为0
- clear:清除
- containsKey:查找键是否存在
Map遍历
- containsKey:查找键是否存在
- keySet:获取所有的键
- entrySet:获取所有关系k-v
- values:获取所有的值
@SuppressWarnings({"all"}) public class MapFor_ { public static void main(String[] args) { //Map 的六大遍历方式 HashMap map = new HashMap(); map.put("邓超","孙俪"); map.put("王宝强","马蓉"); map.put("宋喆","马蓉"); map.put("刘令博",null); map.put(null,"刘亦菲"); map. put("鹿晗","关晓彤"); //第一种 KeySet Set keySet = map.keySet(); System.out.println("======第一种方式增强for map.keySet()======"); for (Object key :keySet) { System.out.println(key + "=" + map.get(key)); } System.out.println("======第二种方式增强迭代器 map.keySet()======"); Iterator iterator = keySet.iterator(); while (iterator.hasNext()) { Object key = iterator.next(); System.out.println(key + "=" + map.get(key)); } //第二种 values Collection values = map.values(); System.out.println("======第一种方式增强for map.values()======"); for (Object value :values) { System.out.println(value); } System.out.println("======第二种方式增强迭代器 map.values()======"); Iterator iterator1 = values.iterator(); while (iterator1.hasNext()) { Object value = iterator1.next(); System.out.println(value); } //第三种 EntrySet Set entrySet = map.entrySet(); //EntrySet<entry<k,v>> System.out.println("======第一种方式增强for entrySet======"); for (Object entry :entrySet) { Map.Entry m = (Map.Entry) entry; System.out.println(m.getKey() + " = " + m.getValue()); } System.out.println("======第二种方式增强迭代器 entrySet======"); Iterator iterator2 = entrySet.iterator(); while (iterator2.hasNext()) { Object entry = iterator2.next(); Map.Entry m = (Map.Entry) entry; System.out.println(m.getKey() + " = " + m.getValue()); } } }
HashMap
HashMap底层机制
HashMap底层维护了Node类型的数组table,默认为null
当创建对象时,将加载因子(loadfactor)初始化为0.75.
当添加key-val时,通过key的哈希值得到在table的索引。然后判断该索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的key和准备加入的key相是否等,如果相等,则直接替换val;如果不相等,需要判断是树结构还是链表结构,做出相应处理。如果添加时发现容量不够,则需要扩容。
第1次添加,则需要扩容table容量为16,临界值(threshold)为12 (16*0.75)
以后再扩容,则需要扩容table容量为原来的2倍(32),临界值为原来的2倍,即24,依次类推.
在Java8中,如果-条链表的元素个数超过 TREEIFY THRESHOLD(默认是8),并且table的大小>= MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树).
HashMap是Map接口使用频率最高的实现类。
如果添加相同的key ,则会覆盖原来的key-val ,等同于修改.(key不会替换,val会替换)
与HashSet-样,
不保证映射的顺序
,因为底层是以hash表的方式来存储的.HashMap没有实现同步,因此是
线程不安全的
HashTable
HashTable 基本介绍。
- 存放的元素是键值对:即K-V
- hashtable的
键和值都不能为null
- hashTable使用方法基本上和HashMap-样
hashTable是线程安全
的,hashMap 是线程不安全
的- 底层有数组 HashtabLe E n t r y [ ] ( H a s h t a b L e Entry[ ] (HashtabLe Entry[](HashtabLeEntry 类似 HashtabLe$Node)
初始化大小为11
- 临界值threshold 8 = 11 * 0.75
- 扩容:按照自己的扩容机制来进行即可.
HashMap 与 HashTable 对比
版本 线程安全(同步synchronized) 效率 允许null键null值 HashMap 1.2 不安全 高 允许 HashTable 1.0 安全 较低 不允许
Properties
Properties 介绍
Properties类继承自
Hashtable
类并且实现了Map接口,也是使用一种键值对的形式来保存数据。他的使用特点和 HashTable 类似
Properties还可以用于从xxx.properties文件中,加载数据到Properties类对象,并进行读取和修改
说明:工作后xx.properties 文件通常作为配置文件。
public class Properties02 { public static void main(String[] args) throws IOException { Properties properties = new Properties(); //我在这边的根目录读取不到,只能用绝对路径 properties.load(new FileReader("C:\\Users\\86152\\IdeaProjects\\kuangshen-study\\baseLearn\\src\\mysql.properties")); //把 K-V 显示在控制台 properties.list(System.out); String user = properties.getProperty("user"); String pwd = properties.getProperty("pwd"); System.out.println("user=" + user); System.out.println("pwd=" + pwd); } }
public class Properties03 { public static void main(String[] args) throws IOException { Properties properties = new Properties(); properties.setProperty("charset","utf8"); properties.setProperty("user","汤姆"); properties.setProperty("pwd","abc111"); properties.store(new FileOutputStream("C:\\Users\\86152\\IdeaProjects\\kuangshen-study\\baseLearn\\src\\mysql2.properties"),null); // properties.store(new FileOutputStream("/mysql.properties"),null); System.out.println("配置文件保存成功"); } }
总结
开发中如何选择集合实现类
- 先判断存储的类型(一组对象[单列]或-组键值对[双列])
- 一组对象[单列]: Collection接口
- 允许重复: List
- 增删多: LinkedList [底层维护了一个双向链表,
链表易增删
]- 改查多:ArrayList [底层维护Object类型的可变数组,
下标易定位
]- 不允许重复: Set
- 无序: HashSet [底层是HashMap,维护了个哈希表 即(数组+链表+红黑树)]
- 排序: TreeSet
- 插入和取出顺序一致: LinkedHashSet , 维护数组+双向链表
- 一组键值对[双列]: Map
- 键无序: HashMap [底层是:哈希表jdk7: 数组+链表,jdk8:数组+链表+红黑树]
- 键排序: TreeMap
- 键插入和取出顺序一致: LinkedHashMap
- 读取文件Properties
TreeSet 简述
- 底层是TreeMap
- 当我们使用无参构造器,创建TreeSet时, 仍然是无序的
- 使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类)并指定排序规则
//可以直接debug看源码 @SuppressWarnings({"all"}) public class TreeSet_ { public static void main(String[] args) { // TreeSet treeSet = new TreeSet(); TreeSet treeSet = new TreeSet(new Comparator() { @Override public int compare(Object o1, Object o2) { // return ((String)o1).compareTo((String)o2);//按照字符大小进行排序 return ((String)o1).length() - ((String)o2).length(); } }); treeSet.add("jack"); treeSet.add("tom"); treeSet.add("sp"); treeSet.add("a"); System.out.println(treeSet); } }
TreeMap 简述
- 构造器。把传入的实现了Comparator接 口的匿名内部类(对象),传给给TreeMap的comparator
- 调用put方法
- 第一次添加,把k-v 封装到Entry对象,放入root
- 调用compare
//可以直接debug看源码 @SuppressWarnings({"all"}) public class TreeMap_ { public static void main(String[] args) { TreeMap treeMap = new TreeMap(new Comparator() {//比较器排序 @Override public int compare(Object o1, Object o2) { return ((String)o1).compareTo((String) o2); // return ((String)o1).length() - ((String)o2).length(); } }); // TreeMap treeMap = new TreeMap(); treeMap.put("jack","杰克"); treeMap.put("Tom","汤姆"); treeMap.put("kristina","克斯替诺"); treeMap.put("smith","史密斯"); System.out.println(treeMap); } }