21. Map的主要实现类、HashMap、Collections工具类的使用、泛型使用

1. Map的主要实现类的区别

一、框架
/*  java.util.Map:存储一对一对的数据 (key-value) ----> 高中学的"函数" y = f(x)   y = 2 * x + 1 (x1,y1),(x2,y2)
*       |---- HashMap:Map的主要实现类;线程不安全、效率高;可以存储null的key和value;底层使用Entry[](或Node[])
*              |---- LinkedHashMap:HashMap的子类,可以实现按照添加的顺序实现遍历操作。对于频繁的遍历,建议使用此类。此类实际上是在HashMap结构的基础上,给每一个Node元素添加了一对指针,指向其前一个和后一个元素。
*       |---- TreeMap:可以按照添加的元素node的key的指定的属性的大小顺序实现遍历操作。使用红黑树实现的数据存储。
*       |---- Hashtable: Map的古老实现类;线程安全,效率低;不可以存储null的key或value;底层使用Entry[](或Node[])
*              |---- Properties:是Hashtable的子类,主要用来处理属性文件的。其key和value都是String类型。
*/
public class MapTest {

    @Test
    public void test1(){
        HashMap map = new HashMap();

        map.put("Tom",67);
        map.put(56,"AA");
        map.put(null,"AA");
        map.put(67,null);
        map.put("Tim",78);

        System.out.println(map);
    }

    @Test
    public void test2(){
        Hashtable map = new Hashtable();
//        map.put(null,123);
//        map.put("AA",null);
    }

    @Test
    public void test3(){
        HashMap map = new LinkedHashMap();

        map.put("Tom",67);
        map.put(56,"AA");
        map.put(null,"AA");
        map.put(67,null);
        map.put("Tim",78);

        System.out.println(map);
    }
}
  • TreeMap的测试(不带泛型)
import org.junit.Test;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;

public class TreeMapTest {

    @Test
    public void test1(){
        TreeMap map = new TreeMap();

        map.put("Tom",67);
        map.put("Jerry",76);
        map.put("Tonny",78);
        map.put("Jack",99);
        map.put("Jack",77);
        map.put("Alice",66);
//        map.put(87,66);

        Set entrySet = map.entrySet();
        Iterator iterator = entrySet.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }

    }
    //向TreeMap中添加key和value。要求key考虑:① 自然排序 或 ② 定制排序
    @Test
    public void test2(){
        TreeMap map = new TreeMap();

        User u1 = new User("Tom",34);
        User u2 = new User("Jerry",56);
        User u3 = new User("Jack",44);
        User u4 = new User("Alice",34);
        User u5 = new User("Rose",12);


        map.put(u1,89);
        map.put(u2,55);
        map.put(u3,34);
        map.put(u4,78);
        map.put(u5,88);

        Set entrySet = map.entrySet();
        Iterator iterator = entrySet.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

    @Test
    public void test3(){
        TreeMap map = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if(o1 instanceof User && o2 instanceof User){
                    User u1 = (User)o1;
                    User u2 = (User)o2;
                    return u1.getAge() - u2.getAge();
                }
                throw new RuntimeException("输入的类型不匹配");
            }
        });

        User u1 = new User("Tom",34);
        User u2 = new User("Jerry",56);
        User u3 = new User("Jack",44);
        User u4 = new User("Alice",34);
        User u5 = new User("Rose",12);

        map.put(u1,89);
        map.put(u2,55);
        map.put(u3,34);
        map.put(u4,78);
        map.put(u5,88);

        Set entrySet = map.entrySet();
        Iterator iterator = entrySet.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

public class User implements Comparable{
    private String name;
    private int age;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", 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;
    }

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

    public User() {
    }

    @Override
    public int compareTo(Object o) {
        if(o instanceof User){
            User u = (User)o;
            int ageValue= this.age - u.age;
            if(ageValue != 0){
                return ageValue;
            }
            return this.name.compareTo(u.name);
        }
        throw new RuntimeException("输入的类型不匹配");
    }
}
  • Properties的使用
import org.junit.Test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;

public class PropertiesTest {
    @Test
    public void test1() throws IOException {

        Properties pros = new Properties();
        FileInputStream fis = new FileInputStream(new File("info.properties"));
        pros.load(fis);

        String name = pros.getProperty("name");

        String pwd = pros.getProperty("password");

        System.out.println("name = " + name + ", pwd = " + pwd);

    }
}

在这里插入图片描述
内容为:

name=tom
password=abc123

面试题:

HashMap与Hashtable的区别

2. HashMap的底层实现原理

三、
/*   HashMap的底层源码分析:
*   jdk7的实现:
*   HashMap map = new HashMap(); //底层创建了一个长度为16的Entry[] table
*   ....
*   map.put(key1,value1);//添加一个key1-value1。 key1,value1封装为entry对象的两个属性,将entry对象放到数组table中。具体
*   应该放在table中的哪个位置呢?具体过程为:
*
*   1. 调用key1所属类的hashCode(),计算出key1的哈希值1,此哈希值1经过某个算法(hash())之后,得到哈希值2。此哈希值2就决定了key1-value1
*   封装为的entry1在数组table中的位置。假设此位置为索引i。
*   2. 如果table[i]位置上没有其他元素,则key1-value1封装的entry1直接添加成功。
*      如果table[i]位置上有其他元素,比如只有一对key2-value2封装的entry2。此时需要继续比较:
*          3.  比较key1和key2的哈希值,判断此哈希值是否相等:
*                 3.1 两个哈希值不相等,则认为key1和key2就不相同。则key1-value1封装的entry1添加成功。此时entry1和entry2以链表方式存储。
*                      jdk7中将entry1放到table[i]中,通过单向链表指向entry2
*                 3.2 两个哈希值相等,则需要继续调用key1所在类的equals()。
*                      3.2.1 如果equals()返回true,则认为key1和key2相同,则默认情况下,value1替换旧的value2
*                      3.2.2 如果equals()返回false,则认为key1和key2不相同。则key1-value1封装的entry1添加成功。此时entry1和entry2以链表方式存储。
*                         jdk7中将entry1放到table[i]中,通过单向链表指向entry2
*
*
*    在不断put添加的过程中,需要考虑扩容。默认扩容为原来的2倍。
*    什么时候扩容呢?默认情况下:数组的长度 * LOAD_FACTOR (默认值是0,75)
*
*
*  jdk8相较于jdk7的区别:
*  1. HashMap map = new HashMap();//底层没有创建长度为16的数组。
*  2. 底层数组的类型调整为Node[],而非Entry[]
*  3. 在首次调用put()方法时,底层才开始创建长度为16的数组
*  4. jdk7中索引i位置如果有多个元素,构成的链表的特点与jdk8中的不同。
*    “七上八下”
*  5. jdk8中如果数组索引i位置上的链表的长度大于8且数组的长度大于64时,此索引i位置上的元素都要调整为红黑树的数据结构进行存储。
*
*  说明:
*  1. 要求向HashMap中添加的key-value中key所在的类一定要重写:equals()\hashCode()
*
*  四、LinkedHashMap在HashMap的基础上,针对于Node增加了一对指针。证明:
*  在LinkedHashMap中定义了Entry结构如下:
*    static class Entry<K,V> extends HashMap.Node<K,V> {
*         Entry<K,V> before, after;
*         Entry(int hash, K key, V value, Node<K,V> next) {
*             super(hash, key, value, next);
*         }
*     }
*/

3. Collections工具类的使用

import org.junit.Test;
import java.lang.reflect.Array;
import java.util.*;

/**
 * Collections:操作集合(List\Set\Map)的工具类
 *
 *
 * Collection 和 Collections 区别?
 *
 */
public class CollectionsTest {

    /*
    reverse(List):反转 List 中元素的顺序
    shuffle(List):对 List 集合元素进行随机排序
    sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序  类似于:Arrays.sort(Object[])
    sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序  类似于:
Arrays.sort(Object[],Comparator)
    swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换

    Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
    Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
    Object min(Collection)
    Object min(Collection,Comparator)
    int frequency(Collection,Object):返回指定集合中指定元素的出现次数
    void copy(List dest,List src):将src中的内容复制到dest中
    boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值

     */
    @Test
    public void test1(){
        List list = new ArrayList();
        list.add(34);
        list.add("AA");
        list.add("AA");
        list.add("AA");
        list.add("CC");
        list.add(new Date());
        System.out.println(list);


//        Collections.reverse(list);
//        Collections.shuffle(list);
        Collections.swap(list,0,2);
        System.out.println(Collections.frequency(list, "AA"));

//        System.out.println(list);
    }
    @Test
    public void test2(){

        //void copy(List dest,List src):将src中的内容复制到dest中
        List list = new ArrayList();
        list.add(34);
        list.add("AA");
        list.add("AA");
        list.add("AA");
        list.add("CC");

        //错误的做法:
//        List dest = new ArrayList();
//        Collections.copy(dest,list);

//        System.out.println(dest);

        //正确的做法:
        List dest = Arrays.asList(new Object[list.size()]);
        Collections.copy(dest,list);
        System.out.println(dest);
    }
}

4. 泛型的理解

在这里插入图片描述
在这里插入图片描述

5. 泛型在集合中的使用

public class GenericTest {

    //1.在集合中使用泛型之前的例子
    @Test
    public void test1(){
        List list = new ArrayList();

        list.add(68);
        list.add(54);
        list.add(88);
        list.add(99);
        //问题一:添加数据时,没有类型的校验,导致数据添加不安全。
//        list.add("AA");


        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            Object obj = iterator.next();
            //问题二:可能导致类型转换异常。
            int score = (int) obj;
            System.out.println(score);
        }
    }

    //2. 在集合中使用泛型的例子
    //说明1:泛型参数赋的实参只能是引用数据类型。
    //说明2:在实例化集合类时,指名了泛型的参数类型(比如:Integer)。则集合类内部的属性、方法、构造器中凡是使用类的泛型的位置
    //  都替换为具体的泛型的参数类型(比如:Integer)。
    //说明3:在使用泛型类或泛型接口时,没有指明类或接口的泛型参数,则默认将此类型理解为Object类型。
    @Test
    public void test2(){
//        List<int> list = new ArrayList<int>();//报错
        ArrayList<Integer> list = new ArrayList<>();//类型推断

        list.add(67);
        list.add(65);
        list.add(78);
        //编译不通过
//        list.add("AA");

        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            //不会出现类型转换异常
            int score = iterator.next();
            System.out.println(score);
        }
    }
    @Test
    public void test3(){
//        Map<String,Integer> map = new HashMap<String,Integer>();
        Map<String,Integer> map = new HashMap<>();

        map.put("Tom",67);
        map.put("Jack",77);
        map.put("Rose",89);
//        map.put(45,"Jerry");//编译不通过

        //keySet():
        Set<String> keySet = map.keySet();
        Iterator<String> iterator = keySet.iterator();
        while(iterator.hasNext()){
            String key = iterator.next();
            System.out.println(key);
        }

        //values():
        Collection<Integer> values = map.values();

        //entrySet():
        Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator1 = entrySet.iterator();
        while(iterator1.hasNext()){
            Map.Entry<String,Integer> entry = iterator1.next();
            System.out.println(entry.getKey() + "--->" + entry.getValue());
        }
    }
}
  • 练习:涉及到在Comparable 和 Comparator 中使用泛型
import org.junit.Test;
import java.util.*;

public class TreeMapTest {

    //向TreeMap中添加key和value。要求key考虑:① 自然排序 或 ② 定制排序
    @Test
    public void test2() {
        TreeMap<User, Integer> map = new TreeMap<User, Integer>();

        User u1 = new User("Tom", 34);
        User u2 = new User("Jerry", 56);
        User u3 = new User("Jack", 44);
        User u4 = new User("Alice", 34);
        User u5 = new User("Rose", 12);

        map.put(u1, 89);
        map.put(u2, 55);
        map.put(u3, 34);
        map.put(u4, 78);
        map.put(u5, 88);

        Set<Map.Entry<User, Integer>> entrySet = map.entrySet();
        Iterator<Map.Entry<User, Integer>> iterator = entrySet.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
    @Test
    public void test3() {
        TreeMap<User, Integer> map = new TreeMap<>(new Comparator<User>() {
            @Override
            public int compare(User u1, User u2) {
                return u1.getAge() - u2.getAge();
            }
        });

        User u1 = new User("Tom", 34);
        User u2 = new User("Jerry", 56);
        User u3 = new User("Jack", 44);
        User u4 = new User("Alice", 34);
        User u5 = new User("Rose", 12);

        map.put(u1, 89);
        map.put(u2, 55);
        map.put(u3, 34);
        map.put(u4, 78);
        map.put(u5, 88);

        Set<Map.Entry<User, Integer>> entrySet = map.entrySet();
        Iterator<Map.Entry<User, Integer>> iterator = entrySet.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}


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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", 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;
    }

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

    public User() {
    }

    @Override
    public int compareTo(User u) {
        int ageValue = this.age - u.age;
        if (ageValue != 0) {
            return ageValue;
        }
        return this.name.compareTo(u.name);
    }
}

6. 自定义泛型类、泛型接口、泛型方法

  • 自定义泛型类、泛型方法
import java.util.ArrayList;

/**
 * 自定义的泛型类
 *
 */
public class Order<T> {

    String orderName;
    int orderId;
    T orderT; //在属性中可以使用类的泛型参数

    //在方法中使用类的泛型参数
    public void setT(T t){
        this.orderT = t;
    }

    public T getT(){
        return orderT;
    }

    public void show(T t){
        System.out.println(t);
    }

    //构造中使用类的泛型参数
    public Order(String orderName, int orderId, T orderT) {
        this.orderName = orderName;
        this.orderId = orderId;
        this.orderT = orderT;
    }

    public Order(T t){
        this.orderT = t;
    }
    public Order(){}


    //定义一个泛型方法
    //将数组中的数据复制到ArrayList中,并返回
    public static<E>  ArrayList<E> copyFromArrayToList(E[] arr){
        ArrayList<E> list = new ArrayList<E>();
        for(int i = 0;i < arr.length;i++){
            list.add(arr[i]);
        }
        return list;
    }
}
public class SubOrder<T> extends Order<T> {

    //功能的扩展
    public T info(T t){
        return null;
    }
}
public class SubOrder1 extends Order<String> { //SubOrder1不是泛型类

//    public static<E> ArrayList<E> copyFromArrayToList(E[] arr){
//        ArrayList<E> list = new ArrayList<E>();
//        for(int i = 0;i < arr.length;i++){
//            list.add(arr[i]);
//        }
//        return list;
//    }
}
  • 测试上述代码
import org.junit.Test;

import java.util.ArrayList;

/**
 * 自定义泛型类、泛型接口、泛型方法的使用
 *
 * 1. 在使用泛型类或泛型接口时,没有指明类或接口的泛型参数,则默认将此类型理解为Object类型。
 * 2. 在实例化泛型类时,指名了泛型的参数类型(比如:Integer)。则泛型类内部的属性、方法、构造器中凡是使用类的泛型的位置
 *   都替换为具体的泛型的参数类型(比如:Integer)。
 *
 * 3. 类的泛型参数在类实例化时,或子类继承泛型类时,指明类的泛型参数类型。
 *
 * 4. 泛型方法中的泛型参数是在方法调用时指名的。
 *
 * 5. 泛型类中,使用类的泛型的方法不能声明为static的。
 *    泛型方法,可以根据需要,声明为static的。
 *
 */
public class GenericTest1 {

    @Test
    public void test1(){
        Order order = new Order();

        order.show("TTT");

        Order<Integer> order1 = new Order<>();
        order1.show(123);
//        order1.setT("Abc");
    }

    @Test
    public void test2(){
        SubOrder<String> sub = new SubOrder<>();
        sub.show("AA");


        SubOrder1 sub1 = new SubOrder1();
        sub.show("AA");
    }

    //泛型方法使用的举例
    @Test
    public void test3(){
        Order<Integer> order1 = new Order<>();
        String[] arr = new String[]{"AA","BB","CC","DD"};
        ArrayList<String> list = order1.copyFromArrayToList(arr);
        System.out.println(list);
    }
}
  • 泛型类、泛型方法的使用举例
import java.util.List;

/**
 * DAO: data(base) access object
 *
 */
public class DAO<T> {

    //增
    public void add(T t){

    }
    //删
    public T delete(int id){
        return null;
    }

    //改
    public void update(int id,T data){

    }

    //查
    public T getInstance(int id){
        return null;
    }

    public List<T> getForList(){
        return null;
    }


    //泛型方法
    //比如:获取表中的条目数、表中字段的最大值、最小值(最大的生日)等
    public <E> E getValue(){

        return null;
    }
}
import java.sql.Date;

public class Customer {
    int id;
    String name;
    String email;
    Date birth;
}
public class CustomerDAO extends DAO<Customer> {
}

7. 泛型在继承上的体现

 /*
    泛型在继承上的体现

    情况1:A类是B类的父类,结论:G<A> 和 G<B> 不是子父类的关系,是并列关系的两个类

    情况2:A类是B类的父类,结论:A<G>是B<G>的父类,可以使用多态。
     */
    @Test
    public void test1(){
        Object obj;
        String str = new String();
        obj = str;//多态

        Object[] arr1;
        String[] arr2 = new String[10];
        arr1 = arr2;//动态

        List<Person> list1;
        List<Student>  list2 = new ArrayList<Student>();
//        list1 = list2; //编译不通过


        List<Object> list3;
        List<String> list4 = new ArrayList<String>();
//        list3 = list4;//编译不通过
        /*
        反证法:
        * 如果可以list3 = list4;
        * list3 = new ArrayList<String>();
        * list3.add(123);
        * */

//        String str1 = new Date(23423432L);

    }
    @Test
    public void test2(){
        List<String> list1;
        ArrayList<String> list2 = new ArrayList<>();
        list1 = list2;
    }

8. 通配符的使用

/*
    * 通配符的使用: ?
    *
    * A<?> 可以看做是A<G> 的父类。
    * */
    @Test
    public void test3(){
        ArrayList<String> list = new ArrayList<>();
//        method(list); //List<Object> list1 = list
        method1(list); //编译通过

        method2(list);

        ArrayList<Object> list1 = new ArrayList<>();
        method2(list1);
    }

    public void method(ArrayList<Object> list1){

    }
    public void method1(ArrayList<String> list1){

    }

    public void method2(ArrayList<?> list1){

    }

作业题1:

定义个泛型类 DAO<T>,在其中定义一个Map 成员变量,Map 的键为 String 类型,值为 T 类型。

分别创建以下方法:
public void save(String id,T entity): 保存 T 类型的对象到 Map 成员变量中
public T get(String id):从 map 中获取 id 对应的对象
public void update(String id,T entity):替换 map 中key为id的内容,改为 entity 对象
public List<T> list():返回 map 中存放的所有 T 对象
public void delete(String id):删除指定 id 对象

定义一个 User 类:
该类包含:private成员变量(int类型) id,age;(String 类型)name。

定义一个测试类:
创建 DAO 类的对象, 分别调用其 save、get、update、list、delete 方法来操作 User 对象,
使用 Junit 单元测试类进行测试。


public class User {
    private int id;
    private int age;
    private String name;

    public User() {
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (id != user.id) return false;
        if (age != user.age) return false;
        return name != null ? name.equals(user.name) : user.name == null;
    }

    @Override
    public int hashCode() {
        int result = id;
        result = 31 * result + age;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        return result;
    }
}
import sun.awt.SunHints;

import java.util.*;

public class DAO<T>{
    private Map<String,T> map = new HashMap<>();

    /*/*
     * @Author
     * @Description //TODO 保存 T 类型的对象到 Map 成员变量中
     * @Date 19:57 2021/3/30
     * @Param [id, entity]
     * @return void
     **/
    public void save(String id,T entity){
        map.put(id,entity);
    }
    /*/*
     * @Author 
     * @Description //TODO 从 map 中获取 id 对应的对象
     * @Date 19:58 2021/3/30
     * @Param [id] 
     * @return T 
     **/
    public T get(String id){
        T entity = map.get(id);
        return entity;
    }
    /*/*
     * @Author 
     * @Description //TODO 替换 map 中key为id的内容,改为 entity 对象
     * @Date 19:58 2021/3/30
     * @Param [id, entity] 
     * @return void 
     **/
    public void update(String id,T entity){
        if (map.containsKey(id)){
            map.put(id, entity);
        }
    }
    /*/*
     * @Author 
     * @Description //TODO 返回 map 中存放的所有 T 对象
     * @Date 19:58 2021/3/30
     * @Param []
     * @return java.util.List<T>
     **/
    public List<T> list(){
        //错误的
//        return (List<T>)map.values();
        //正确的
        ArrayList<T> list = new ArrayList<>();
        Collection<T> values = map.values();
        for (T t : values){
            list.add(t);
        }
        return list;
    }
    /*/*
     * @Author 
     * @Description //TODO 删除指定 id 对象
     * @Date 19:58 2021/3/30
     * @Param [id] 
     * @return void 
     **/
    public void delete(String id){
        map.remove(id);
    }
}

import org.junit.Test;

import java.util.List;

public class GenericTest {
    @Test
    public void test1(){
        DAO<User> dao = new DAO<>();
        dao.save("1001",new User(1001, 55, "张三"));
        dao.save("1002",new User(1002, 45, "李四"));
        dao.save("1003",new User(1003, 26, "王二麻子"));
        dao.save("1004",new User(1004, 37, "慕容六"));
        dao.save("1005",new User(1005, 62, "鬼脚七"));

        dao.update("1003",new User(1003,42,"老八"));
        System.out.println("*********************8");
        System.out.println(dao.get("1005"));
        System.out.println("*********************8");
        dao.delete("1004");

        List<User> list = dao.list();
//        System.out.println(list);
        list.forEach(System.out::println);
    }
    @Test
    public void test(){

    }
}

作业题2:

定义一个Employee类,
该类包含:private成员变量name,age,birthday,其中 birthday 为 MyDate 类的对象;
并为每一个属性定义 getter, setter 方法;
并重写 toString 方法输出 name, age, birthday

MyDate类包含:
private成员变量month,day,year;并为每一个属性定义 getter, setter 方法;

创建该类的 5 个对象,并把这些对象放入 TreeSet 集合中(TreeSet 需使用泛型来定义),
分别按以下两种方式对集合中的元素进行排序,并遍历输出:

1). 使Employee 继承 Comparable 接口,并按 name 排序
2). 创建 TreeSet 时传入 Comparator对象,按生日日期的先后排序。

package com.atguigu.exer2;

/**
 * @author 
 * @create 2021-03-29 15:50
 */
public class Employee implements Comparable<Employee>{
    private String name;
    private int age;
    private MyDate birthday;

    public Employee(String name, int age, MyDate birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }

    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;
    }

    public MyDate getBirthday() {
        return birthday;
    }

    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }
    @Override
    public int compareTo(Employee o) {
        return this.name.compareTo(o.name);
    }
}


public class MyDate<Employee> {
    private int year;
    private int month;
    private int day;

    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    @Override
    public String toString() {
        return "MyBirthday{"+year +
                "年," + month + "月,"+
                day + "日"+
                '}';
    }
}

import java.util.*;

public class TreeSetTest {
    public static void main(String[] args) {
        Employee e1 = new Employee("Tom", 25, new MyDate(1996,2,15));
        Employee e2 = new Employee("Alice", 26, new MyDate(1995,3,25));
        Employee e3 = new Employee("AliceSem", 26, new MyDate(1995,3,21));
        Employee e4 = new Employee("Rose", 27, new MyDate(1994,5,5));
        Employee e5 = new Employee("Jack", 24, new MyDate(1997,7,23));
        Employee e6 = new Employee("Zom", 23, new MyDate(1998,10,18));
        Employee e7 = new Employee("Zomer", 23, new MyDate(1998,11,18));

//        TreeSet<Employee> ts1 = new TreeSet<>();
//        ts1.add(e1);
//        ts1.add(e2);
//        ts1.add(e3);
//        ts1.add(e4);
//        ts1.add(e5);
//        //按name排序
//        Iterator iterator1 = ts1.iterator();
//        while (iterator1.hasNext()){
//            System.out.println(iterator1.next());
//        }

        //按出生日期排序
        Comparator<Employee> comparator = new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                if (o1.getBirthday().getYear()!= o2.getBirthday().getYear()){
                    return o1.getBirthday().getYear()-o2.getBirthday().getYear();
                }else if(o1.getBirthday().getMonth()!=o2.getBirthday().getMonth()){
                    return o1.getBirthday().getMonth() - o2.getBirthday().getMonth();
                }else{
                    return o1.getBirthday().getDay() - o2.getBirthday().getDay();
                }
            }
        };

        TreeSet<Employee> ts = new TreeSet<>(comparator);
        ts.add(e1);
        ts.add(e2);
        ts.add(e3);
        ts.add(e4);
        ts.add(e5);
        ts.add(e6);
        ts.add(e7);

        Iterator iterator = ts.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. `HashTable` 是 Java 中的一个哈希表实现,它继承自 `Dictionary` 实现了 `Map` 接口。`HashTable` 使用值对的方式存储数据,其中和值都是对象类型。 特点: - 线程安全:`HashTable` 是同步的,多线程环境下可以安全使用。 - 值不允许为 null:`HashTable` 不允许使用 null 作为或值,否则会抛出 NullPointerException。 - 哈希冲突解决:使用链表法解决哈希冲突,即在哈希表的每个位置上维护一个链表,当多个映射到同一个位置时,将它们链接在一起。 2. `Collections` 是 Java 中提供的工具类,提供了一系列静态方法,用于操作集合(`Collection`)和地图(`Map`)。其中一些常用方法包括: - `sort()`:对集合进行排序。 - `binarySearch()`:在有序集合中执行二分查找。 - `reverse()`:反转集合中的元素顺序。 - `shuffle()`:随机打乱集合中的元素顺序。 - `max()`、`min()`:返回集合中最大或最小的元素。 - `addAll()`:将多个元素添加到集合中。 - `frequency()`:计算指定元素在集合中出现的次数。 3. 泛型Java一个特性,它允许在编译时指定集合中存储的元素类型。通过使用泛型,可以在编译时检查类型安全性,并减少在运行时出现类型转换错误的可能性。 在集合中使用泛型的作用: - 提供类型安全性:泛型可以防止将错误类型的对象放入集合中。 - 简化代码:避免了手动进行类型转换,使代码更加清晰和简洁。 - 提高性能:避免了运行时的类型检查和类型转换。 4. `? extends T` 是泛型通配符中的一种形式,表示可以接受 T 类型及其子类型的参数。这种通配符限制了具体的类型范围,可以用于声明方法参数、变量或返回值。 例如,`List<? extends Number>` 表示一个存储 Number 或其子的列表,可以接受 Integer、Double 等具体类型的列表作为参数。 在使用 `? extends T` 通配符时,只能读取集合中的元素,不能添加新的元素到集合中。因为编译器无法确定具体的类型,只能确保从集合中读取的元素是 T 类型或其子类型。 5. `HashSet` 和 `HashMap` 都是 Java 中的集合。 `HashSet` 是基于哈希表实现的无序集合,它使用哈希函数来计算元素的存储位置,具有快速的插入、删除和查找操作。`HashSet` 不允许重复元素,当尝试向 `HashSet` 中插入重复元素时,插入操作会被忽略。 `HashMap` 是基于哈希表实现值对存储结构。它也使用哈希函数来计算的存储位置,可以通过来快速查找对应的值。`HashMap` 允许和值都为 null,并且允许重复的值。 在底层实现上,`HashSet` 实际上是通过一个 `HashMap` 来实现的,`HashSet` 的元素被存储为 `HashMap` 的,而值则是一个常量对象。 6. `BigDecimal` 是 Java 中用于精确表示和计算大数字的,提供了高精度的十进制计算。 `BigDecimal` 适用于需要高精度计算的场景,例如金融计算、货币计算等,可以避免使用浮点数导致的精度损失问题。 `BigDecimal` 的算术运算方法包括加法、减法、乘法、除法等,这些方法都是精确计算的,并且可以指定舍入模式来控制结果的精度和舍入方式。 例如,使用 `BigDecimal` 进行加法运算可以通过 `BigDecimal.add()` 方法实现: ```java BigDecimal num1 = new BigDecimal("10.25"); BigDecimal num2 = new BigDecimal("5.75"); BigDecimal sum = num1.add(num2); System.out.println(sum); // 输出: 16.00 ``` 在进行算术运算时,需要使用 `BigDecimal` 的方法进行操作,而不是直接使用运算符。这样可以确保精确的计算结果,并且可以灵活地控制舍入方式和精度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值