集合框架(二)

4.Set子接口

  • 特点:无序、无下标、元素不可重复。
  • 方法:全部继承自Collection中的方法

set实现类

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

1.Set接口的使用

Set子接口的使用和之前的Collection父接口方法相同

package com.collection.Set;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/*
       测试Set接口的使用
       特点:无序、无下标、元素不能重复
 */
public class Demo01 {
    public static void main(String[] args) {
        //创建集合
        Set<String> set = new HashSet<>();
        //添加数据
        set.add("华为");
        set.add("小米");
        set.add("苹果");
        System.out.println("元素个数"+set.size());
        System.out.println(set.toString());
        //删除
        set.remove("小米");
        System.out.println(set.toString());
        //遍历【重点】
        for (String string : set) {
            System.out.println(string);
        }
        //迭代器
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

        //判断
        System.out.println(set.contains("苹果"));
        System.out.println(set.isEmpty());

    }
}

2.HashSet的使用

  • 增、删、遍历、判断和之前的方法一样
  • 存储结构:哈希表(数组+链表+红黑树)

例1:

package com.collection.Set;

import java.util.HashSet;
import java.util.Iterator;

/*
    HashSet集合的使用
    存储结构:哈希表(数组+链表+红黑树)
 */
public class Demo02 {
    public static void main(String[] args) {
        //新建集合
        HashSet<String> hashSet = new HashSet<>();
        //添加元素
        hashSet.add("刘德华");
        hashSet.add("梁朝伟");
        hashSet.add("林志玲");
        hashSet.add("周润发");
        System.out.println("元素个数"+hashSet.size());
        System.out.println(hashSet.toString());

        //删除数据
        hashSet.remove("刘德华");
        System.out.println(hashSet.size());

        //遍历
        for (String string : hashSet) {
            System.out.println(string);
        }
        Iterator<String> iterator = hashSet.iterator();
        while ((iterator.hasNext())) {
            System.out.println(iterator.next());
        }

        //判断
        System.out.println(hashSet.contains("林志玲"));
        System.out.println(hashSet.isEmpty());
    }
}
  • 存储过程(重复的依据)
    (1)根据hashcode计算保存的位置,如果此位置为空,则直接保存,如果不为空执行第二步
    (2)再执行equals方法,如果为true,则认为是重复,否则,形成链表

persons.add(new Person("梁朝伟", 24));//重写了hashcode和equals

//手写:
//    @Override
//    public int hashCode() {
//        int n1 = this.name.hashCode();
//        int n2 = this.age;
//        return n1+n2;
//    }
//
//    @Override
//    public boolean equals(Object obj) {
//        if(this == obj){
//            return true;
//        }
//        if(obj == null){
//            return false;
//        }
//        if(obj instanceof Person){
//            Person p = (Person)obj;
//            if(this.name.equals(p.getName())&&this.age == p.getAge()){
//                return true;
//            }
//        }
//        return false;
//    }

//idea 自动生成:
    @Override
    public boolean equals(Object object) {
        if (this == object) return true;
        if (object == null || getClass() != object.getClass()) return false;
        Person person = (Person) object;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

实例2:

package com.collection.Set;

import java.util.HashSet;
import java.util.Iterator;

/*
     存储过程(重复的依据)
     (1)根据hashcode计算保存的位置,如果此位置为空,则直接保存,如果不为空执行第二步
     (2)再执行equals方法,如果为true,则认为是重复,否则,形成链表
 */
public class Demo03 {
    public static void main(String[] args) {
        //创建集合
        HashSet<Person> persons =  new HashSet<>();
        //添加数据
        Person p1 = new Person("刘德华", 20);
        Person p2 = new Person("林志玲", 22);
        Person p3 = new Person("梁朝伟", 24);
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        //persons.add(p3);重复不能添加
        persons.add(new Person("梁朝伟", 24));//重写了hashcode和equals
        System.out.println("元素个数:"+persons.size());
        System.out.println(persons.toString());

        //删除
        persons.remove(p1);
        System.out.println(persons.size());
        //遍历
        for (Person person : persons) {
            System.out.println(person.toString());
        }
        Iterator<Person> it = persons.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }

        //4.判断
        System.out.println(persons.contains(p2));
        System.out.println(persons.isEmpty());

        //


    }
}

3.TreeSet的使用

  • 方法的使用与HashSet相同
  • 存储结构:红黑树 会有排序
package com.collection.Set;

import java.util.Iterator;
import java.util.TreeSet;

/*
    TreeSet的使用
    存储结构:红黑树
 */
public class Demo04 {
    public static void main(String[] args) {
        TreeSet<String> treeSet = new TreeSet<>();
        //添加
        treeSet.add("xyz");
        treeSet.add("abc");
        treeSet.add("hello");
        treeSet.add("xyz");
        System.out.println(treeSet.size());
        System.out.println(treeSet.toString());
        //删除
        treeSet.remove("abc");
        System.out.println(treeSet.size());
        //遍历
        for (String string : treeSet) {
            System.out.println(string);
        }
        Iterator<String> it = treeSet.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        //判断
        System.out.println(treeSet.contains("xyz"));
        System.out.println(treeSet.isEmpty());

    }
}

使用复杂类型:

  • 要求:元素必须要实现Comparable接口,compareTo()方法返回值为0,认为是重复元素
  • 添加元素时要重写compareTo()方法
package com.collection.Set;

import java.util.Objects;

public class Person implements Comparable<Person> {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    //先按姓名来比,然后再按年龄比
    @Override
    public int compareTo(Person o) {
        int n1 = this.getName().compareTo(o.getName());
        int n2 = this.age - o.getAge();
        return n1 == 0 ? n2 : n1;
    }

}

例2:

package com.collection.Set;

import java.util.Iterator;
import java.util.TreeSet;

/*
    使用TreeSet保证数据
    要求:元素必须要实现Comparable接口,compareTo()方法返回值为0,认为是重复元素
 */
public class Demo05 {
    public static void main(String[] args) {
        TreeSet<Person> persons = new TreeSet<>();
        //添加
        Person p1 = new Person("xyz", 20);
        Person p2 = new Person("hello", 22);
        Person p3 = new Person("zhangsan", 24);
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        System.out.println(persons.size());
        System.out.println(persons.toString());
        //删除
        persons.remove(p1);
        System.out.println(persons.size());
        //遍历
        for (Person person : persons) {
            System.out.println(person);
        }
        Iterator<Person> iterator = persons.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        //判断
        System.out.println(persons.contains(p2));
        System.out.println(persons.isEmpty());
    }
}

Compareor接口

​ Comparator:实现定制比较(比较器),就不需要连接Comparable接口了
​ Comparable:可比较的

package com.collection.Set;

import java.util.Comparator;
import java.util.TreeSet;

/*
    TreeSet的使用
    Comparator:实现定制比较(比较器)
    Comparable:可比较的
 */
public class Demo06 {
    public static void main(String[] args) {
        //创建集合,并指定比较规则
        TreeSet<Person> persons = new TreeSet<>(new Comparator<Person>() {//使用匿名内部类
            @Override
            public int compare(Person o1, Person o2) {
                int n1 = o1.getAge() - o2.getAge();
                int n2 = o1.getName().compareTo(o2.getName());
                return n1 == 0 ? n2 : n1;
            }
        });
        Person p1 = new Person("刘德华", 20);
        Person p2 = new Person("林志玲", 22);
        Person p3 = new Person("梁朝伟", 24);
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        System.out.println(persons.toString());
    }


}

TreeSet案例

使用TreeSet集合实现字符串按照长度进行排序:

package com.collection.Set;

import java.util.Comparator;
import java.util.TreeSet;

/*
    使用TreeSet集合实现字符串按照长度进行排序
    helloworld   zhang  lisi  wangwu   beijing   xian   nanjing
    Comparator接口实现定制比较
 */
public class Demo07 {
    public static void main(String[] args) {
        //创建集合,并指定比较规则
        TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                int n1 = o1.length() - o2.length();
                int n2 = o1.compareTo(o2);
                return n1 == 0?n2:n1;
            }
        });
        //添加数据
        treeSet.add("helloworld");
        treeSet.add("zhang");
        treeSet.add("lisi");
        treeSet.add("beijing");
        treeSet.add("xian");
        treeSet.add("nanjing");
        System.out.println(treeSet.size());
        System.out.println(treeSet.toString());

    }
}

5.Map集合


)

  • Map接口的特点
    • 用于存储任意键值对(Key--Value)
    • 键:无序、无下标、不允许重复(唯一)
    • 值:无序、无下标、允许重复

1.Map父接口

  • 特点:存储一对数据(Key--Value),无序、无下标、键不可重复,值可以重复
  • 方法:
    • V put(K key,V value):将对象存入集合中,关联键值。key重复则覆盖原来的值
    • Object get(Object key):根据键获取对应的值。
    • keySet:返回所有的key
    • Collection values():返回包含所有值的Collection集合
    • Set<Map.Entry<K,V>>:键值匹配的Set集合

2.Map接口的基本使用

package com.collection.Map;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/*
    Map接口的使用
    特点:(1)存储键值对(2)键不能重复,值可以重复(3)无序
 */
public class Demo01 {
    public static void main(String[] args) {
        //创建Map集合
        Map<String,String> map = new HashMap<>();
        //添加元素
        map.put("cn","中国");
        map.put("uk","英国");
        map.put("usa","美国");
        map.put("cn","zhongguo");//key重复则覆盖原来的值
        System.out.println(map.size());//元素个数
        System.out.println(map.toString());
        //删除
//        map.remove("usa");
//        System.out.println("删除之后:"+map.size());

        //遍历
        //3.1.使用keySet();
        //Set<String> keyset = map.keySet();
        for (String key : map.keySet()) {
            System.out.println(key+"-------"+map.get(key));
        }
        //3.2.使用entrySet()方法(效率更高)
        //Set<Map.Entry<String, String>> entryset  = map.entrySet();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            System.out.println(entry.getKey()+"-------"+entry.getValue());
        }

        //4.判断
        System.out.println(map.containsKey("cn"));
        System.out.println(map.containsValue("zhongguo"));

    }

}

3.Map集合的实现类

  • HashMap【重点】
    • JDK1.2版本,线程不安全,运行效率快;允许用null作为key或者是value
  • Hashtable(了解)
    • jdk1.0版本,线程安全,运行效率慢;不允许null作为key或是value
  • Properties:
    • Hashtable的子类,要求key和value都是String。通常用于配置文件的读取
  • TreeMap
    • 实现了SortedMap接口(是Map的子接口),可以对key自动排序

HashMap的使用

package com.collection.Map;

import java.util.HashMap;
import java.util.Map;

/*
    HashMap集合的使用
    存储接结构:哈希表(数组+链表+红黑树)
    使用key可用hashcode和equals作为重复
 */
public class Demo02 {
    public static void main(String[] args) {
        HashMap<Student, String> students = new HashMap<>();
        //刚创建hashMap之后没有添加元素table=null  size=0 目的是节省空间
        //添加
        Student s1 = new Student("孙悟空", 100);
        Student s2 = new Student("猪八戒", 101);
        Student s3 = new Student("沙和尚", 102);
        students.put(s1,"北京");
        students.put(s2,"上海");
        students.put(s3,"杭州");
        students.put(new Student("沙和尚", 102),"浙江");//重写hashcode 和 equals
        System.out.println(students.size());
        System.out.println(students.toString());
        //删除
        students.remove(s1);
        System.out.println("删除之后"+students.size());
        //遍历
        //使用keySet();
        for (Student key: students.keySet()) {
            System.out.println(key.toString()+"--------"+students.get(key));
        }
        //使用entrySet()
        for (Map.Entry<Student, String> entry : students.entrySet()) {
            System.out.println(entry.getKey()+"--------"+entry.getValue());
        }
        //判断
        System.out.println(students.containsKey(new Student("猪八戒", 101)));
        System.out.println(students.containsValue("杭州"));
    }
}

源码分析:

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; //hashMap初始容量大小
static final int MAXIMUM_CAPACITY = 1 << 30; //hashMap 的数组最大容量
static final float DEFAULT_LOAD_FACTOR = 0.75f; //默认加载因子
static final int TREEIFY_THRESHOLD = 8; //jdk1.8 当链表长度大于8时,调整成红黑树
static final int UNTREEIFY_THRESHOLD = 6; //jdk1.8 当链表长度小于6时,调整成链表
static final int MIN_TREEIFY_CAPACITY = 64; //jdk1.8 当链表长度大于8时,并且集合元素个数大于等于64时,跳转成红黑树
transient Node<K,V>[] table; //哈希表中的数组 

源编总结:

  • HashMap刚创建时,table是null,为了节省空间,当添加第一个元素时,table容量调整为16.
  • 当元素个数大于阈值(16*0.75=12)时,会进行扩容,扩容后大小为原来的2倍。目的是减少调整元素的个数
  • jdk1.8 当每个链表长度大于8,并且数组元素个数大于等于64时,会调整成红黑树,目的是提高执行效率
  • jdk1.8 当链表长度小于6时,调整成链表
  • jdk1.8以前,链表是头插入,jdk1.8以后是尾插

TreeMap的使用

package com.collection.Map;

import java.util.Map;
import java.util.TreeMap;

/*
    TreeMap的使用
    存储结构:红黑树
 */
public class Demo03 {
    public static void main(String[] args) {
        //新建集合(也可以使用定制比较)
        TreeMap<Student, String> treeMap = new TreeMap<Student,String>();
        //1.添加元素
        Student s1 = new Student("孙悟空", 100);
        Student s2 = new Student("猪八戒", 101);
        Student s3 = new Student("沙和尚", 102);
        //添加需要重写compareTo
        treeMap.put(s1,"北京");
        treeMap.put(s2,"上海");
        treeMap.put(s3,"深圳");
        treeMap.put(new Student("沙和尚", 102),"南京");
        System.out.println("元素个数:"+treeMap.size());
        System.out.println(treeMap.toString());
        //删除
//        treeMap.remove(s3);
//        System.out.println(treeMap.size());
        //遍历
        //使用keySet
        for (Student key : treeMap.keySet()) {
            System.out.println(key+"---------"+treeMap.get(key));
        }
        //使用entrySet
        for (Map.Entry<Student, String> entry : treeMap.entrySet()) {
            System.out.println(entry.getKey()+"---------"+entry.getValue());
        }
        //判断
        System.out.println(treeMap.containsKey(s3));
        System.out.println(treeMap.containsValue("南京"));

    }

}

6.Collections工具类

  • 概念:集合工具类,定义了除了存取以外的集合常用的方法
  • 方法:
    • public static void reverse(List<?> list ):反转集合中元素的顺序
    • public static void shuffle(List<?> list):随机重置集合元素的顺序
    • public static void sort(List<?> list):升序排序(元素类型必须实现Comparable接口)
package com.collection.Collectiontool;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/*
    演示Collection工具类的使用
 */
public class Demo01 {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        list.add(20);
        list.add(5);
        list.add(12);
        list.add(30);
        list.add(6);
        //sort 排序
        System.out.println("排序前:"+list.toString());
        Collections.sort(list);
        System.out.println("排序后:"+list.toString());

        //binarySearch 二分查找
        int i = Collections.binarySearch(list, 12);
        System.out.println(i);

        //copy复制
        List<Integer> dest = new ArrayList<>();//在无数据时size为0,故要先添加一个元素
        for (int k=0; k< list.size();k++){
            dest.add(0);
        }
        Collections.copy(dest, list);//要保证集合大小相等才行
        System.out.println(dest.toString());

        //reverse反转
        Collections.reverse(list);
        System.out.println("反转之后"+list.toString());

        //shuffle 打乱
        Collections.shuffle(list);
        System.out.println("打乱之后:"+list.toString());

        //补充:list转成数组
        Integer[] array = list.toArray(new Integer[0]);//当list中的长度小于所设置的长度,其数组长度与list长度相等
        System.out.println(Arrays.toString(array));

        //数组转成集合
        String[] name = {"张三","李四","王五"};
        //集合是一个受限集合,不能添加和删除 因为数组的大小已经固定。
        List<String> list2 = Arrays.asList(name);
        System.out.println(list2.toString());
        //把基本类型数组转换为集合时,需要修改为包装类型
        Integer[] num2 = {100,200,300,400};
        List<Integer> list3 = Arrays.asList(num2);
        System.out.println(list3.toString());
    }
}
posted @ 2025-02-11 20:06  昼冷夜欢  阅读(21)  评论(0)    收藏  举报