Java集合框架总结
- 格式:doc
- 大小:39.50 KB
- 文档页数:7
java中集合的概念Java中的集合是一种非常重要的数据结构,用于存储和操作一组对象。
集合框架包含了许多类和接口,可以方便地进行数据的存储、查询、排序等操作,使得Java程序开发变得更加高效和便捷。
在本文中,我们将逐步介绍Java中集合的概念和用法。
一、集合框架概述Java中的集合框架是一个包含了多个接口和类的层次结构,用于表示和操作一组对象。
集合框架包含了通用的集合接口和实现,以及特定的集合类和接口,如List、Set、Map等。
集合框架的接口和类都是通过泛型实现的,可以存储任意类型的对象,比如基本类型和自定义类型的对象。
二、集合框架的接口Java中的集合框架包含了多个接口,其中包括:1. Collection:代表一组对象的集合,是其他集合接口的父接口。
它定义了一些通用的方法,如添加、删除、迭代等。
2. List:代表有序的集合,其中每个元素都有一个对应的索引。
List允许重复元素出现,并且可以通过索引访问、添加、删除元素。
3. Set:代表无序的集合,其中每个元素都是唯一的。
Set不允许重复的元素出现,可以用来去重。
4. Map:代表一组键值对的集合,其中每个键都是唯一的。
Map 允许多个值对应同一个键,可以用来快速查找和存储数据。
三、集合类的实现Java中的集合类可以通过实现集合接口来实现。
如ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等都是集合类的实现,我们可以通过这些集合类来方便地实现对一组对象的操作。
例如:1. 使用ArrayList来实现List接口,可以进行元素的添加、删除、查询等操作:List<String> list = new ArrayList<>();list.add("Alice");list.add("Bob");System.out.println(list.get(1));2. 使用HashSet来实现Set接口,可以去重并存储元素:Set<Integer> set = new HashSet<>();set.add(1);set.add(2);set.add(2);System.out.println(set.size());3. 使用HashMap来实现Map接口,可以快速查找并存储数据:Map<String, Integer> hashMap = new HashMap<>(); hashMap.put("Alice", 12);hashMap.put("Bob", 18);System.out.println(hashMap.get("Bob"));四、集合的迭代Java中的集合类都实现了Iterable接口,因此可以使用迭代器来访问集合中的元素。
java三大框架是什么Java三大框架是什么一、介绍Java是一种广泛使用的编程语言,由于其跨平台性和丰富的类库支持,成为了企业级应用开发的首选语言。
在Java开发中,框架是非常重要的组成部分,它们提供了一套结构化的工具和方法来简化开发流程并提高代码的重用性和可维护性。
在众多Java框架中,有三个最重要、最流行且被广泛使用的框架,它们分别是Spring框架、Hibernate框架和Struts框架。
二、Spring框架1. 简介Spring框架是一个轻量级的Java开发框架,最初用于解决企业级应用开发中的复杂性和耦合性问题。
Spring提供了一系列的模块和组件,为开发者提供了全面的解决方案,例如依赖注入、AOP(面向切面编程)、IoC(控制反转)等。
Spring框架的核心是IoC容器,它通过管理对象的生命周期和控制对象之间的依赖关系,简化了开发流程。
2. 主要特点和优势(1)松耦合:Spring框架通过IoC容器管理对象之间的依赖关系,使得应用程序的各个组件之间变得松散耦合,便于维护和升级。
(2)面向切面编程:Spring框架支持AspectJ规范,可以通过AOP实现横切关注点的模块化,并将其与业务逻辑分离,提高了代码的可维护性和重用性。
(3)可扩展性:Spring框架采用模块化的设计,开发者可以根据需要选择性地使用各个模块,使得框架具有很高的可扩展性和灵活性。
(4)测试支持:Spring框架提供了对单元测试的支持,可以方便地对代码进行单元测试和集成测试。
3. 使用场景Spring框架广泛应用于企业级应用开发,特别是在大规模和复杂度高的项目中表现出色。
由于其完善的设计和优秀的生态系统,Spring框架不仅可以用于开发Web应用程序,还可以用于开发移动应用、分布式系统、大数据系统等各种类型的应用。
三、Hibernate框架1. 简介Hibernate框架是一个优秀的Java持久化框架,它简化了对象与数据库之间的映射和操作,提高了开发效率和代码的可维护性。
java中集合知识点总结1. Collection接口Collection接口是Java中集合类的基本接口,它定义了一组通用的操作方法,包括添加、删除、查找等操作。
Collection接口有三个主要的子接口:List、Set和Queue。
(1) ListList是一种有序的集合,它允许重复的元素,并且可以按照索引访问元素。
List接口中有常用的实现类:ArrayList、LinkedList和Vector。
其中,ArrayList是基于数组实现的,它支持快速的随机访问和插入操作;LinkedList是基于双向链表实现的,它支持快速的插入和删除操作;Vector是线程安全的类,它支持并发访问。
(2) SetSet是一种不允许重复元素的集合,它用来存储唯一的元素。
Set接口中有常用的实现类:HashSet、LinkedHashSet和TreeSet。
其中,HashSet是基于哈希表实现的,它提供了快速的查找和插入操作;LinkedHashSet是基于哈希表和链表实现的,它保持了元素的插入顺序;TreeSet是基于红黑树实现的,它提供了有序的集合。
(3) QueueQueue是一种先进先出的集合,它用来存储元素,并且支持插入和删除操作。
Queue接口中有常用的实现类:LinkedList和PriorityQueue。
其中,LinkedList可以作为Queue来使用,它支持快速的插入和删除操作;PriorityQueue是基于堆实现的,它提供了优先级队列的功能。
2. Map接口Map接口是Java中的映射表,它用来存储键值对的数据。
Map接口中有常用的实现类:HashMap、LinkedHashMap、TreeMap和Hashtable。
其中,HashMap是基于哈希表实现的,它提供了快速的查找和插入操作;LinkedHashMap是基于哈希表和链表实现的,它保持了键值对的插入顺序;TreeMap是基于红黑树实现的,它提供了有序的映射表;Hashtable是线程安全的类,它支持并发访问。
几种Java集合框架详解Koloboke的目标是替换标准的Java集合和流的API,提供更高效的实现。
Koloboke目前的版本主要是替换java.util.HashSet和java.util.HashMap。
Koloboke提供了一套完整的集合原始类型的实现,可以避免开销很大的装箱/拆箱操作,节省了原始类型装箱消耗的内存。
在Koloboke中,HashSet和HashMap比其它专门的实现(比如GS collections、fastutil、HTTP & Trove)要更快,这是因为:1)相比于其它库,Koloboke对每个entry使用了更少的内存2)Koloboke目标是把键和值存储在同一行高速缓存中3)所有的方法都经过了实现优化,而不是像AbstractSet类或AbstractMap类那样委托给框架类(Skeleton Class)Koloboke的官网:Koloboke的特征:1)极好的兼容Java集合框架(JCF,Java Collections Framework)2)所有原始专门的集合类都继承了基本的接口(比如Collection、Set、Map)3)可用于替换标准的JCF4)Koloboke API for Java 6 and Java 7向前兼容Java 8的新方法5)快速失败的语义6)支持null键(可选的),就像java.util.HashMap中的Float.NaN和Double.NaN键的处理那样。
什么时候使用Chronicle Map或Koloboke Map?使用Chronicle Map的场景:1)存储的entry超过5亿条2)在进程之间分布Map3)使用堆外内存(Off-Heap Memory),因为键和值占用了太多的内存,JVM遭遇GC的痛苦当不想在进程间共享数据,且存储的entry在5亿条以内,那么Koloboke是更理想的选择。
Koloboke目前的最新版本为0.6.8版。
java中的常⽤集合类整理⽬录Collection接⼝集合的遍历:iterator 接⼝集合的遍历:增强for循环List接⼝ArrayListSet接⼝Map接⼝HashMapLinkedHashMapTreeMapPropertiesCollections⼯具类总结集合、数组都是对多个数据进⾏存储操作(主要是内存层⾯存储)的结构,简称Java容器。
数组的特点1.数组初始化以后,长度确定不可变2.数组定义好,其元素的类型确定不可变(可能有多态性)3.数组中提供的⽅法有限,对于添加、删除、插⼊数据等操作不⽅便。
4.获取数组中实际元素的个数是没有办法的。
5.数组存储数据的特点是有序、可重复的。
Java集合可分为Collection和Map两种体系,集合存储的优点是解决数组存储数据⽅⾯的弊端。
Collection接⼝:单列数据,⽤来存储⼀个⼀个的对象List接⼝:元素有序,可重复的集合 --> '动态'数组Set接⼝ :元素⽆序、不可重复的集合Map接⼝:双列数据,保存有映射关系(键值对)的集合Collection接⼝向collection接⼝的实现类的对象中添加数据obj时,要求obj所在类要重写equals⽅法。
Abstract Methodsadd(Object e):将元素e添加到集合中size():获取添加的元素个数addAll(Collection coll):将形参coll集合的元素添加到当前集合中clear():清空集合元素,集合仍然存在,只是集合⾥没有元素isEmpty():判断当前集合是否为空contains(Object obj):判断当前集合中是否包含obj,是否包含是通过调⽤obj的equals判断containsAll(Collection coll):判断形参coll中的所有元素是否都存在当前集合中。
remove(Object obj):移除某个元素,同样通过equals寻找移除的元素removeAll(Collection coll):从当前集合中移除coll集合中所有的元素,需要调⽤equals函数retainAll(Collection coll):求两个集合的交集,结果为修改当前集合后的集合。
浙江大学城市学院实验报告课程名称 Java高级程序设计实验项目名称 Java集合框架实验学生姓名专业班级学号一、实验目的1.理解Java集合框架的特点、接口与类之间的关系2.掌握Java集合框架的List接口,以及List接口的重要实现类LinkedList、ArrayList3.掌握Java集合框架的Set、SortedSet接口,以及重要实现类HashSet与TreeSet4.掌握Java集合框架的Map、SortedMap接口及其重要实现类HashMap、TreeMap5.掌握Java集合框架的Collection与Iterator接口的特点与使用方式二、实验内容1、使用List管理对象集合2、使用Map管理对象集合3、使用Set管理对象集合4、设计一个自定义的集合类三、实验步骤1、在Eclipse中新建工程(即项目)2、使用List管理对象集合1)新建一个包listExample2)在这个包中新建三个类:Student类,StudentList类,StudentListTest类。
参考代码: Student.java, StudentList.java,StudentListTest.java3)完善上面三个类,相关要求参考源代码程序的注释,即根据要求修改源代码程序,给出具体的实现代码(不使用泛型类)。
void addStudent(Student student){//添加一个学生对象boolean a=true;for(int i=0;i<students.size();i++){Student stud = (Student)students.get(i);if(stud.getId().equalsIgnoreCase(student.getId()))a=false;}if(a==true)students.add(student);//修改代码,保证students集合中所有学生对象的id 号唯一}void deleteStudentById(String id){//根据学号删除学生对象for(int i=0;i<students.size();i++){Student stud = (Student)students.get(i);if(stud.getId().equalsIgnoreCase(id))students.remove(stud);}}void deleteStudentByName(String name){//根据姓名删除学生对象for(int i=0;i<students.size();i++){Student stud = (Student)students.get(i);if(stud.getName().equalsIgnoreCase(name))students.remove(stud);}}void deleteStudentByAge(int age){//根据年龄删除学生对象for(int i=0;i<students.size();i++){Student stud = (Student)students.get(i);if(stud.getAge()==age)students.remove(stud);}}Student[] findByName(String name){int a=0;for(int i=0;i<students.size();i++){Student stud = (Student)students.get(i);if(stud.getName().equalsIgnoreCase(name))a++;}Student[] st=new Student[a];int b=0;for(int i=0;i<students.size();i++){Student stud = (Student)students.get(i);if(stud.getName().equalsIgnoreCase(name)){st[b]=stud;b++;}}return st;}Student[] findByAge(int age){int a=0;for(int i=0;i<students.size();i++){Student stud = (Student)students.get(i);if(stud.getAge()==age)a++;}Student[] st=new Student[a];int b=0;for(int i=0;i<students.size();i++){Student stud = (Student)students.get(i);if(stud.getAge()==age){st[b]=stud;b++;}}return st;}4)新创建listExample2包,重新设计设计上述程序(新程序都属于这个包),这时需要使用泛型类,即出现的List、ArrayList或LinkedList都使用泛型。
一、实验目的1. 理解Java集合框架的基本概念和结构。
2. 掌握常用集合类(如ArrayList、LinkedList、HashSet、HashMap等)的使用方法。
3. 熟悉集合框架中的迭代器、比较器、集合工具类等高级特性。
4. 通过实际编程练习,提高对集合框架的运用能力。
二、实验环境1. 操作系统:Windows 102. 编程语言:Java3. 开发工具:Eclipse三、实验内容1. 创建一个包含整数的ArrayList集合,并添加、删除、查找元素。
2. 使用LinkedList实现一个简单的栈和队列。
3. 创建一个包含字符串的HashSet集合,并实现元素的唯一性。
4. 创建一个HashMap集合,存储学生信息(学号作为键,姓名作为值)。
5. 使用迭代器遍历集合元素。
6. 实现自定义比较器,对集合元素进行排序。
7. 使用集合工具类对集合进行操作。
四、实验步骤及代码实现1. 创建一个包含整数的ArrayList集合,并添加、删除、查找元素。
```javaimport java.util.ArrayList;import java.util.List;public class ArrayListTest {public static void main(String[] args) {List<Integer> list = new ArrayList<>();// 添加元素list.add(1);list.add(2);list.add(3);// 删除元素list.remove(1);// 查找元素int index = list.indexOf(2);System.out.println("元素2的索引:" + index); }}```2. 使用LinkedList实现一个简单的栈和队列。
```javaimport java.util.LinkedList;import java.util.Queue;import java.util.Stack;public class LinkedListTest {public static void main(String[] args) {Stack<Integer> stack = new Stack<>();Queue<Integer> queue = new LinkedList<>();// 栈操作stack.push(1);stack.push(2);stack.push(3);System.out.println("栈顶元素:" + stack.peek()); // 队列操作queue.offer(1);queue.offer(2);queue.offer(3);System.out.println("队列头元素:" + queue.peek()); }}```3. 创建一个包含字符串的HashSet集合,并实现元素的唯一性。
java集合知识点Java集合是Java中重要的数据结构之一,它提供了一种方便的方式来存储和操作多个相关对象。
Java集合框架提供了很多实现集合的类和接口,如List、Set、Map等。
在本文中,我们将介绍Java集合的基本概念和常用方法。
一、集合的基本概念1. 集合是什么?集合是用来存储一组相关对象的容器。
与数组不同的是,集合的大小可以动态调整,可以执行插入、删除、查找等操作。
2. 集合的分类Java集合框架中的集合主要分为三个类别:- List:有序的集合,元素可以重复。
常见的实现类有ArrayList、LinkedList。
- Set:无序的集合,元素不可重复。
常见的实现类有HashSet、TreeSet。
- Map:通过键值对存储数据,键不可重复。
常见的实现类有HashMap、TreeMap。
二、集合常用方法1. List常用方法- add(Object obj):向列表中添加指定元素。
- get(int index):返回列表中指定位置的元素。
- remove(int index):删除列表中指定位置的元素。
- size():返回列表中元素的个数。
2. Set常用方法- add(Object obj):向集合中添加指定元素。
- contains(Object obj):判断集合中是否包含指定元素。
- remove(Object obj):从集合中删除指定元素。
- size():返回集合中元素的个数。
3. Map常用方法- put(Object key, Object value):将指定的键值对添加到集合中。
- get(Object key):返回与指定键关联的值。
- remove(Object key):从集合中删除指定键的值。
- size():返回集合中键值对的个数。
三、集合的遍历1. 使用迭代器遍历集合可以使用集合的迭代器来依次访问集合中的元素,例如:```List<String> list = new ArrayList<>();list.add("Apple");list.add("Banana");list.add("Orange");Iterator<String> iterator = list.iterator();while(iterator.hasNext()) {String item = iterator.next();System.out.println(item);}```2. 使用增强for循环遍历集合Java提供了增强for循环,可以方便地遍历集合,例如:```List<String> list = new ArrayList<>();list.add("Apple");list.add("Banana");list.add("Orange");for(String item : list) {System.out.println(item);}```3. 使用Lambda表达式遍历集合Java 8引入了Lambda表达式,可以使用Lambda表达式遍历集合,例如:```List<String> list = new ArrayList<>();list.add("Apple");list.add("Banana");list.add("Orange");list.forEach(item -> System.out.println(item));```综上所述,Java集合是一种方便存储和操作多个相关对象的数据结构,可以根据实际情况选择合适的集合类型,并使用相应的方法来对集合进行操作和遍历。
JA V A集合框架一、集合框架在实际开发中,需要将对象根据不同的需求而存储在特定的数据结构容器中。
但是数组虽然是一种用来存储数据的数据结构,但是它的局限性很低,很难满足各种的需求,所以JDK出现了用来满足各种需求的框架——集合框架。
“集合框架”主要由一组用来操作对象的接口组成。
不同接口描述一组不同数据类型。
常见的集合类有:1)实现Collection接口的:List接口、Set接口。
2)实现Map接口的。
二、Collection接口Collection接口表示了如何把一组对象作为它的元素。
JDK没有直接提供Collection接口的实现,Collection接口的实现依赖于两个继承自自己的接口:Set和List。
所有通过实现Collection接口的子接口的类应该提供两个标准的构造器:一个不需要参数的构造器,用来创建一个空的集合,另外一个需要一个类型作为参数的构造器,用来创建一个和参数的类型相同的元素的集合。
int size():返回这个集合中的元素的数量。
boolean isEmpty():返回集合是否包含元素,如果没有的话,返回true。
boolean contains(E e):如果这个集合包含某个指定的元素,返回true。
Iterator<E> iterator():返回这个集合中的所有元素的迭代。
boolean add(E e):向集合中添加新的元素,如果添加成功,返回true。
boolean remove(E e):从集合中删除指定元素,如果删除成功,返回true。
boolean containsAll(Collection<?> c):这个集合是否包含指定集合中的所有的元素。
boolean addAll(Collection<? extends E> c):添加指定的集合中的所有元素到这个集合中。
boolean removeAll(Collection<?> c):删除当前集合中与给定集合相同的元素。
在这个调用返回之后,这个集合将不包含和指定的集合一样的元素。
boolean retainAll(Collection<?> c):从这个集合中删除所有不包含在指定的集合中的所有元素。
<T> T[] toArray(T[] a):返回一个包含集合中所有的元素的数组。
void clear():从集合中删除所有的元素。
boolean equals(Object obj):比较这个集合和指定对象是否相等。
int hashCode():返回这个集合的哈希值。
三、List接口List 接口继承了Collection 接口,用于定义一个允许重复项的有序集合。
可以将List理解为存放对象的数组,只不过其元素个数可以动态的增加或者减少。
该接口不但能够对列表的一部分进行处理,还添加了面向位置的操作。
面向位置的操作包括插入某个元素或Collection 的功能,还包括获取、除去或更改元素的功能。
在List 中搜索元素可以从列表的头部或尾部开始,如果找到元素,还将报告元素所在的位置:void add(int index, Object element): 在指定位置index上添加元素element。
boolean addAll(int index, Collection c): 将集合c的所有元素添加到指定位置index。
Object get(int index): 返回List中指定位置的元素。
int indexOf(Object o): 返回第一个出现元素o的位置,否则返回-1。
int lastIndexOf(Object o) :返回最后一个出现元素o的位置,否则返回-1。
Object remove(int index):删除指定位置上的元素。
Object set(int index, Object element) :用元素element取代位置index上的元素,并且返回旧的元素。
在“集合框架”中有两种常规的List 实现ArrayList 和LinkedList,分别用动态数组和链表的方式实现List接口。
可以认为ArrayList和LinkedList的方法在逻辑上完全一样,只是在性能上有一定的差别。
如果要支持随机访问,而不必在除尾部的任何位置插入或除去元素,那么,ArrayList 提供了可选的集合。
但如果,您要频繁的从列表的中间位置添加和除去元素,而只要顺序的访问列表元素,那么,LinkedList 实现更好。
1)LinkedList类LinkedList类——链表实现的List,在删除或插入时只需改变链表“指针”,即可实现。
(1) void addFirst(Object o): 将对象o添加到列表的开头void addLast(Object o):将对象o添加到列表的结尾(2) Object getFirst(): 返回列表开头的元素Object getLast(): 返回列表结尾的元素(3) Object removeFirst(): 删除并且返回列表开头的元素Object removeLast():删除并且返回列表结尾的元素(4) LinkedList(): 构建一个空的链接列表LinkedList(Collection c): 构建一个链接列表,并且添加集合c的所有元素“使用这些新方法,您就可以轻松的把LinkedList 当作一个堆栈、队列或其它面向端点的数据结构。
”2)ArrayList类ArrayList类——动态数组实现的List,可以通过下标迅速的索引到对应的元素,但在删除和移动时移动较多元素。
ArrayList类封装了一个动态再分配的Object[]数组。
每个ArrayList对象有一个capacity。
这个capacity表示存储列表中元素的数组的容量。
当元素添加到ArrayList时,它的capacity在常量时间内自动增加。
在向一个ArrayList对象添加大量元素的程序中,可使用ensureCapacity方法增加capacity。
这可以减少增加重分配的数量。
(1) void ensureCapacity(int minCapacity): 将ArrayList对象容量增加minCapacity(2) void trimToSize(): 整理ArrayList对象容量为列表当前大小。
程序可使用这个操作减少ArrayList对象存储空间。
四、List高级—数据结构:Queue队列队列是常用的数据结构,可以将(Queue)队列看成特殊的线性表,队列限制了对线性表的访问方式,即只能从线性表的一段添加(offer)元素,从另一端取出(poll)元素。
队列遵循先进先出(FIFO)原则。
JDK中提供了Queue接口,同时使得LinkedList实现该接口(Queue经常要进行插入和删除的操作,而LinkedList在这方面效率最高)。
Queue接口中的主要方法:Boolean offer(E e)讲一个对象添加到队尾,添加成功则返回true。
E pool()从队首删除并返回一个元素。
E peek() 返回队首的元素(但并不删除)。
五、List高级—数据结构:Deque栈栈也是常用的数据结构,栈(Deque)则是Queue的子接口,定义了所谓的“双端队列”,即从队列的两端分别可以入队(offer)和出队(poll),如果将Deque限制为只能从一段入队和出队,则可实现“栈(Stack)”的数据结构,对于栈而言,入栈称之为push,出栈称为pop。
栈遵循先进后出(FILO)原则。
Deque常用的方法:E push()压入,向栈中存入数据。
E pop()取出,从栈中取出数据。
E peek()获取栈顶位置的元素,但不取出。
六、Set接口Set 接口也是Collection 接口的子接口,但是与Collection 或List 接口不同的是,Set 接口中不能加入重复的元素,是因为Set判断两个对象相同不是使用==运算符,而是根据equals方法。
即两个对象用equals方法比较返回true,Set就不能接受两个对象。
同时Set 集合里多个对象之间没有明显的顺序。
其实Set具有与Collection完全一样的接口,除了注释不一样其他都一样,也就是Set 根本没有对Collection扩展,只是对add,equals,hashCode的定义说明不一样,因为Set是不允许重复元素的。
但是要注意的是:虽然Set和Collection中的方法一样,但是他们是完全不一样的,List可以自动为Collection,但是绝对不可以转为Set的。
遍历Set集合的元素只有一种方式,迭代器。
同时set集合不支持索引,也不具备List 集合的get()方法。
Set 接口的常用子类:1)散列的存放:HashSetHashSet按Hash算法来存储集合的元素,因此具有很好的存取和查找性能。
HashSet的特点:(1)HashSet不是同步的,多个线程访问是需要通过代码保证同步(2)集合元素值可以使null。
HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值也相等。
其实原理是这样的:HashSet的底层采用HashMap来存放数据,HashMap的put()方法是这样的:public V put(K key, V value) {if (key == null)return putForNullKey(value);int hash = hash(key.hashCode());//----------1----------int i = indexFor(hash, table.length);//-----------2---------for (Entry<K,V> e = table[i]; e != null; e = e.next) {//-----------3---------Object k;if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {V oldValue = e.value;e.value = value;e.recordAccess(this);return oldValue;}}//------------------4--------------------modCount++;addEntry(hash, key, value, i);return null;}当向HashMap中添加元素的时候,首先计算元素的hashcode值,然后根据1处的代码计算出Hashcode的值,再根据2处的代码计算出这个元的存储位置如果这个位置为空,就将元素添加进去;如果不为空,则看3-4的代码,遍历索引为i的链上的元素,如果key重复,则替换并返回oldValue值。