Java集合框架的知识在Java基础阶段是极其重要的,我平时使用List、Set和Map集合时经常出错,常用方法还记不牢,
于是就编写这篇博客来完整的学习一下Java集合框架的知识,如有遗漏和错误,欢迎大家指出。
以下是我整理的大致Java集合框架内容,本篇博客就是围绕以下内容展开

注:本篇博客是根据B站Java集合框架的视频进行编写,视频原地址:【千锋】最新版 Java集合框架详解 通俗易懂

下面我们开始正式学习!!!

1.1、概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能

1.2、集合与数组区别:

  • 数组长度固定,集合长度不固定

  • 数组可以存储基本类型和引用类型,集合只能存储引用类型

1.3、位置:java.util*

Collection体系集合

  • 特点:代表一组任意类型的对象,无序、无下标、不能重复

  • 方法:

(1)Demo1保存字符串(重点关注迭代器iterator的使用)

  1. import java.util.ArrayList;
  2. import java.util.Collection;
  3. import java.util.Iterator;
  4. public class Demo1 {
  5. public static void main(String[] args) {
  6. //创建集合
  7. Collection collection = new ArrayList();
  8. //1.添加元素
  9. collection.add("香蕉");
  10. collection.add("苹果");
  11. collection.add("西瓜");
  12. System.out.println("元素个数:"+collection.size());
  13. System.out.println(collection);
  14. //2.删除元素
  15. //collection.remove("香蕉");
  16. //collection.clear();//清除
  17. //System.out.println("删除之后:"+collection.size());
  18. //3.遍历元素(重点)
  19. System.out.println("==========================");
  20. //方法一:增强for
  21. for (Object object:collection) {
  22. System.out.println(object);
  23. }
  24. //方法二:使用迭代器(迭代器专门用来遍历集合的一种方式)
  25. //iterator3个方法
  26. //hasNext();有没有下一个元素
  27. //next();l获取下一个元素
  28. //remove();删除当前元素
  29. System.out.println("==========================");
  30. Iterator iterator = collection.iterator();
  31. while (iterator.hasNext()) {
  32. String s = (String) iterator.next();
  33. System.out.println(s);
  34. // collection.remove(s);//不允许使用collection删除会引发并发修改错误,只能使用以下方法移除
  35. //iterator.remove();
  36. }
  37. System.out.println("元素个数:"+collection.size());
  38. //4.判断
  39. System.out.println(collection.contains("香蕉"));
  40. System.out.println(collection.isEmpty());
  41. }
  42. }

结果

(2)Demo2 保存学生信息

学生类

  1. //学生类
  2. public class Student {
  3. private String name;
  4. private int age;
  5. public String getName() {
  6. return name;
  7. }
  8. public void setName(String name) {
  9. this.name = name;
  10. }
  11. @Override
  12. public String toString() {
  13. return "Student{" +
  14. "name='" + name + '\'' +
  15. ", age=" + age +
  16. '}';
  17. }
  18. public int getAge() {
  19. return age;
  20. }
  21. public void setAge(int age) {
  22. this.age = age;
  23. }
  24. public Student() {
  25. }
  26. public Student(String name, int age) {
  27. this.name = name;
  28. this.age = age;
  29. }
  30. }
  1. import java.util.ArrayList;
  2. import java.util.Collection;
  3. import java.util.Iterator;
  4. // 保存学生信息
  5. public class Demo2 {
  6. public static void main(String[] args) {
  7. //新建Collection对象
  8. Collection collection = new ArrayList();
  9. Student s1 = new Student("张三",18);
  10. Student s2 = new Student("李四",19);
  11. Student s3 = new Student("王五",21);
  12. //1.添加数据
  13. collection.add(s1);
  14. collection.add(s2);
  15. collection.add(s3);
  16. System.out.println("元素个数:"+collection.size());
  17. System.out.println(collection.toString());
  18. //2.删除
  19. //collection.remove(s1);
  20. //System.out.println("删除之后:"+collection.size());
  21. //3.遍历
  22. //方法一:增强for
  23. System.out.println("========增强for===========");
  24. for (Object object:collection) {
  25. Student s = (Student) object;
  26. System.out.println(s.toString());
  27. }
  28. //方法二:使用迭代器(迭代器专门用来遍历集合的一种方式)
  29. System.out.println("========使用迭代器===========");
  30. Iterator iterator = collection.iterator();
  31. while (iterator.hasNext()) {
  32. Student s =(Student) iterator.next();
  33. }
  34. System.out.println(collection.toString());
  35. //4.判断
  36. System.out.println(collection.contains(s1));
  37. System.out.println(collection.isEmpty());
  38. }
  39. }

结果

  • 特点:有序,有下标,元素可以重复

  • 方法:

(1)Demo3

  1. public class Demo3 {
  2. public static void main(String[] args) {
  3. //先创建一个集合对象
  4. List list = new ArrayList();
  5. //1.添加元素
  6. list.add("唱");
  7. list.add("跳");
  8. list.add(0,"打篮球");//下标为0,放在第一位
  9. System.out.println("元素个数:"+list.size());
  10. System.out.println(list.toString());
  11. //2.删除元素
  12. // list.remove("唱");
  13. // list.remove(1);
  14. // System.out.println("元素个数:"+list.size());
  15. // System.out.println(list.toString());
  16. //3.遍历
  17. //方法一:使用for遍历
  18. System.out.println("===========for遍历===============");
  19. for (int i = 0; i < list.size(); i++) {
  20. System.out.println(list.get(i));
  21. }
  22. //方法二:使用增强for
  23. System.out.println("===========增强for===============");
  24. for (Object o:list) {
  25. System.out.println(o);
  26. }
  27. //方法三:使用迭代器
  28. System.out.println("===========迭代器===============");
  29. Iterator iterator = list.iterator();
  30. while (iterator.hasNext()) {
  31. System.out.println(iterator.next());
  32. }
  33. //方法四:使用列表迭代器
  34. //和迭代器的区别:可以向前或向后遍历,添加、删除、修改元素
  35. System.out.println("===========列表迭代器===============");
  36. ListIterator lit = list.listIterator();
  37. System.out.println("===========列表迭代器从前往后===============");
  38. while (lit.hasNext()) {
  39. System.out.println(lit.nextIndex()+":"+lit.next());
  40. }
  41. System.out.println("===========列表迭代器从后往前===============");
  42. while (lit.hasPrevious()) {
  43. System.out.println(lit.previousIndex()+":"+lit.previous());
  44. }
  45. System.out.println("==========================");
  46. //4.判断
  47. System.out.println(list.contains("rap"));
  48. System.out.println(list.isEmpty());
  49. //5.获取位置
  50. System.out.println(list.indexOf(2));
  51. }
  52. }

结果

(2)Demo4

  1. public class Demo4 {
  2. public static void main(String[] args) {
  3. //先创建一个集合对象
  4. List list = new ArrayList();
  5. //1.添加数字数据(自动装箱)
  6. list.add(17);
  7. list.add(27);
  8. list.add(37);
  9. list.add(47);
  10. list.add(57);
  11. System.out.println("元素个数:"+list.size());
  12. System.out.println(list.toString());
  13. //2.删除
  14. //注意这里是用脚标删除的,如果要用数字需要转成Object
  15. list.remove(0);
  16. //list.remove((Object) 17);
  17. //list.remove(new Integer(20));
  18. System.out.println("元素个数:"+list.size());
  19. System.out.println(list.toString());
  20. //3.补充方法subList:返回子集合,包含头不包含尾
  21. List subList = list.subList(1, 3);
  22. System.out.println(subList.toString());
  23. }
  24. }

结果:

  • ArrayList(重点):

    • 数组结构实现,查询快,增删慢
    • jdk1.2版本后加入,运行效率快,线程不安全
  • Vector:

    • 数组结构实现,查询快,增删慢
    • jdk1.0版本后加入,运行效率慢,线程安全
  • LinkedList:

    • 链表结构实现,增删快,查询慢
  1. /**
  2. * ArrayList的使用
  3. * 特点:有序,有下标,可以重复
  4. * 存储结构:数组,查找遍历速度快,增删慢
  5. */
  6. public class Demo5 {
  7. public static void main(String[] args) {
  8. //创建结合
  9. ArrayList arrayList = new ArrayList();
  10. //1.添加元素
  11. Student s1 = new Student("张三",20);
  12. Student s2 = new Student("李四",23);
  13. Student s3 = new Student("王五",19);
  14. arrayList.add(s1);
  15. arrayList.add(s2);
  16. arrayList.add(s3);
  17. System.out.println("元素个数:"+arrayList.size());
  18. System.out.println(arrayList.toString());
  19. //2.删除元素
  20. // arrayList.remove(0);
  21. // arrayList.remove(s2);
  22. arrayList.remove(new Student("ooof",12));//这样删除需要在Student中重写 equals(this == obj) 方法
  23. //3.遍历元素【重点】
  24. //使用迭代器
  25. System.out.println("========= 使用迭代器=========");
  26. Iterator it = arrayList.iterator();
  27. while (it.hasNext()) {
  28. Student s =(Student) it.next();
  29. System.out.println(s.toString());
  30. }
  31. //列表迭代器
  32. System.out.println("========= 列表迭代器=========");
  33. ListIterator lit = arrayList.listIterator();
  34. while (lit.hasNext()) {
  35. Student s =(Student) lit.next();
  36. System.out.println(s.toString());
  37. }
  38. System.out.println("========= 列表迭代器逆序=========");
  39. while (lit.hasPrevious()) {
  40. Student s =(Student) lit.previous();
  41. System.out.println(s.toString());
  42. }
  43. //4.判断
  44. System.out.println(arrayList.contains(new Student("王五",19)));
  45. System.out.println(arrayList.isEmpty());
  46. //5.查找
  47. System.out.println(arrayList.indexOf(new Student("王五",19)));
  48. }
  49. }

结果

源码分析

  • 默认容量:DEFAULT_CAPACITY = 10;

    • 注:如果没有向集合中添加任何元素,容量为0,添加一个元素之后,容量为10,每次扩容大小为原来的1.5 倍
  • 存放元素的数组:elementData

  • 实际元素个数:size

  • 添加元素:add()方法

    1. public boolean add(E e) {
    2. modCount++;
    3. add(e, elementData, size);
    4. return true;
    5. }
    6. public void ensureCapacity(int minCapacity) {
    7. if (minCapacity > elementData.length
    8. && !(elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
    9. && minCapacity <= DEFAULT_CAPACITY)) {
    10. modCount++;
    11. grow(minCapacity);
    12. }
    13. }
    14. //grow为核心
    15. private Object[] grow(int minCapacity) {
    16. int oldCapacity = elementData.length;
    17. if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
    18. int newCapacity = ArraysSupport.newLength(oldCapacity,
    19. minCapacity - oldCapacity, /* minimum growth */
    20. oldCapacity >> 1 /* preferred growth */);
    21. return elementData = Arrays.copyOf(elementData, newCapacity);
    22. } else {
    23. return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
    24. }
    25. }
  • 存储结构:数组

  • 创建集合 Vector vector = new Vector<>();

  • 增加(vector.add())、删除(vector.remove)、判断(vector.contains())同上

  • 遍历–枚举器遍历

  1. Enumeration en = vector.elements();
  2. while(en.hasMoreElements()){
  3. String s = (String)en.nextElement();
  4. sout(s);
  5. }
  1. /**
  2. *LinkedList的使用
  3. * 存储结构:双向链表
  4. * 可以重复添加
  5. */
  6. public class LinkedListTest1 {
  7. public static void main(String[] args) {
  8. //创建集合
  9. LinkedList linkedList = new LinkedList<>();
  10. //1.添加元素
  11. Student s1 = new Student("张三",20);
  12. Student s2 = new Student("李四",23);
  13. Student s3 = new Student("王五",19);
  14. linkedList.add(s1);
  15. linkedList.add(s2);
  16. linkedList.add(s3);
  17. System.out.println("元素个数:"+linkedList.size());
  18. System.out.println(linkedList.toString());
  19. //2.删除
  20. // linkedList.remove(s1);
  21. // System.out.println("删除之后:"+linkedList.size());
  22. //3.遍历
  23. //for遍历
  24. System.out.println("========for=====");
  25. for (int i = 0; i < linkedList.size(); i++) {
  26. System.out.println(linkedList.get(i));
  27. }
  28. System.out.println("========增强for=====");
  29. for (Object object:linkedList) {
  30. Student s = (Student) object;
  31. System.out.println(s.toString());
  32. }
  33. //迭代器
  34. System.out.println("========迭代器=====");
  35. Iterator it = linkedList.iterator();
  36. while (it.hasNext()) {
  37. Student s =(Student) it.next();
  38. System.out.println(s.toString());
  39. }
  40. System.out.println("========列表迭代器=====");
  41. ListIterator lit = linkedList.listIterator();
  42. while (lit.hasNext()) {
  43. Student s =(Student) lit.next();
  44. System.out.println(s.toString());
  45. }
  46. //4.判断
  47. System.out.println(linkedList.contains(s1));
  48. System.out.println(linkedList.isEmpty());
  49. //5.获取
  50. System.out.println(linkedList.indexOf(s1));
  51. }
  52. }

结果

源码分析

  1. transient int size = 0;//集合大小
  2. transient Node<E> first;//头结点
  3. transient Node<E> last;//尾节点
  4. public boolean add(E e) {
  5. linkLast(e);
  6. return true;
  7. }
  8. void linkLast(E e) {
  9. final Node<E> l = last;
  10. final Node<E> newNode = new Node<>(l, e, null);
  11. last = newNode;
  12. if (l == null)
  13. first = newNode;
  14. else
  15. l.next = newNode;
  16. size++;
  17. modCount++;
  18. }

  • ArrayList:数组,必须开辟连续空间,查询快,增删慢

  • LinkedList:双向链表,无需开辟连续空间,查询慢,增删快

泛型

  • Java泛型是JDK1.5中引入的一个新特性,其本质是參数化类型,把类型作为参数传递
  • 常见形式有泛型类、泛型接口、泛型方法
  • 语法:
    • <T,…>T称为类型占位符,表示一种引用类型。
  • 好处:
    • (1)提高代码的重用性
    • (2)防止类型转换异常,提高代码的安全性

泛型类

  1. /**
  2. * 泛型类
  3. * 语法:<T>
  4. * T表示类型占位符,表示一种引用类型,如果编写多个用逗号隔开
  5. * */
  6. public class MyGeneric<T> {
  7. //使用泛型T
  8. //1.创建变量,不能new T()因为T数据类型不确定
  9. T t;
  10. //2.创建一个方法,作为方法的参数
  11. public void show(T t){
  12. System.out.println(t);
  13. }
  14. //3.使用泛型作为方法的返回值
  15. public T getT(){
  16. return t;
  17. }
  18. }
  1. public class TestGeneric {
  2. public static void main(String[] args) {
  3. //使用泛型类创建对象
  4. //注意:1.泛型只能使用引用类型,2.不同泛型类型对象之间不能相互赋值
  5. MyGeneric<String> myGeneric = new MyGeneric<String>();
  6. myGeneric.t = "hello";
  7. myGeneric.show("你好");
  8. String t1 = myGeneric.getT();
  9. MyGeneric<Integer> myGeneric2 = new MyGeneric<Integer>();
  10. myGeneric2.t = 100;
  11. myGeneric2.show(200);
  12. Integer t2 = myGeneric2.getT();
  13. }
  14. }

结果:

泛型接口

  1. /**
  2. *泛型接口
  3. * 语法:接口名<T>
  4. * 注意:不能使用泛型来创建静态常量
  5. */
  6. public interface MyInterface<T> {
  7. String name = "张三";
  8. T server(T t);
  9. }

泛型接口实现有两种方法:

1、指定数据类型

  1. public class MyInterfaceImpl implements MyInterface<String>{
  2. @Override
  3. public String server(String t) {
  4. System.out.println(t);
  5. return t;
  6. }
  7. }

测试

  1. MyInterfaceImpl impl = new MyInterfaceImpl();
  2. impl.server("KKKKKKKK");

2、不指定数据类型

  1. public class MyInterfaceImpl2<T> implements MyInterface<T>{
  2. @Override
  3. public T server(T t) {
  4. System.out.println(t);
  5. return t;
  6. }

测试

  1. MyInterfaceImpl2 impl2 = new MyInterfaceImpl2();
  2. impl2.server(1000);

结果:

泛型方法

  1. /**
  2. *泛型方法
  3. * 语法:<T>返回值类型
  4. */
  5. public class MyGenericMethod {
  6. //泛型方法
  7. public <T> void show(T t){
  8. System.out.println("泛型方法"+t);
  9. }
  10. }

测试

  1. //泛型方法
  2. //不需要指定类型
  3. MyGenericMethod myGenericMethod = new MyGenericMethod();
  4. myGenericMethod.show("坤坤");
  5. myGenericMethod.show(200);
  6. myGenericMethod.show(3.1415);

结果:

泛型集合

  • 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致。
  • 特点:
    • 编译时即可检查,而非逐行时抛出异常。
    • 访问时,不必类型转换(拆箱)。
    • 不同泛型之间引用不能相互赋值,泛型不存在多态。
  1. public class DemoCollect {
  2. public static void main(String[] args) {
  3. ArrayList<String> arrayList = new ArrayList<String>();
  4. arrayList.add("xxx");
  5. arrayList.add("yyy");
  6. //指定String类型一下两条数据就不能添加进去
  7. // arrayList.add(10);
  8. // arrayList.add(20);
  9. for (String str:arrayList) {
  10. System.out.println(str);
  11. }
  12. ArrayList<Student> arrayList2 = new ArrayList<Student>();
  13. Student s1 = new Student("张三",18);
  14. Student s2 = new Student("李四",19);
  15. Student s3 = new Student("王五",21);
  16. arrayList2.add(s1);
  17. arrayList2.add(s2);
  18. arrayList2.add(s3);
  19. Iterator<Student> iterator = arrayList2.iterator();
  20. while (iterator.hasNext()) {
  21. Student s = iterator.next();
  22. System.out.println(s.toString());
  23. }
  24. }
  25. }

测试

  • 特点:无序,无下标,元素不可重复

  • 方法:全部继承自Collecton中的方法

  1. /**
  2. * 测试Set接口的使用
  3. * 特点:无序,无下标,元素不可重复
  4. */
  5. public class Demo1 {
  6. public static void main(String[] args) {
  7. //创建集合
  8. HashSet<String> set = new HashSet<>();
  9. //1.添加数据
  10. set.add("唱");
  11. set.add("跳");
  12. set.add("rap");
  13. //set.add("rap");重复添加不进去
  14. System.out.println("数据个数:"+set.size());
  15. System.out.println(set.toString());
  16. //2.删除
  17. set.remove("唱");
  18. System.out.println(set.toString());
  19. //3.遍历【重点】
  20. System.out.println("----增强for----");
  21. for (String str:set) {
  22. System.out.println(str);
  23. }
  24. System.out.println("----迭代器----");
  25. Iterator<String> iterator = set.iterator();
  26. while (iterator.hasNext()) {
  27. String s = iterator.next();
  28. System.out.println(s);
  29. }
  30. //4.判断
  31. System.out.println(set.contains("打篮球"));
  32. System.out.println(set.isEmpty());
  33. }
  34. }

测试:(注意这里添加的顺序与显示的顺序不同,因为无序)

  • HashSet【重点】:
    • 基于HashCode实现元素不重复。
    • 当存入元素的哈希码相同时,会调用equalsi进行确认,如结果为true,则拒绝后者存入。
  • TreeSet:
    • 基于排列顺序实现元素不重复。
    • 实现了SortedSet接口,对集合元素自动排序
    • 元素对象的类型必须实现Comparable接口,指定排序规则
    • 通过CompareTo方法确定是否为重复元素

HashSet的使用

(1)Demo2

  1. /***
  2. * HashSet集合的使用
  3. * 存储结构:哈希表(数组+链表+红黑树)
  4. */
  5. public class Demo2 {
  6. public static void main(String[] args) {
  7. //新建集合
  8. HashSet<String> hashSet = new HashSet<>();
  9. //1.添加元素
  10. hashSet.add("张三");
  11. hashSet.add("李四");
  12. hashSet.add("王五");
  13. hashSet.add("赵六");
  14. System.out.println("数据个数:"+hashSet.size());
  15. System.out.println(hashSet.toString());
  16. //2.删除
  17. hashSet.remove("张三");
  18. System.out.println("删除后数据个数:"+hashSet.size());
  19. System.out.println(hashSet.toString());
  20. //3.遍历
  21. System.out.println("----增强for----");
  22. for (String str:hashSet) {
  23. System.out.println(str);
  24. }
  25. System.out.println("----迭代器----");
  26. Iterator<String> iterator = hashSet.iterator();
  27. while (iterator.hasNext()) {
  28. String s = iterator.next();
  29. System.out.println(s);
  30. }
  31. //4.判断
  32. System.out.println(hashSet.contains("打篮球"));
  33. System.out.println(hashSet.isEmpty());
  34. }
  35. }

测试

(2)Demo3

person类

  1. public class Person {
  2. private String name;
  3. private int age;
  4. @Override
  5. public String toString() {
  6. return "Person{" +
  7. "name='" + name + '\'' +
  8. ", age=" + age +
  9. '}';
  10. }
  11. public String getName() {
  12. return name;
  13. }
  14. public void setName(String name) {
  15. this.name = name;
  16. }
  17. public int getAge() {
  18. return age;
  19. }
  20. public void setAge(int age) {
  21. this.age = age;
  22. }
  23. public Person() {
  24. }
  25. public Person(String name, int age) {
  26. this.name = name;
  27. this.age = age;
  28. }
  29. @Override
  30. public int hashCode() {
  31. int n1 = this.name.hashCode();
  32. int n2 = this.age;
  33. return n1+n2;
  34. }
  35. @Override
  36. public boolean equals(Object o) {
  37. if (this == o) return true;
  38. if (o == null || getClass() != o.getClass()) return false;
  39. if(o instanceof Person){
  40. Person person = (Person) o;
  41. if(this.name.equals(person.getName())&&this.age == person.getAge()){
  42. return true;
  43. }
  44. }
  45. return false;
  46. }
  47. }

Demo3

  1. /***
  2. * HashSet集合的使用
  3. * 存储结构:哈希表(数组+链表+红黑树)
  4. * 存储过程:
  5. * (1)根据hashcode计算保存位置,如果位置为空,则直接保存,如果不为空,执行第二步
  6. * (2)再执行equals方法,如果equals方法为true,则认为是重复,否则形成链表
  7. */
  8. public class Demo3 {
  9. public static void main(String[] args) {
  10. //新建集合
  11. HashSet<Person> persons = new HashSet<>();
  12. //1.添加元素
  13. Person p1 = new Person("乔纳森-乔斯达",20);
  14. Person p2 = new Person("乔瑟夫-乔斯达",19);
  15. Person p3 = new Person("空条承太郎",16);
  16. persons.add(p1);
  17. persons.add(p2);
  18. persons.add(p3);
  19. persons.add(new Person("空条承太郎",16));//重写hashCode()形成链表,再重写equals()就不能添加进来了
  20. System.out.println("元素个数:"+persons.size());
  21. System.out.println(persons.toString());
  22. //2.删除
  23. // persons.remove(p1);
  24. // persons.remove( new Person("乔纳森-乔斯达",20));//这时可以删除
  25. // System.out.println("删除之后:"+persons.toString());
  26. //3.遍历
  27. System.out.println("------for----");
  28. for (Person person:persons) {
  29. System.out.println(person.toString());
  30. }
  31. System.out.println("------迭代器----");
  32. Iterator<Person> iterator = persons.iterator();
  33. while (iterator.hasNext()) {
  34. System.out.println(iterator.next());
  35. }
  36. //4.判断
  37. System.out.println(persons.contains(p1));
  38. System.out.println(persons.isEmpty());
  39. }
  40. }

测试

(1)简单使用

  1. /**
  2. * TreeSet的使用
  3. * 存储结构:红黑树
  4. */
  5. public class Demo4 {
  6. public static void main(String[] args) {
  7. //创建集合
  8. TreeSet<String> treeSet = new TreeSet<>();
  9. //1.添加元素
  10. treeSet.add("xyz");
  11. treeSet.add("abc");
  12. treeSet.add("wer");
  13. treeSet.add("opq");
  14. System.out.println("元素个数:"+treeSet.size());
  15. System.out.println(treeSet.toString());
  16. //2.删除
  17. treeSet.remove("wer");
  18. System.out.println("删除后元素个数:"+treeSet.size());
  19. //3.遍历
  20. for (String str:treeSet) {
  21. System.out.println(str);
  22. }
  23. //4.判断
  24. System.out.println(treeSet.contains("opq"));
  25. }
  26. }

(2)保存Person类的数据

  1. /**
  2. * 使用TreeSet保存数据
  3. * 存储结构:红黑树
  4. * 要求:元素必须要实现Comparable接口,compareTo方法返回值为0,认为是重复元素
  5. */
  6. public class Demo5 {
  7. public static void main(String[] args) {
  8. //创建集合
  9. TreeSet<Person> persons = new TreeSet<>();
  10. //1.添加元素
  11. Person p1 = new Person("7乔纳森-乔斯达",20);
  12. Person p2 = new Person("5乔瑟夫-乔斯达",19);
  13. Person p3 = new Person("3东方仗助",16);
  14. Person p4 = new Person("3东方仗助",17);
  15. //直接添加不能添加进去,因为没有比较规则,即没有实现Comparable接口,需要在Person类中实现
  16. persons.add(p1);
  17. persons.add(p2);
  18. persons.add(p3);
  19. persons.add(p4);
  20. System.out.println("元素个数:"+persons.size());
  21. System.out.println(persons.toString());
  22. //2.删除
  23. persons.remove(p4);
  24. System.out.println("元素个数:"+persons.size());
  25. //3.遍历
  26. Iterator<Person> iterator = persons.iterator();
  27. while (iterator.hasNext()) {
  28. System.out.println(iterator.next());
  29. }
  30. //4.判断
  31. System.out.println(persons.contains(p1));
  32. }
  33. }

person类没有实现Comparable接口

person类实现Comparable接口

  1. public class Person implements Comparable<Person>{
  2. private String name;
  3. private int age;
  4. @Override
  5. public String toString() {
  6. return "Person{" +
  7. "name='" + name + '\'' +
  8. ", age=" + age +
  9. '}';
  10. }
  11. public String getName() {
  12. return name;
  13. }
  14. public void setName(String name) {
  15. this.name = name;
  16. }
  17. public int getAge() {
  18. return age;
  19. }
  20. public void setAge(int age) {
  21. this.age = age;
  22. }
  23. public Person() {
  24. }
  25. public Person(String name, int age) {
  26. this.name = name;
  27. this.age = age;
  28. }
  29. @Override
  30. public int hashCode() {
  31. int n1 = this.name.hashCode();
  32. int n2 = this.age;
  33. return n1+n2;
  34. }
  35. @Override
  36. public boolean equals(Object o) {
  37. if (this == o) return true;
  38. if (o == null || getClass() != o.getClass()) return false;
  39. if(o instanceof Person){
  40. Person person = (Person) o;
  41. if(this.name.equals(person.getName())&&this.age == person.getAge()){
  42. return true;
  43. }
  44. }
  45. return false;
  46. }
  47. //先按姓名比再按年龄比
  48. @Override
  49. public int compareTo(Person o) {
  50. int n1 = this.getName().compareTo(o.getName());
  51. int n2 = this.age - o.getAge();
  52. return n1==0?n2:n1;
  53. }
  54. }

测试

Comparator接口实现定制比较(不需要元素实现Comparable接口)

  1. /**
  2. * 使用TreeSet保存数据
  3. * 存储结构:红黑树
  4. * Comparator:实现定制比较(比较器)
  5. */
  6. public class Demo6 {
  7. public static void main(String[] args) {
  8. //创建集合,并指定比较规则(匿名内部类)
  9. TreeSet<Person> persons = new TreeSet<>(new Comparator<Person>() {
  10. @Override
  11. //先比较年龄再比较姓名
  12. public int compare(Person o1, Person o2) {
  13. int n1 = o1.getAge() - o2.getAge();
  14. int n2 = o1.getName().compareTo(o2.getName());
  15. return n1==0?n2:n1;
  16. }
  17. });
  18. //1.添加元素
  19. Person p1 = new Person("7乔纳森-乔斯达",20);
  20. Person p2 = new Person("5乔瑟夫-乔斯达",19);
  21. Person p3 = new Person("3东方仗助",16);
  22. Person p4 = new Person("4东方仗助",16);
  23. persons.add(p1);
  24. persons.add(p2);
  25. persons.add(p3);
  26. persons.add(p4);
  27. System.out.println(persons.toString());
  28. }
  29. }

测试

TreeSet案例

  1. /**
  2. * 要求:使用TreeSet集合实现字符串按照长度进行排序
  3. * Comparator实现定制比较
  4. *
  5. */
  6. public class Demo7 {
  7. public static void main(String[] args) {
  8. //创建集合并指定比较规则
  9. TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
  10. @Override
  11. public int compare(String o1, String o2) {
  12. int n1 = o1.length() - o2.length();
  13. int n2 = o1.compareTo(o2);
  14. return n1==0?n2:n1;
  15. }
  16. });
  17. //添加数据
  18. treeSet.add("hello");
  19. treeSet.add("hello,world");
  20. treeSet.add("dalian");
  21. treeSet.add("kunkun");
  22. treeSet.add("ikun");
  23. treeSet.add("cat");
  24. treeSet.add("beijing");
  25. System.out.println(treeSet.toString());
  26. }
  27. }

测试

Map体系集合

Map接口的特点:

  1. 用于存储任意键值对(Key-Value)

  2. 键:无序、无下标、不允许重复(唯一)

  3. 值:无序、无下标、允许重复

Map父接口

  • 特点:存储一对数据(Key-Value),无序、无下标,键不可重复,值可重复。

  • 方法:

    • V put(K key,V value) //将对象存入到集合中,关联键值。key重复则覆盖原值。
    • Object get(Object key)//根据键获取对应的值。
    • Set keySet() //返回所有key。
    • Collectionvalues()//返回包含所有值的Collection集合。
    • Set<Map.Entry<K,V>>//键值匹配的Set集合。

Map接口使用

  1. /**
  2. * Map接口的使用
  3. * 特点:(1)存储键值对(2)键不能重复,值可以重复(3)无序
  4. */
  5. public class Demo1 {
  6. public static void main(String[] args) {
  7. //创建Map集合
  8. Map<String, String> map = new HashMap<>();
  9. //1.添加元素
  10. map.put("tom","汤姆");
  11. map.put("jack","杰克");
  12. map.put("rose","露丝");
  13. //map.put("rose","ooo");value会被替换
  14. System.out.println("元素个数:"+map.size());
  15. System.out.println(map.toString());
  16. //2.删除
  17. // map.remove("tom");
  18. // System.out.println("删除后元素个数:"+map.size());
  19. //3.遍历
  20. //3.1使用keySet()
  21. System.out.println("-------keySet()遍历---------");
  22. //Set<String> keySet = map.keySet();
  23. for(String key:map.keySet()){
  24. System.out.println(key+"---"+map.get(key));
  25. }
  26. //3.2使用entrySet()
  27. System.out.println("-------entrySet()遍历---------");
  28. //Set<Map.Entry<String, String>> entries = map.entrySet();
  29. for (Map.Entry<String, String> entry: map.entrySet()) {
  30. System.out.println(entry.getKey()+"---"+entry.getValue());
  31. }
  32. //4.判断
  33. System.out.println(map.containsKey("jack"));
  34. System.out.println(map.containsValue("杰克"));
  35. }
  36. }

测试

keySet()与entrySet()

  • HashMap【重点】

    • jdk1.2版本,线程不安全,运行效率快
    • 允许使用null作为key或value
  • Hashtable【了解】

    • jdk1.0版本,线程安全,运行效率慢
    • 不允许使用null作为key或value
  • Properties

    • Hashtable的子类
    • 要求key和value都是String
    • 通常用于配置文件的读取
  • TreeMap

    • 实现了SortedMap接口(是Map的子接口),可以对key自动排序

Student类:

  1. public class Student {
  2. private String name;
  3. private int stuNo;
  4. public Student(String name, int stuNo) {
  5. this.name = name;
  6. this.stuNo = stuNo;
  7. }
  8. public Student() {
  9. }
  10. public String getName() {
  11. return name;
  12. }
  13. public void setName(String name) {
  14. this.name = name;
  15. }
  16. public int getStuNo() {
  17. return stuNo;
  18. }
  19. public void setStuNo(int stuNo) {
  20. this.stuNo = stuNo;
  21. }
  22. @Override
  23. public String toString() {
  24. return "Student{" +
  25. "name='" + name + '\'' +
  26. ", stuNo=" + stuNo +
  27. '}';
  28. }
  29. @Override
  30. public boolean equals(Object o) {
  31. if (this == o) return true;
  32. if (o == null || getClass() != o.getClass()) return false;
  33. Student student = (Student) o;
  34. return stuNo == student.stuNo && Objects.equals(name, student.name);
  35. }
  36. @Override
  37. public int hashCode() {
  38. return Objects.hash(name, stuNo);
  39. }
  40. }
  1. /**
  2. * HashMap集合的使用
  3. * 存储结构:哈希表(数组+链表+红黑树)
  4. * 存储过程:
  5. * (1)根据hashcode计算保存位置,如果位置为空,则直接保存,如果不为空,执行第二步
  6. * (2)再执行equals方法,如果equals方法为true,则认为是重复,否则形成链表
  7. */
  8. public class Demo2 {
  9. public static void main(String[] args) {
  10. //创建集合
  11. HashMap<Student,String> students = new HashMap<>();
  12. //1.添加元素
  13. Student s1 = new Student("张三",503);
  14. Student s2 = new Student("李四",509);
  15. Student s3 = new Student("王五",505);
  16. students.put(s1,"3班");
  17. students.put(s2,"7班");
  18. students.put(s3,"8班");
  19. //students.put(s3,"9班");键重复不能添加进去,但是值会覆盖
  20. students.put(new Student("张三",503),"3班");
  21. //会添加进去,new会在堆中新创建一个对象,如果要让它添加不进去,要在Student中重写hashcode和equals方法
  22. System.out.println("元素个数:"+students.size());
  23. System.out.println(students.toString());
  24. //2.删除
  25. // students.remove(s1);
  26. // System.out.println("删除之后:"+students.size());
  27. //3.遍历
  28. //keySet()
  29. System.out.println("-------keySet()遍历---------");
  30. for (Student key: students.keySet()) {
  31. System.out.println(key.toString()+"========="+students.get(key));
  32. }
  33. System.out.println("-------entrySet()遍历---------");
  34. for (Map.Entry<Student,String> entry: students.entrySet()) {
  35. System.out.println(entry.getKey()+"========="+entry.getValue());
  36. }
  37. //4.判断
  38. System.out.println(students.containsKey(s1));
  39. }
  40. }

测试

  1. static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 HashMap初始容量大小
  2. static final int MAXIMUM_CAPACITY = 1 << 30; // HashMap数组的最大容量
  3. static final float DEFAULT_LOAD_FACTOR = 0.75f; //默认加载因子为0.75(到75%时扩容)
  4. static final int TREEIFY_THRESHOLD = 8; //链表长度大于8时,调整成红黑树
  5. static final int UNTREEIFY_THRESHOLD = 6; //链表长度小于6时,调整成链表
  6. static final int MIN_TREEIFY_CAPACITY = 64; //链表长度大于8,并且集合元素个数大于等于64时,调整成红黑树
  7. transient Node<K,V>[] table; //哈希表中的数组
  8. transient int size; //元素个数

构造函数

  1. public HashMap() {
  2. this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
  3. }
  4. //刚创建HashMap之后没有添加元素 table=null,size=0 目的是节省空间

put方法(这个源码不太容易理解,大家尝试理解前每个方法的前几行就可以,有能力的可以深入研究)

  1. //put方法
  2. public V put(K key, V value) {
  3. return putVal(hash(key), key, value, false, true);
  4. }
  5. //putVal方法
  6. final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
  7. boolean evict) {
  8. Node<K,V>[] tab; Node<K,V> p; int n, i;
  9. if ((tab = table) == null || (n = tab.length) == 0)
  10. n = (tab = resize()).length;
  11. if ((p = tab[i = (n - 1) & hash]) == null)
  12. tab[i] = newNode(hash, key, value, null);
  13. else {
  14. Node<K,V> e; K k;
  15. if (p.hash == hash &&
  16. ((k = p.key) == key || (key != null && key.equals(k))))
  17. e = p;
  18. else if (p instanceof TreeNode)
  19. e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
  20. else {
  21. for (int binCount = 0; ; ++binCount) {
  22. if ((e = p.next) == null) {
  23. p.next = newNode(hash, key, value, null);
  24. if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
  25. treeifyBin(tab, hash);
  26. break;
  27. }
  28. if (e.hash == hash &&
  29. ((k = e.key) == key || (key != null && key.equals(k))))
  30. break;
  31. p = e;
  32. }
  33. }
  34. if (e != null) { // existing mapping for key
  35. V oldValue = e.value;
  36. if (!onlyIfAbsent || oldValue == null)
  37. e.value = value;
  38. afterNodeAccess(e);
  39. return oldValue;
  40. }
  41. }
  42. ++modCount;
  43. if (++size > threshold)
  44. resize();
  45. afterNodeInsertion(evict);
  46. return null;
  47. }
  48. // resize()方法
  49. final Node<K,V>[] resize() {
  50. Node<K,V>[] oldTab = table;
  51. int oldCap = (oldTab == null) ? 0 : oldTab.length;
  52. int oldThr = threshold;
  53. int newCap, newThr = 0;
  54. if (oldCap > 0) {
  55. if (oldCap >= MAXIMUM_CAPACITY) {
  56. threshold = Integer.MAX_VALUE;
  57. return oldTab;
  58. }
  59. else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
  60. oldCap >= DEFAULT_INITIAL_CAPACITY)
  61. newThr = oldThr << 1; // double threshold
  62. }
  63. else if (oldThr > 0) // initial capacity was placed in threshold
  64. newCap = oldThr;
  65. else { // zero initial threshold signifies using defaults
  66. newCap = DEFAULT_INITIAL_CAPACITY;
  67. newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
  68. }
  69. if (newThr == 0) {
  70. float ft = (float)newCap * loadFactor;
  71. newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
  72. (int)ft : Integer.MAX_VALUE);
  73. }
  74. threshold = newThr;
  75. @SuppressWarnings({"rawtypes","unchecked"})
  76. Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
  77. table = newTab;
  78. if (oldTab != null) {
  79. for (int j = 0; j < oldCap; ++j) {
  80. Node<K,V> e;
  81. if ((e = oldTab[j]) != null) {
  82. oldTab[j] = null;
  83. if (e.next == null)
  84. newTab[e.hash & (newCap - 1)] = e;
  85. else if (e instanceof TreeNode)
  86. ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
  87. else { // preserve order
  88. Node<K,V> loHead = null, loTail = null;
  89. Node<K,V> hiHead = null, hiTail = null;
  90. Node<K,V> next;
  91. do {
  92. next = e.next;
  93. if ((e.hash & oldCap) == 0) {
  94. if (loTail == null)
  95. loHead = e;
  96. else
  97. loTail.next = e;
  98. loTail = e;
  99. }
  100. else {
  101. if (hiTail == null)
  102. hiHead = e;
  103. else
  104. hiTail.next = e;
  105. hiTail = e;
  106. }
  107. } while ((e = next) != null);
  108. if (loTail != null) {
  109. loTail.next = null;
  110. newTab[j] = loHead;
  111. }
  112. if (hiTail != null) {
  113. hiTail.next = null;
  114. newTab[j + oldCap] = hiHead;
  115. }
  116. }
  117. }
  118. }
  119. }
  120. return newTab;
  121. }

HashMap源码简单总结

  1. HashMap刚创建时,table是null,为了节省空间,当添加第一个元素时,table容量调整为16
  2. 当元素个数大于阈值(16*0.75=12)时,会进行扩容,扩容后大小为原来的2倍,目的是减少调整元素的个数
  3. jdk1.8,当每个链表长度大于8,并且数组元素个数大于等于64时,会调整为红黑树,日的提高执行效率
  4. jdk1.8当链表长度小于6时,调整成链表
  5. jdk1.8以前,链表是头插入,jdk1.8以后是尾插入
  • 概念:集合工具类,定义了除存取以外的集合常用方法

  • 方法:

代码实现

  1. /**
  2. * Collections工具类的使用
  3. *
  4. */
  5. public class Demo4 {
  6. public static void main(String[] args) {
  7. List<Integer> list = new ArrayList<>();
  8. list.add(20);
  9. list.add(77);
  10. list.add(23);
  11. list.add(89);
  12. list.add(12);
  13. //sort排序
  14. System.out.println("排序前:"+list.toString());
  15. Collections.sort(list);//升默认序
  16. System.out.println("排序后:"+list.toString());
  17. //binarySearch二分查找, 找到为下标,没找到为负数
  18. int i = Collections.binarySearch(list, 12);
  19. System.out.println(i);
  20. //copy复制
  21. List<Integer> dest = new ArrayList<>();
  22. for (int j = 0; j < list.size(); j++) {
  23. dest.add(0);
  24. }
  25. Collections.copy(dest,list);
  26. System.out.println(dest.toString());
  27. //reverse反转
  28. Collections.reverse(list);
  29. System.out.println("反转之后:"+list);
  30. //shuffle 打乱
  31. Collections.shuffle(list);
  32. System.out.println("打乱之后:"+list);
  33. //补充:list 转成数组
  34. System.out.println("=======list 转成数组========");
  35. Integer[] integers = list.toArray(new Integer[0]);
  36. System.out.println(integers.length);
  37. System.out.println(Arrays.toString(integers));
  38. //数组转成集合
  39. System.out.println("=======数组转成集合========");
  40. String[] names = {"小明","小红","小王"};
  41. //集合是一个受限集合,不能添加和删除
  42. List<String> list1 = Arrays.asList(names);
  43. System.out.println(list1);
  44. //把基本类型数组转成集合时,需要修改为包装类
  45. Integer[] nums = {100,200,300,400,500};
  46. List<Integer> integerList = Arrays.asList(nums);
  47. System.out.println(integerList);
  48. }
  49. }

测试

最后,我们再看一下这张图回顾一下Java集合框架的重点和常用知识

  • 集合的概念:
    • 对象的容器,和数组类似,定义了对多个对象进行操作的常用方法。
  • List集合:
    • 有序、有下标、元素可以重复。(ArrayList、LinkedList、Vector)
  • Set集合:
    • 无序、无下标、元素不可重复。(HashSet、TreeSet)
  • Map集合:
    • 存储一对数据,无序、无下标,键不可重复,值可重复。(HashMap、HashTable、TreeMap)
  • Collections:
    • 集合工具类,定义了除了存取以外的集合常用方法。

到这里关于Java集合框架的知识就结束啦°꒰๑’ꀾ’๑꒱°,希望大家都有所收获,觉得文章还可以的话可以点个推荐支持博主啊

版权声明:本文为鹤鸣呦呦、、原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/qjds/p/16552897.html