集合类
集合类的概念:用于存储数据的容器。
集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。
任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。
集合框架逻辑梳理
在我们学习集合框架前需要理清其中的继承和逻辑关系,这样方便我们学好集合框架
Collection接口
所有集合类都位于java.util包下。Java的集合类主要由两个接口派生而出:Collection和Map,Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类。
Collection一次存一个元素,是单列集合;
Map一次存一对元素,是双列集合。Map存储的一对元素:键–值,键(key)与值(value)间有对应(映射)关系。
Collection集合主要有List和Set两大接口
List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引。元素可以重复。
Set:无序(存入和取出顺序有可能不一致),不可以存储重复元素。必须保证元素唯一性。
集合框架被设计成要满足以下几个目标。
-
该框架必须是高性能的。基本集合(动态数组,链表,树,哈希表)的实现也必须是高效的。
-
该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性。
-
对一个集合的扩展和适应必须是简单的
为什么要有集合类
在实际应用中,我们经常需要用到数据结构。在java.util包中定义了一组类,用于按照不同需求进行数据存储和访问,这组类称为对象容器类,简称容器类。
集合的优缺点
该框架中的各种类和接口各有各的特点所以只能通过比较不同得出优缺点。
Set和List的区别
-
Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
-
Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 <实现类有HashSet,TreeSet>。
-
List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 <实现类有ArrayList,LinkedList,Vector> 。
但是集合框架有共通的优点
- 容量自增长
- 提供了高性能的数据结构和算法,使代码的编写更加轻松
- 允许不同的API之间的互操作,API之间可以来回传递集合
- 可以方便地扩展和操作集合,提高代码复用性和可操作性
- 通过使用JDK自带的集合类,降低了代码维护和学习的成本。
Iterator
在我们学习集合类之前不可避免地需要学习集合类中重要的Iterator接口。
迭代器可以方便我们操作集合对象中的数据。
迭代器为我们提供了三个方法分别为
hasNext(boolean)
如果仍有元素可以迭代,则返回true。next(E)
返回迭代的下一个元素。remove(void)
从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。
Iterator的代码实现遍历
List list = new ArrayList();
list.add(111);
list.add(222);
list.add(888);
//iterator的使用
//根据集合对象获取对象的迭代器对象
Iterator it = list.iterator();
//判断集合迭代器中是否有元素
while (it.hasNext()){
int i = (int) it.next();
System.out.println(i);
}
//如果有就获取元素
Iterator的增删操作
//列表迭代器能对列表中的元素进行增删
//但是必须使用列表迭代中的方法来实现
ListIterator lit = list.listIterator();
while (lit.hasNext()){
int b = (int) lit.next();
if (b==222){
lit.add(999);//使用了列表迭代器中的方法
}
System.out.println(b);
}System.out.println(list);
集合类中工具类Collections
List<Integer> list = new ArrayList<>()
list.add(99);
list.add(99);
list.add(93);
list.add(94);
list.add(96);
list.add(99);
list.add(29);
System.out.println(Collections.max(list));
Collections.sort(list);//排序
System.out.println(list);
Collections.reverse(list);//翻转
System.out.println(list);
Collections.shuffle(list);//洗牌
System.out.println(list);
List接口
List接口继承了Collection接口,该接口中元素是按顺序存放的,允许有相同的元素,由元素的存放顺序来决定其下标,所以,通数组一样,我们可以通过下标访问元素。还可以任意增删List中任意位置的元素。
方法 | 描述 |
---|---|
boolean add(int index,Object obj) | 添加元素,操作成功返回true,失败返回false |
boolean addALL(int index,Collection coll) | 添加集合中的全部元素,操作成功返回true,失败返回false |
Object get(int index) | 返回指定位置的元素 |
Object set (int index , Object obj) | 将list对象中的指定位置元素改成指定对象 |
List集合中的主要实现:Vector向量类、ArrayList、LinkedList
ArrayList | LinkedList | Vector | |
---|---|---|---|
底层实现 | 数组 | 双向链表 | 数组 |
同步性及效率 | 不同步,非线程安全,效率高,支持随机访问 | 不同步,非线程安全,效率高 | 同步,线程安全,效率低 |
特点 | 查询快,增删慢 | 查询慢,增删快 | 查询快,增删慢 |
默认容量 | 10 | / | 10 |
扩容机制 | int newCapacity = oldCapacity + (oldCapacity >> 1); | / | 2 倍 |
List集合的实际实现
public static void main(String[] args){
// 1.创建集合
List list = new ArrayList();
// 2.创建元素对象
Student s1 = new Student("jjj",12);
Student s2 = new Student("jjj",13);
Student s3 = new Student("jjj",14);
Student s4 = new Student("jjj",15);
// 3.将元素对象添加到集合对象中去
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
System.out.println(list);
//get方法
Object obj = list.get(2);
System.out.println("索引为2的方法为"+obj);
//size方法
System.out.println(list.size());
// 4.遍历集合
for (int i = 0 ; i <list.size();i++ ){
System.out.println(list.get(i));
}
Set接口
Set接口继承了Collection接口,该接口不允许存在相同的元素,也就是说当已经存储了一个元素e时,无法再向其中添加另一个完全相同的元素e,也不无法将已有的元素修改成与其他元素相同的值。
Set接口中类的特性
- 以不同的数据结构实现的set类,拥有不同数据结构带来的特性,在实际使用时,根据逻辑的需要选择适合的Set类进行使用
- Set系列中的类提供的方法比List系列提供的方法少很多,例如不支持插入和修改操作,而且Set类中的Iterator()方法也需要专门的定制
Set集合的实现集合
- Set中最常用的集合:HashSet
在用Set集合的时候我几乎用的都是HashSet,HashSet是使用Hash表实现的,集合里面的元素是无序得,可以有null值,但是不能有重复元素。
特点:因为相同的元素具有相同的hashCode,所以不能有重复元素
小知识点:由于我们在创建集合对象时,创建的对象的内存是不同的所以Set会默认为不同元素,我们需要将对象中的equals()和hashcode()进行重写。
public static void main(String[] args) {
//set特性 无序 唯一
Set<people> set = new HashSet<people>();
people p1 = new people(55,41,"zhuzhu");
people p2 = new people(115,61,"shasha");
people p3 = new people(515,43,"zuizui");
people p4 = new people(535,43,"luoluo");
people p5 = new people(15,55,"paopao");
people p6 = new people(15,55,"paopao");
//p6创建并不报错 应为set集合保证元素的唯一性依赖 equals() 和hascode()方法,在people类中没有重写该方法
//默认调用的是Object类中的equals和hascode方法比较的是地址值
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
set.add(p5);
set.add(p6);
System.out.println(set);
//遍历打印Set
System.out.println("迭代器的使用");
Iterator<people> cutpeople = set.iterator();
while (cutpeople.hasNext()){
people p = cutpeople.next();
System.out.println(p);
}
重写后的equals方法和hashcode方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
people people = (people) o;
return wight == people.wight && Height == people.Height && Objects.equals(name, people.name);
}
@Override
public int hashCode() {
return Objects.hash(wight, Height, name);
}
- Set中第二常用的集合:TreeSet
TreeSet是用二叉树结构实现的集合
特点:集合中的元素是有顺序得,不允许放入null,同样不能放入重复元素。
小知识点:TreeSet对对象进行排序时我们需要在类中实现comparable接口 重写compareTo方法实现treeset的对象排序
public static void main(String[] args) {
//treeset 的存储的数据类型必须一致
Set<Integer> treeset = new TreeSet<>();
treeset.add(99);
treeset.add(99);
treeset.add(3);
treeset.add(93);
treeset.add(99);
treeset.add(29);
treeset.add(99);
System.out.println(treeset);
Set<people> peopleSet = new TreeSet<>();
//通过people类中实现comparable接口 重写compareTo方法实现treeset的对象排序
//先按体重排序,如果相同按身高排序,后按名字排
people p1 = new people(55,41,"zhuzhu");
people p2 = new people(115,61,"shasha");
people p3 = new people(535,43,"zuizui");
people p4 = new people(535,93,"luoluo");
people p5 = new people(15,55,"paopao");
people p6 = new people(15,55,"paopao");
peopleSet.add(p1);
peopleSet.add(p2);
peopleSet.add(p3);
peopleSet.add(p4);
peopleSet.add(p5);
peopleSet.add(p6);
System.out.println(peopleSet);
System.out.println("迭代器的使用");
Iterator<people> cutpeople = peopleSet.iterator();
while (cutpeople.hasNext()){
people p = cutpeople.next();
System.out.println(p);
}
重写后的类中的ComparTo实现
class people implements Comparable<people> {
@Override
public int compareTo(people people) {//先按体重排序,如果相同按身高排序,后按名字排
int num = this.wight - people.wight;
int num2 = num == 0 ? this.Height-people.Height :num;
int num3 = num2 == 0 ? this.name.compareTo(people.name):num2;
return num3;
}
}
Map类
Map(映射)是一种容器,该容器中每个元素由两个部分组成:关键字、值(键值对)。由于容器中关键字不存在重复的元素(唯一),所以可以通过关键字找到对应的值。
方法 | 描述 |
---|---|
void clear() | 删除所有键值对 |
boolean containKey(Object key) | 判断当前对象中,是否包含关键字key,若包含,返回true;否则返回false |
Object get(Object k) | 返回当前映射中与关键字k匹配的值 |
Set keySet() | 返回当前映射中关键字的集合 |
Object put(Object k,Object v) | 增加一对映射 |
Object remove(Object k) | 删除以k为关键字的映射 |
Collection values() | 返回当前映射中的值的类集 |
HashMap
经常遇到需要使用键值对存储的场景,而HashMap是用得最多的一种键值对存储的集合。
特点:HashMap允许空键值,并且它是非线程安全的,所以插入、删除和定位元素会比较快。
Map<String,Student> map = new HashMap<>();
Student s1 = new Student("yaojiefan",92);
Student s2 = new Student("yao",22);
Student s3 = new Student("yaojiefa",32);
Student s4 = new Student("yaoji",24);
Student s5 = new Student("yaoj",52);
Student s6 = new Student("yaojiefan",212);
map.put("1",s1);
map.put("2",s2);
map.put("3",s3);
map.put("4",s4);
map.put("5",s5);
map.put("6",s6);
System.out.println(map);
TreeMap
TreeMap:不允许空键值。会按照key的值进行排序
public static void main(String[] args) {
Map<String,roomate> roomateMap = new TreeMap();
roomate r1 = new roomate(119,88);
roomate r2 = new roomate(19,88);
roomate r3 = new roomate(12,88);
roomate r4 = new roomate(196,88);
roomate r5 = new roomate(1,88);
roomate r6 = new roomate(129,88);
roomate r7 = new roomate(179,88);
roomateMap.put("jiwei",r1);
roomateMap.put("zhengzhenan",r2);
roomateMap.put("xiehaonian",r3);
roomateMap.put("yaojiefan sb",r4);
roomateMap.put("baifeirong",r5);
roomateMap.put("liumingzhou",r6);
roomateMap.put("lingjianmian",r7);
System.out.println(roomateMap);
Map的迭代器遍历Map对象
这里的迭代器遍历的是HashMap并且key为Int类型
Iterator<Integer> iterator = map.keySet().iterator();
while (iterator.hasNext()){
Integer I = iterator.next();
Student s = map.get(I);
System.out.println(I);
System.out.println(s);
}
for (Object obj : map.keySet()){
System.out.println(map.get(obj));
}
TreeMap和HashMap的对比
-
TreeMap是根据key进行排序的,它的排序和定位需要依赖比较器或覆写Comparable接口,也因此不需要key覆写hashCode方法和equals方法,就可以排除掉重复的key,而HashMap的key则需要通过覆写hashCode方法和equals方法来确保没有重复的key。
-
TreeMap的查询、插入、删除效率均没有HashMap高,一般只有要对key排序时才使用TreeMap。
-
TreeMap的key不能为null,而HashMap的key可以为null。
-
TreeMap不是同步的。如果多个线程同时访问一个映射,并且其中至少一个线程从结构上修改了该映射,则其必须 外部同步。
我在Map类中使用各种排序方式(尽我所能)
HashMap的排序
排序分别用set和list分别实现
list通过collections的sort()排序 sort 方法也需要重写
set通过重写CompareTo方法实现
创建Student类中的sort方法
//set排序
Set<Student> set = new TreeSet<>(values);//将值都存入Set中利用重写的CopareTo方法进行排序
for (Object obj : map.keySet()){
Student s = new Student(map.get(obj).getName(),map.get(obj).getAge()) ;
set.add(s);
}
System.out.println(set);
//list排序
List<Student> list = new ArrayList(values);
Collections.sort(list);//用工具类进行排序
Iterator iteratorAfter = map.keySet().iterator();
int j=0;
System.out.println("change after");
while (iteratorAfter.hasNext()) {
String k = (String) iteratorAfter.next();
map.put(k, list.get(j));//替换原来的排序
System.out.println(map.get(k).getName()+map.get(k).getAge());
j++;
}
重写的CompateTo方法(这里主要在类要继承Comparable类)
@Override
public int compareTo(Student o) {
return (int)(this.age-o.age);
}
TreeMap的排序大致相同但是TreeMap中存储的类型与HashMap中不相同所以我也提供给各位参考
Collection<roomate> values = roomateMap.values();
List<roomate> list = new ArrayList<>(values);
Collections.sort(list);
System.out.println(list);
Iterator iterator1 = roomateMap.keySet().iterator();
int j = 0;
while (iterator1.hasNext()){
String k = (String) iterator1.next();
roomateMap.put(k,list.get(j));
System.out.println(roomateMap.get(k).getAge()+":"+roomateMap.get(k).getWeight());
j++;
}
重写的CompateTo方法(这里主要在类要继承Comparable类)
@Override
public int compareTo(roomate o) {
return (int)(this.age-o.age);//如果需要按体重排序只需将age改为weight即可
}
全部程序
List的java程序
import java.util.*;
//list接口中的成员方法:
// public boolean add(E e)
// public E get(int index)
// public int size()
public class list {
public static void main(String[] args){
// 1.创建集合
List list = new ArrayList();
// 2.创建元素对象
Student s1 = new Student("jjj",12);
Student s2 = new Student("jjj",13);
Student s3 = new Student("jjj",14);
Student s4 = new Student("jjj",15);
// 3.将元素对象添加到集合对象中去
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
System.out.println(list);
//get方法
Object obj = list.get(2);
System.out.println("索引为2的方法为"+obj);
//size方法
System.out.println(list.size());
// 4.遍历集合
for (int i = 0 ; i <list.size();i++ ){
System.out.println(list.get(i));
}
}
}
Student类
class Student implements Comparable<Student>{
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student(String name) {
this.name = name;
}
private int age;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
public Student(){
}
@Override
public int compareTo(Student o) {
return (int)(this.age-o.age);
}
}
Set的java程序
hashset
import java.util.*;
public class collection_set {
public static void main(String[] args) {
//set特性 无序 唯一
Set<people> set = new HashSet<people>();
people p1 = new people(55,41,"zhuzhu");
people p2 = new people(115,61,"shasha");
people p3 = new people(515,43,"zuizui");
people p4 = new people(535,43,"luoluo");
people p5 = new people(15,55,"paopao");
people p6 = new people(15,55,"paopao");
//p6创建并不报错 应为set集合保证元素的唯一性依赖 equals() 和hascode()方法,在people类中没有重写该方法
//默认调用的是Object类中的equals和hascode方法比较的是地址值
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
set.add(p5);
set.add(p6);
System.out.println(set);
//遍历
System.out.println("迭代器的使用");
Iterator<people> cutpeople = set.iterator();
while (cutpeople.hasNext()){
people p = cutpeople.next();
System.out.println(p);
}
System.out.println("增强for循环的使用");
//增强for循环遍历set集合
for (people p : set){
System.out.println(p);
}
//排序
}
}
people类
class people implements Comparable<people> {
@Override
public int compareTo(people people) {
int num = this.wight - people.wight;
int num2 = num == 0 ? this.Height-people.Height :num;
int num3 = num2 == 0 ? this.name.compareTo(people.name):num2;
return num3;
}
@Override
public String toString() {
return "people{" +
"wight=" + wight +
", Height=" + Height +
", name='" + name + '\'' +
'}';
}
int wight,Height;
public people(int wight, int height, String name) {
this.wight = wight;
Height = height;
this.name = name;
}
public int getWight() {
return wight;
}
public void setWight(int wight) {
this.wight = wight;
}
public int getHeight() {
return Height;
}
public void setHeight(int height) {
Height = height;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
people people = (people) o;
return wight == people.wight && Height == people.Height && Objects.equals(name, people.name);
}
@Override
public int hashCode() {
return Objects.hash(wight, Height, name);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
String name;
}
TreeSet
import java.util.Collections;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class collection_Treeset {
public static void main(String[] args) {
//treeset 的存储的数据类型必须一致
Set<Integer> treeset = new TreeSet<>();
treeset.add(99);
treeset.add(99);
treeset.add(3);
treeset.add(93);
treeset.add(99);
treeset.add(29);
treeset.add(99);
System.out.println(treeset);
Set<people> peopleSet = new TreeSet<>();
//通过people类中实现comparable接口 重写compareTo方法实现treeset的对象排序
//先按体重排序,如果相同按身高排序,后按名字排
people p1 = new people(55,41,"zhuzhu");
people p2 = new people(115,61,"shasha");
people p3 = new people(535,43,"zuizui");
people p4 = new people(535,93,"luoluo");
people p5 = new people(15,55,"paopao");
people p6 = new people(15,55,"paopao");
peopleSet.add(p1);
peopleSet.add(p2);
peopleSet.add(p3);
peopleSet.add(p4);
peopleSet.add(p5);
peopleSet.add(p6);
System.out.println(peopleSet);
System.out.println("迭代器的使用");
Iterator<people> cutpeople = peopleSet.iterator();
while (cutpeople.hasNext()){
people p = cutpeople.next();
System.out.println(p);
}
}
}
Map的java程序
hashMap
import java.util.*;
public class collection_map {
public static void main(String[] args) {
Map<String,Student> map = new HashMap<>();
Student s1 = new Student("yaojiefan",92);
Student s2 = new Student("yao",22);
Student s3 = new Student("yaojiefa",32);
Student s4 = new Student("yaoji",24);
Student s5 = new Student("yaoj",52);
Student s6 = new Student("yaojiefan",212);
map.put("1",s1);
map.put("2",s2);
map.put("3",s3);
map.put("4",s4);
map.put("5",s5);
map.put("6",s6);
System.out.println(map);
// Iterator<Integer> iterator = map.keySet().iterator();
// while (iterator.hasNext()){
// Integer I = iterator.next();
// Student s = map.get(I);
// System.out.println(I);
// System.out.println(s);
// }
// for (Object obj : map.keySet()){
//
// System.out.println(map.get(obj));
//
// }
//排序
//排序分别用set和list分别实现
//list通过collections的sort()排序 sort 方法也需要重写
//set通过重写CompareTo方法实现
//创建Student类中的sort方法
Collection<Student> values = map.values();
//set排序
Set<Student> set = new TreeSet<>(values);
for (Object obj : map.keySet()){
Student s = new Student(map.get(obj).getName(),map.get(obj).getAge()) ;
set.add(s);
}
System.out.println(set);
//list排序
List<Student> list = new ArrayList(values);
Collections.sort(list);
Iterator iteratorAfter = map.keySet().iterator();
int j=0;
System.out.println("change after");
while (iteratorAfter.hasNext()) {
String k = (String) iteratorAfter.next();
map.put(k, list.get(j));//替换原来的排序
System.out.println(map.get(k).getName()+map.get(k).getAge());
j++;
}
for (Object obj : map.keySet()){
// System.out.println(map.get(obj));
// }
// Collections.sort(list);
// System.out.println(list);
}
}
TreeMap
import java.util.*;
public class collection_treemap {
public static void main(String[] args) {
Map<String,roomate> roomateMap = new TreeMap();
roomate r1 = new roomate(119,88);
roomate r2 = new roomate(19,88);
roomate r3 = new roomate(12,88);
roomate r4 = new roomate(196,88);
roomate r5 = new roomate(1,88);
roomate r6 = new roomate(129,88);
roomate r7 = new roomate(179,88);
roomateMap.put("jiwei",r1);
roomateMap.put("zhengzhenan",r2);
roomateMap.put("xiehaonian",r3);
roomateMap.put("yaojiefan sb",r4);
roomateMap.put("baifeirong",r5);
roomateMap.put("liumingzhou",r6);
roomateMap.put("lingjianmian",r7);
System.out.println(roomateMap);
// Iterator<String> iterator = roomateMap.keySet().iterator();
// while (iterator.hasNext()){
// Integer I = iterator.next();
// roomate roomate = roomateMap.get(I);
// System.out.println(I);
// System.out.println(roomate);
// }
Collection<roomate> values = roomateMap.values();
List<roomate> list = new ArrayList<>(values);
Collections.sort(list);
System.out.println(list);
Iterator iterator1 = roomateMap.keySet().iterator();
int j = 0;
while (iterator1.hasNext()){
String k = (String) iterator1.next();
roomateMap.put(k,list.get(j));
System.out.println(roomateMap.get(k).getAge()+":"+roomateMap.get(k).getWeight());
j++;
}
}
}
roommate类
class roomate implements Comparable<roomate> {
int age;
int weight;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
roomate roomate = (roomate) o;
return age == roomate.age && weight == roomate.weight;
}
@Override
public int hashCode() {
return Objects.hash(age, weight);
}
public roomate(int age, int weight) {
this.age = age;
this.weight = weight;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
@Override
public String toString() {
return "roomate{" +
"age=" + age +
", weight=" + weight +
'}';
}
@Override
public int compareTo(roomate o) {
return (int)(this.age-o.age);
}
}
Iterator代码
import java.util.ArrayList;
import java.util.*;
public class iterator {
public static void main(String[] args) {
List list = new ArrayList();
list.add(111);
list.add(222);
list.add(888);
//iterator的使用
//根据集合对象获取对象的迭代器对象
Iterator it = list.iterator();
//判断集合迭代器中是否有元素
while (it.hasNext()){
int i = (int) it.next();
System.out.println(i);
}
//如果有就获取元素
//列表迭代器能对列表中的元素进行增删
//但是必须使用列表迭代中的方法来实现
ListIterator lit = list.listIterator();
while (lit.hasNext()){
int b = (int) lit.next();
if (b==222){
lit.add(999);//使用了列表迭代器中的方法
}
System.out.println(b);
}System.out.println(list);
}
}