zhc-code

集合心得总结

为什么需要集合? 数组有不足:扩容麻烦 保存元素类型固定,同一数组无法改变 ------> 引出集合的概念

集合体系

集合分为两大类 一类是Collection(一组对象) 一类是Map(一组键值对)

底层维护实现关系

ArrayList/Vector实现Collection的List接口 底层是可变类型数组Object[]

LinkedList实现Collection的List接口 底层是双向链表

TreeSet实现了Collection的Set接口 底层是TreeMap

HashSet实现了Collection的Set接口 底层是HashMap

LinkedHashSet实现了Map接口 底层是LinkedHashMap

Hashtable实现了Map接口 底层Entry数组

HashMap实现了Map接口 底层是Node类型数组table 在JDK7中 实现形式是数组+链表 在JDK8以后 实现形式是数组+链表+红黑树

LinkedHashMap实现了Map接口 底层是数组+双向链表

选择

1.判断存储的类型

一组对象/一组键值对

2.一组对象【单列】

Collection接口

允许重复:List

 增删多:LinkedList【双向链表】

 改查多:ArrayList/Vector【可变类型Object数组】

不允许重复:Set 底层都是Map接口的实现类 而Map的Key不允许重复

 无序:HashSet

 排序:TreeSet

 插入和取出顺序一致: LinkedHashSet

3.一组键值对

Map接口 Key不允许重复 可以为空 Values可以重复 可以为null(多个) 一对K-V ---> 放在HashMap$Node Node实现了Entry接口 可以说一对K-V是一个Entry

    1. k-v 最后是HashMap$Node
    2. k-v为了方便程序员的遍历 还会创建 EntrySet 集合 该集合存放的元素的类型 Entry
       而一个Entry对象 就有k,v EntrySet<Entry<k,v>> 即 transicent Set<Map.Entry<k,v>> entrySet;
    3. entrySet 中 定义的类型是 Map.Entry 但是实际上存放的还是 HashMap$Node
       这是因为 static class Node<K,V> implements Map.Entry<K,V>
    4. 当把HashMap$Node 对象 存放到 entrySet 就方便我们的遍历
      K getKey(); V getValue();

键无序:HashMap

键排序:TreeMap

键插入和取出一致:LinkedHashMap

读取文件:Properties

剖析类

Vector 安全 效率低---ArrayList 不安全 效率高  !!!扩容机制

ArrayList扩容完整过程

TreeSet--TreeMap 强调定制排序(匿名内部类)

image
image

HashSet--HashMap线程不安全 !!!扩容机制

image
image
image
image
重写hashCode equals 来控制当什么条件相同时返回相同的hashCode 就不能添加元素

LinkedHashSet

加入顺序和取出元素/数据的顺序一致
LinkedHashSet 底层维护的是一个LinkedHashMap(是HashMap的子类)
LinkedHashSet 底层结构 (数组 + 双向链表)
添加第一次时 直接将 数组table 扩容到16 存放的结点类型 LinkedHashMap\(Entry 数组是 HashMap\)Node[] 存放的元素/数据是 dHashMap$EntrLinkey类型

	继承关系是在内部类完成
        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);
    }
}

HashTable

Hashtable底层
底层有一个数组 Hashtable$Entry[] 初始化大小为11 临界值 threshold 8 = 11 * 0.75 扩容 按照自己的扩容机制来进行即可 执行 方法 addEntry(hash, key, value, index); 添加 k-v 装到Entry 当 if (count >= threshold) 满足时 进行扩容 按照 int newCapacity = (oldCapacity << 1) + 1;

方法

Collection:

Collections工具类方法
image
image
image
image

List/Set方法

add

remove

contains

size

isEmpty

addAll

containsAll

removeAll

get List接口有 Set接口无

Map:

put

remove

get

size

isEmpty

clear

containsKey

遍历

Collection:

Iterator
image
增强for
image
普通for
image
Set接口实现类没有get方法 不能通过普通for遍历

Map

image
image
image

Collections类

image
image

集合关系密切-----> 泛型配合使用

传统方法 不能对加入集合的元素进行约束 可能存在安全隐患  
遍历的时候 需要类型转换 当数据量比较大的时候  会影响效率
![image](https://img2020.cnblogs.com/blog/2679279/202112/2679279-20211228152459833-2069123739.png)

经典题目
image

点击查看代码
public class Main {
    public static void main(String[] args) {

        ArrayList<Employee> employees = new ArrayList<>();
        Employee em1 = new Employee("zhc", 20000, new MyDate(2002, 7, 9));
        Employee em2 = new Employee("myh", 10000, new MyDate(2000, 4, 2));
        Employee em3 = new Employee("zhc", 5000, new MyDate(2001, 2, 5));
        employees.add(em2);
        employees.add(em1);
        employees.add(em3);

        System.out.println("排序前");
        System.out.println(employees);

        employees.sort(new Comparator<Employee>() {
            @Override
            public int compare(Employee emp1, Employee emp2) {
                //先按照 name 排序,如果 name 相同,则按生日日期的先后排序。【即:定制排序】
                //先对传入的参数进行验证
                if(!(emp1 instanceof Employee && emp2 instanceof Employee)) {
                    System.out.println("类型不正确..");
                    return 0;
                }
                //比较 name
                int i = emp1.getName().compareTo(emp2.getName());
                if(i != 0) {
                    return i;
                }

                return emp1.getBirthday().compareTo(emp2.getBirthday());//动态绑定到MyDate类的compareto方法
            }
        });

        System.out.println("排序后");
        System.out.println(employees);




        }
    }


@SuppressWarnings({"all"})
class Employee {
    private String name;
    private double sal;
    private MyDate birthday;

    public Employee(String name, double sal, MyDate birthday) {
        this.name = name;
        this.sal = sal;
        this.birthday = birthday;
    }

    public String getName() {
        return name;
    }

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

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    public MyDate getBirthday() {
        return birthday;
    }

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

    @Override
    public String toString() {
        return "\nEmployee{" +
                "name='" + name + '\'' +
                ", sal=" + sal +
                ", birthday=" + birthday +
                '}';
    }
}
	
	public class MyDate implements Comparable<MyDate> {

        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 getMonth() {
            return month;
        }

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

        public int getDay() {
            return day;
        }

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

        public int getYear() {
            return year;
        }

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

        @Override
        public String toString() {
            return "MyDate{" +
                    "month=" + month +
                    ", day=" + day +
                    ", year=" + year +
                    '}';
        }

        @Override
        public int compareTo(MyDate o) { //把对 year - month - day
            //如果year相同 就比较Month
            int yearMinus = year - o.getYear();
            if (yearMinus != 0) {
                return yearMinus;
            }
            //如果year相同 就比较month
            int monthMinus = month - o.getMonth();
            if (monthMinus != 0) {
                return monthMinus;
            }
            return day - o.getDay();
        }
    }



自定义泛型

自定义泛型类

·基本语法
class 类名 <T,R> {
成员
}
·细节
普通成员可以使用泛型 属性 方法
使用泛型的数组 不能初始化
静态方法中不能使用类的泛型
泛型类的类型 是在创建对象时确定的 因为创建对象时 需要指定类型
如果在创建对象时 没有指定类型 默认为Object

自定义泛型接口

·基本语法
interface 接口名 <T,R> {

}

·细节
接口中 成员是静态性质的 所以不能使用泛型
泛型接口的类型 在继承接口 或者 实现接口 是确定
没有指定类型 默认为Object

自定义泛型方法

·细节
泛型方法 可以定义在普通类 也可以定义在泛型类中
当泛型方法被调用时 类型会确定
public void eat(E e) 修饰符后没有 <T,R> eat 方法不是 泛型方法 而是使用了泛型
image

分类:

技术点:

相关文章: