Java 集合
概述
Java集合类存放于 java.util 包中,是一个用来存放对象的容器。
①、集合只能存放对象。比如你存一个 int 型数据 1放入集合中,其实它是自动转换成 Integer 类后存入的,Java中每一种基本类型都有对应的引用类型。
②、集合存放的是多个对象的引用,对象本身还是放在堆内存中。
③、集合可以存放不同类型,不限数量的数据类型。
Java 集合可分为 Set、List 和 Map 三种大体系
Set:无序、不可重复的集合
List:有序,可重复的集合
Map:具有映射关系的集合
Collection 接口
collection是集合的一个基本接口,里面包含很多方法如下图
Iterator 接口
使用 Iterator 接口遍历集合元素
Iterator 接口主要用于遍历 Collection 集合中的元素,Iterator 对象也被称为迭代器
Iterator 接口隐藏了各种 Collection 实现类的底层细节,向应用程序提供了遍历 Collection 集合元素的统一编程接口
Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。
Collections 工具类
Collections 是一个操作 Set、List 和 Map 等集合的工具类
Collections 中提供了大量方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
排序操作:
reverse(List):反转 List 中元素的顺序
shuffle(List):对 List 集合元素进行随机排序
sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class test7 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("b");
list.add("cd");
list.add("ca");
list.add("a");
list.add("a");
list.add("1");
System.out.println(list);
Collections.reverse(list);//反转 List 中元素的顺序
System.out.println(list);
Collections.shuffle(list);//对 List 集合元素进行随机排序
System.out.println(list);
Collections.sort(list);//list集合字典升序排序
System.out.println(list);
System.out.println(Collections.frequency(list, "x"));//返回指定集合中指定元素的出现次数
Collections.replaceAll(list, "b", "bb");//使用新值替换 List 对象的所有旧值
System.out.println(list);
Collections.swap(list, 0, 4);//将指定 list 集合中的 i 处元素和 j 处元素进行交换
System.out.println(list);
System.out.println(Collections.max(list));
System.out.println(Collections.min(list));
}
}
//
[b, cd, ca, a, a, 1]
[1, a, a, ca, cd, b]
[a, ca, b, a, 1, cd]
[1, a, a, b, ca, cd]
0
[1, a, a, bb, ca, cd]
[ca, a, a, bb, 1, cd]
cd
1
sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
import java.util.*;
public class test07 {
public static void main(String[] args) {
Student s1 = new Student(14,"张三");
Student s2 = new Student(12,"李四");
Student s3 = new Student(13,"王五");
Student s4 = new Student(11,"小六");
List<Student> list = new ArrayList<Student>();//ArrayList没有排序的功能所以这里不能直接newStudents
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
for (Student stu : list){
System.out.println(stu.age + " " + stu.name);
}
System.out.println("===================");
Collections.sort(list , new Student());//使用sort方法,把写好的排序方法Student用在list上
for (Student st : list)
{
System.out.println(st.age + " " + st.name);
}
}
}
class Student implements Comparator<Student> {
int age;
String name;
public Student() {
}
public Student(int age, String name) {
this.age = age;
this.name = name;
}
public int compare(Student p1, Student p2) {
if (p1.age > p2.age) {
return 1;
} else if (p1.age < p2.age) {
return -1;
} else {
return 0;
}
}
}
//
14 张三
12 李四
13 王五
11 小六
===================
11 小六
12 李四
13 王五
14 张三
查找、替换
Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
Object min(Collection)
Object min(Collection,Comparator)
int frequency(Collection,Object):返回指定集合中指定元素的出现次数
boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值
Student s = Collections.max(stus, new Student());//第二个位置放入排序方法
System.out.println(s.name + "," + s.age);
Student ss = Collections.min(stus, new Student());
System.out.println(ss.name + "," + ss.age);
同步控制
Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题
一、HashSet
HashSet 是 Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。我们大多数时候说的set集合指的都是HashSet
HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。
HashSet 具有以下特点:
- 不能保证元素的排列顺序
- 不可重复
- HashSet 不是线程安全的
- 集合元素可以使 null
当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。
如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。
基础功能实现
import java.util.HashSet;
import java.util.Set;
public class test1 {
public static void main(String[] args) {
Set<Object> set = new HashSet<Object>();//用Set接口去接收HashSet
set.add(1);
set.add('a');
System.out.println(set);
set.remove(1);//移除元素
System.out.println(set);
System.out.println(set.contains(1));//判断是否包含元素
set.clear();//清空集合
System.out.println(set.size());//集合大小
System.out.println(set);
}
}
//
[1, a]
[a]
false
[]
遍历集合方法
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class test1 {
public static void main(String[] args) {
Set<Object> set = new HashSet<Object>();//用Set接口去接收HashSet
set.add('a');
set.add('b');
set.add('c');
set.add('d');
System.out.println(set);
//第一种遍历:迭代器
Iterator it = set.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
System.out.println("=============================");
//第二种遍历:for each迭代集合,推荐使用这种
for (Object obj : set){//用Object类型的引用变量
//意思就是吧set集合的每个值取出来赋值给obj,直到把set遍历完成
System.out.println(obj);
}
}
}
一般都用for each遍历集合,这个的意思是把set的每一个值取出来,赋值给obj,直到循环set的所有值
不可重复性和不确定顺序性
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class Test3 {
public static void main(String[] args) {
// Set set = new HashSet();
Set<Object> set = new HashSet<Object>();//与上面的等价
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);
System.out.println(set);
//for each迭代集合,推荐使用这种
for(Object obj : set){//这个的意思是把set的每一个值取出来,赋值给obj,直到循环set的所有值
System.out.println(obj);
}
}
}
//输出结果只有一个d且顺序并不按照添加顺序输出
null
a
1
b
c
d
true
如果想要让集合只能存同样类型的对象,怎么做?
使用泛型
Set<String> set1 = new HashSet<String>();//比如指定
String为集合的泛型,那么这个集合不能存String类型之外的数据
set1.add("sbc");
//set1.add(1);显示错误
二、TreeSet
TreeSet是另一种Set集合,其本质也是实现Collection 接口,TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。TreeSet 支持两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。
自然排序
排序:TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序排列
如果 this > obj,返回正数 1
如果 this < obj,返回负数 -1
如果 this = obj,返回 0 ,则认为这两个对象相等
必须放入同样类的对象!!!!!.(默认会进行排序) 否则可能会发生类型转换异常.我们可以使用泛型来进行限制
import java.util.Set;
import java.util.TreeSet;
public class test2 {
public static void main(String[] args) {
Set<Integer> set = new TreeSet<Integer>();
set.add(1);
set.add(4);
set.add(2);
set.add(7);
System.out.println(set);
}
}
//
[1, 2, 4, 7] 这就是自然排序
实现功能
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class test2 {
public static void main(String[] args) {
Set<Integer> set = new TreeSet<Integer>();
set.add(1);
set.add(4);
set.add(2);
set.add(7);
System.out.println(set);
set.remove(1);
System.out.println(set.contains(5));
//set.clear();
//遍历1,迭代器
Iterator<Integer> it = set.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//遍历2,for each
for (Integer ojb : set ){
System.out.println(ojb);
}
}
}
//
[1, 2, 4, 7]
false
2
4
7
2
4
7
自定义类放入集合的排序
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class test2 {
public static void main(String[] args) {
Person per1 = new Person("张三",23);
Person per2 = new Person("李四",21);
Person per3 = new Person("王五",19);
Person per4 = new Person("赵六",12);
Set<Person> set = new TreeSet<Person>(new Person()) ;//分析见下文
set.add(per1);
set.add(per2);
set.add(per3);
set.add(per4);
for(Person p : set){
System.out.println(p.name + " " + p.age);
}
}
}
class Person implements Comparator<Person>{
int age;
String name;
public Person(){
}
public Person(String name, int age){
this.name = name;
this.age = age;
}
public int compare(Person o1,Person o2){
if(o1.age > o2.age){
return 1;
}else if(o1.age < o2.age){
return -1;
}else{
return 0;
}
}
// @Override
// public int compare(Person o1, Person o2) {//年龄倒序排列
// if(o1.age < o2.age){
// return 1;
// }else if(o1.age > o2.age){
// return -1;
// }else{
// return 0;
// }
// }
}
//
赵六 12
王五 19
李四 21
张三 23
代码分析:Set set = new TreeSet(new Person())
- 这里为什么要newPerson?
- 定义类时为什么同时有无参和有参构造器?
- 这里直接在Person类里面implement了comparator,所以这里传了一个Person对象进TreeSet,但实际上此对象发挥作用的只有compare方法 。
- 首先我们的TreeSet需要有自定义的排序功能,实现此功能需要我们在new TreeSet的时候给他一个“可比较Person对象的对象” 抛砖引玉解释一下这里要写new Person()和Person里必须写空惨构造的原因。
- 理论上来说是可以任意新建一个class implement Comparator’<‘Person’>’,然后把这个class new出对象再传给TreeSet的
- 但是这个用于比较的任意Class(假设叫A),必须要有空参数的构造器,否则无法在TreeSet那里用new A()的写法造出对象。
- 这也是为什么再写Person的构造器的时候必须写两个,其中空参构造器是写来专门给comparator用的。
- 另一个可输入age和name的才是实际新建person类的时候会用到的构造器
- 这里可以做两个实验:第一个是不在person里写comparator,写到一个新建类A里,然后传new A()给TreeSet;第二个是person里面致谢一个有参构造器,然后再TreeSet里面随便new一个person(" ", 0)给他
- 这两种写法最终都能达到比较成功的效果。
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class test02 {
public static void main(String[] args) {
person p1 = new person(19,"张三");
person p2 = new person(17,"张4");
person p3 = new person(23,"张5");
person p4 = new person(26,"张6");
Set<person> set = new TreeSet<person>(new A());
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
for (person pe : set){
System.out.println(pe.age +" " + pe.name);
}
}
}
class person{
int age;
String name;
public person(int age, String name) {
this.age = age;
this.name = name;
}
}
class A implements Comparator<person>{
@Override
public int compare(person p1,person p2){
if(p1.age > p2.age){
return 1;
}else if(p1.age < p2.age){
return -1;
}else{
return 0;
}
}
}
//
17 张4
19 张三
23 张5
26 张6
TreeSet需要有自定义的排序功能,实现此功能需要我们在new TreeSet的时候给他一个“可比较Person对象的对象”在这个代码里---->我们单独用Class A来实现比较代码,在把Class A传入TreeSet里,给TreeSet“可比较Person对象的对象”的功能,但传入时用的代码为Class A();这个代码是无参的,但因为在写Class A类时我们并没有加入有参构造器所以会默认给出无参构造器所以可以直接用,但在第一个例子那,在Person类里写了有参构造器用于初始化数据,所以必须添入无参构造器,new Person()在传入TreeSet时,仅仅作为“比较的方法”传入TreeSet。而为什么要new对象 是因为这个比较的方法是对象名为“可比较Person对象的对象”。
三、List与ArrayList
ArrayList是List的实现类
List 代表一个元素有序、且可重复的集合,集合中的每个元素都有其对应的顺序索引
List 允许使用重复元素,可以通过索引来访问指定位置的集合元素。
List 默认按元素的添加顺序设置元素的索引。
List 集合里添加了一些根据索引来操作集合元素的方法
import java.util.ArrayList;
import java.util.List;
public class test4 {
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);
System.out.println(list.get(2));//通过索引来访问指定位置的集合元素
list.add(1,"f");//在指定索引下标的位置插入数据
System.out.println(list);
List<String> l = new ArrayList<String>();
l.add("123");
l.add("456");
list.addAll(2, l);//在指定索引下标的位置插入集合
System.out.println(list);
System.out.println(list.indexOf("d"));//获取指定元素在集合中第一次出现的索引下标
System.out.println(list.lastIndexOf("d"));//获取指定元素在集合中最后一次出现的索引下标
list.remove(2);//根据指定的索引下标移除元素
System.out.println(list);
list.set(1, "ff");//根据指定的索引下标修改元素
System.out.println(list);
//根据索引下标的起始位置截取一段元素形参一个新的集合,截取的时候,包含开始的索引不包含结束时的索引
List<String> sublist = list.subList(2, 4);//取索引下标在大于等于2小于4的元素
System.out.println(sublist);
System.out.println(list.size());//集合的长度
}
}
//
[b, d, c, a, d]
c
[b, f, d, c, a, d]
[b, f, 123, 456, d, c, a, d]
4
7
[b, f, 456, d, c, a, d]
[b, ff, 456, d, c, a, d]
[456, d]
7
四、Map 接口与HashMap类 TreeMap
-
Map 用于保存具有映射关系的数据,因此 Map 集合里保存着两组值,一组值用于保存 Map 里的 Key,另外一组用于保存 Map 里的 Value。
-
Map 中的 key 和 value 都可以是任何引用类型的数据
-
Map 中的 Key 不允许重复,即同一个 Map 对象的任何两个 Key 通过 equals 方法比较中返回 false
-
Key 和 Value 之间存在单向一对一关系,即通过指定的 Key 总能找到唯一的,确定的 Value。
基本功能
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
public class test6 {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("b", 1);//添加数据
map.put("c", 2);
map.put("e", 2);
System.out.println(map);
System.out.println(map.get("b"));//根据key取值
map.remove("c");//根据key移除键值对
System.out.println(map);
System.out.println(map.size());//map集合的长度
System.out.println(map.containsKey("a"));//判断当前的map集合是否包含指定的key
System.out.println(map.containsValue(10));//判断当前的map集合是否包含指定的value
// map.clear();//清空集合
Set<String> keys = map.keySet();//获取map集合的key的集合
map.values();//获取集合的所有value值
//遍历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());
}
}
}
//
{b=1, c=2, e=2}
1
{b=1, e=2}
2
false
false
key: b, value: 1
key: e, value: 2
key: b, value: 1
key: e, value: 2
字典排序
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
public class test6 {
public static void main(String[] args) {
//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);
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=a, 2=a, 3=a, 4=a}
{1=ab, 10=ab, a=a, ab=ab, b=b, c=c, d=d}