集合是java中常用的一个机制。上次,我在想回头重新看集合的时候,发现网上对集合的整理大多都非常糟,要么过于繁琐,要么过于简洁。于是,我决心自己整理一篇集合的文章,作为自己学过集合的一个总结。
老规矩,我会把我看过的给我印象比较深刻的文章贴在最后,作为参考文献。
集合的概述
(1)Java集合类存放于 java.util 包中,是一个用来存放对象的容器。
-
集合只能存放对象。比如你存一个 int 型数据1 放入集合中,其实它是自动转换成 Integer类后存入的,Java中每一种基本类型都有对应的引用类型。
-
集合存放的是多个对象的引用,对象本身还是放在堆内存中。
-
集合可以存放不同类型,不限数量的数据类型。
(2)Java 集合可分为 Set、List 和 Map 三种大体系
-
Set:存取无序,元素不可以重复
-
List:存取有序,有索引,可以根据索引来进行取值,元素可以重复
-
Map:具有映射关系的集合
(3)在 JDK5 之后,增加了泛型,Java 集合可以记住容器中对象的数据类型
set集合
Hashset集合
特点、方法
HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。我们大多数时候说的set集合指的都是HashSet。
HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。HashSet 具有以下特点:
- 不能保证元素的排列顺序
- 不可重复(hashcode不相同)
- HashSet 不是线程安全的
- 集合元素可以使 null
当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置
存在set集合哪个位置由这个值的hashcode决定,而不是按先来后到
如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功
基本操作
public class test3 {
public static void main(String[] args) {
// Set set = new HashSet();//创建set集合-方式1
Set <Object> set = new HashSet<Object>();//创建set集合-方式2。与上面的方式1等价
set.add(1);//添加元素
set.add("a");
set.remove(1);//移除元素
System.out.println(set.contains(1));//判断是否包含元素,存在返回true
set.clear();//清空集合
遍历
- 使用 Iterator 接口遍历集合元素
Iterator 接口主要用于遍历 Collection 集合中的元素,Iterator 对象也被称为迭代器
Iterator 接口隐藏了各种 Collection 实现类的底层细节,向应用程序提供了遍历 Collection 集合元素的统一编程接口
Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。
- 使用 foreach 循环遍历集合元素
Java 5 提供了 foreach 循环迭代访问 Collection
set.add("a");
set.add("b");
set.add("c");
set.add("d");
// set.add("d");//set集合是存的值是不重复
set.add(1);
set.add(true);
set.add(null);//Hashset允许使用null,有且仅有一个元素为null
System.out.println(set);//输出集合:[null, a, 1, b, c, d, true]
//使用迭代器遍历集合
Iterator it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//for each迭代集合,推荐使用这种
for(Object obj : set){//这个的意思是把set的每一个值取出来,赋值给obj,直到循环set的所有值
System.out.println(obj);
}
System.out.println(set.size());//获取集合的元素个数
泛型
//如果想要让集合只能存同样类型的对象,怎么做
//使用泛型
Set<String> set1 = new HashSet<String>();//比如指定String为集合的泛型,那么这个集合不能存String类型之外的数据
set1.add("sbc");
// set1.add(1);
Treeset集合
TreeSet 是 SortedSet 接口的实现类
TreeSet 特点:存取无序,元素唯一,可以进行排序(排序是在添加的时候进行排序)
TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序
自然排序
TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序排列
- 如果 this > obj,返回正数 1
- 如果 this < obj,返回负数 -1
- 如果 this = obj,返回 0 ,则认为这两个对象相等
必须放入同样类的对象.(默认会进行排序) 否则可能会发生类型转换异常.我们可以使用泛型来进行限制
public class Test4 {
public static void main(String[] args) {
Set<Integer> set = new TreeSet<Integer>();
//TreeSet自然排序
set.add(5);
set.add(2);
set.add(4);
set.add(3);
System.out.println(set);//输出集合:[2, 3, 4, 5]
set.remove(5);//移除元素
System.out.println(set.contains(3));//判断是否包含元素,存在返回true
set.clear();//清空集合
//使用迭代器遍历集合
Iterator<Integer> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//for each迭代集合,推荐使用这种
for(Integer i : set){
System.out.println(i);
}
定制排序
如果需要实现定制排序,则需要在创建 TreeSet 集合对象时,提供一个 Comparator 接口的实现类对象。由该 Comparator 对象负责集合元素的排序逻辑。
List集合
特点
- List 代表一个元素有序、且可重复的集合,集合中的每个元素都有其对应的顺序索引
- List 允许使用重复元素,可以通过索引来访问指定位置的集合元素。
- List 默认按元素的添加顺序设置元素的索引。
- List 集合里添加了一些根据索引来操作集合元素的方法
ArrayList 和 Vector
ArrayList 和 Vector 是 List 接口的两个典型实现
两者的区别:
-
Vector是一个古老的集合,通常建议使用 ArrayList
-
ArrayList 是线程不安全的,而 Vector 是线程安全的
-
即使为保证 List 集合线程安全,也不推荐使用 Vector
接口实现
基本操作
public class Test5 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("b");//第一个,索引下标0
list.add("d");//索引下标1
list.add("c");//索引下标2
list.add("a");//索引下标3
list.add("d");//允许使用重复元素
System.out.println(list);//结果:[b, d, c, a, d]
System.out.println(list.get(2));//通过索引来访问指定位置的集合元素.结果:c
list.add(1,"f");//在指定索引下标的位置插入数据
System.out.println(list);//结果:[b, f, d, c, a, d]
List<String> m = new ArrayList<String>();
m.add("123");
m.add("456");
list.addAll(2, m);//在指定索引下标的位置插入集合
System.out.println(list);//结果:[b, f, 123, 456, d, c, a, d]
System.out.println(list.indexOf("d"));//获取指定元素在集合中第一次出现的索引下标.结果:4
System.out.println(list.lastIndexOf("d"));//获取指定元素在集合中最后一次出现的索引下标.结果:7
list.remove(2);//根据指定的索引下标移除元素
System.out.println(list);//结果:[b, f, 456, d, c, a, d]
list.set(1, "ff");//根据指定的索引下标修改元素
System.out.println(list);//结果:[b, ff, 456, d, c, a, d]
//根据索引下标的起始位置截取一段元素形参一个新的集合,截取的时候,包含开始的索引不包含结束时的索引
List<String> sublist = list.subList(2, 4);//取索引下标在大于等于2,小于4的元素
System.out.println(sublist);//结果:[456, d]
System.out.println(list.size());//集合的长度.结果:7
}
}
Map集合
HashMap集合
特点
-
Map 用于保存两组具有映射关系的数据,一组值用于保存 Map 里的 Key,另外一组用于保存 Map 里的 Value
-
Map 中的 key 和 value 都可以是任何引用类型的数据
-
Map 中的 Key 不允许重复,即同一个 Map 对象的任何两个 Key 通过 equals 方法比较中返回 false
-
Key 和 Value 之间存在单向一对一关系,即通过指定的 Key 总能找到唯一的,确定的 Value。
Map 接口与HashMap类
基本操作
public class Test6 {
public static void main(String[] args) {
//介绍Map集合的方法
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("b", 1);//添加数据,put(k,v)
map.put("c", 2);
map.put("e", 2);
System.out.println(map);//结果:{b=1, c=2, e=2}
System.out.println(map.get("e"));//根据key取value值. 结果:2
map.remove("c");//根据key移除键值对
System.out.println(map);//结果:{b=1, e=2}
System.out.println(map.size());//map集合的长度. 结果:2
System.out.println(map.containsKey("a"));//判断当前的map集合是否包含指定的key
System.out.println(map.containsValue(2));//判断当前的map集合是否包含指定的value
// map.clear();//清空集合
//介绍Map集合的遍历
Set<String> keys = map.keySet();//获取map集合的key的集合
System.out.println(keys);//结果:[b, e]
map.values();//获取集合的所有value值
System.out.println(map.values());//结果:[1, 2]
//遍历map集合,通过map.keySet();
for(String key : keys){
System.out.println("key: " + key + ", value: " + map.get(key));
}
//通过map.entrySet();遍历map集合
Set<Entry<String, Integer>> entrys = map.entrySet();
for(Entry<String, Integer> en : entrys){
System.out.println("key: " + en.getKey() + ", value: " + en.getValue());
}
HashMap & Hashtable
HashMap 和 Hashtable 是 Map 接口的两个典型实现类,区别:
- Hashtable 是一个古老的 Map 实现类,不建议使用
- Hashtable 是一个线程安全的 Map 实现,但 HashMap 是线程不安全的。
- Hashtable 不允许使用 null 作为 key 和 value,而 HashMap 可以
与 HashSet 集合不能保证元素的顺序一样,Hashtable 、HashMap 也不能保证其中 key-value 对的顺序
-
Hashtable 、HashMap 判断两个 Key 相等的标准是:两个 Key 通过 equals 方法返回 true,hashCode 值也相等。
-
Hashtable 、HashMap 判断两个 Value 相等的标准是:两个 Value 通过 equalHashMap 判断两个 Values 方法返回 true
TreeMap集合
TreeMap 存储 Key-Value 对时,需要根据 Key 对 key-value 对进行排序。TreeMap 可以保证所有的 Key-Value 对处于有序状态。
TreeMap 的 Key 的排序:
-
自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException
-
定制排序(了解):创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口
注:
-
Comparable接口是在java.lang类中的,而Comparator接口是在java.util类中的。
-
Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。
//TreeMap的自然排序是英文字典排序 Map<Integer,String> map = new TreeMap<Integer, String>(); map.put(4, "a"); map.put(2, "a"); map.put(3, "a"); map.put(1, "a"); System.out.println(map);//结果:{1=a, 2=a, 3=a, 4=a} Map<String,String> map1 = new TreeMap<String, String>(); map1.put("b", "b"); map1.put("c", "c"); map1.put("d", "d"); map1.put("a", "a"); map1.put("ab", "ab"); map1.put("1", "ab"); map1.put("10", "ab"); System.out.println(map1);//结果:{1=ab, 10=ab, a=a, ab=ab, b=b, c=c, d=d}
参考文献
Java 集合框架 www.runoob.com/java/java-c…
java集合入门和深入学习,看这篇就差不多了 juejin.cn/post/684490…
Java常用集合类及其区别 blog.csdn.net/zhj87097558… (常用类)
java集合的各种操作 www.51gjie.com/java/654.ht… (操作详解)
Set之HashSet和TreeSet介绍 blog.csdn.net/u010648555/…