8集合
集合
1 java集合框架概述
 数组在存储多个数据方面的特点
- 一旦初始化以后,长度就确定了
- 比如String[] arr需要指明类型,一旦定义好,元素类型就确定了
 数组在存储多个数据方面的缺点
- 一旦初始化以后,长度就不可修改了
- 数组中提供的方法有限,对于添加,删除,插入等操作非常不便,效率不高
- 获取数组中实际元素的个数的需求,数组没有现成的方法可用
- 数组存储数据的特点:有序,可重复 对于无序,不重复需求数组不能满足
 集合框架
 1.1 Colection接口:单列集合,用来存储一个个的对象
- List接口:存储有序的可重复的数据,动态数组(ArrayList LinkedList Vector)
- Set接口:存储无序的不可重复的数据,高中讲的集合(HashSet LinkedHashSet TreeSet)
 1.2 Map接口:双列集合,用于存储一对一对的对象,高中函数y=f(x)
- HashMap LinkedHashMap TreeMap Hashtable Properties


2 Collection接口中的方法使用
 2.1 常用方法
- 
add(Object e):将元素e添加到集合coll中 
- 
size() :获取添加元素的个数 
- 
addAll(Collection col1):将col1中的元素添加到当前集合中 
- 
clear():清空当前集合的元素 
- 
isEmpty():判断当前集合是否为空 
- 
contains(Object obj):判断集合中是否存在obj 
- 
containsall(collection c2):判断c2是否都在当前集合中 
- 
remove(object obj):删除集合中的obj元素 
- 
removeAll(Collection c2):从当前集合中移除c2包含元素 
- 
retainAll(collection c2):获取当前集合和c2集合的交集 
- 
equals(Object obj): 判断是否相等,是否需要按顺序得看具体容器 
- 
hashcode():返回当前对象的哈希值 
- 
toArray():集合-->数组 
- 
asList():数组-->集合 调用Arrays的静态方法 
- 
iterator():返回Iterator接口的实例 用于遍历集合元素(具体在2.2展开) 
- 
注意:向collection接口的实现类的对象中添加数据obj需要重写equals方法(因为涉及到值的比较和地址的比较 重写之后变成值的比较 这样在有些方法中可以更好的表现语义)(涉及到的方法有:remove(), removeAll(), retainAll(), equals(), contains(), containsAll(), hashcode() ) 
//collection接口的实现类
class 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 +
                '}';
    }
    //注意这里重写equals()方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age && Objects.equals(name, person.name);
    }
}
public class G36Collection {
    @Test
    public void test1(){
        Collection col=new ArrayList();
        //add(Object e)将元素e添加到集合coll中
        col.add("aa");
        col.add("bb");
        col.add(123);//自动装箱
        col.add(new Date());
        //size() 获取添加元素的个数
        System.out.println(col.size());//4
        //addAll(Collection col1)将col1中的元素添加到当前集合中
        Collection col1=new ArrayList();
        col1.add(456);
        col1.add("Cc");
        col.addAll(col1);
        System.out.println(col);
        //[aa, bb, 123, Thu Sep 02 14:44:13 CST 2021, 456, Cc]
        //clear():清空当前集合的元素
        col.clear();
        //isEmpty():判断当前集合是否为空
        System.out.println(col.isEmpty());//true
    }
    @Test
    public void test2(){
 
        Collection col1=new ArrayList();
        col1.add(123);
        col1.add(456);
        col1.add(new String("tom"));
        col1.add(false);
        col1.add(new Person("fao",18));
        
       //contains(Object obj)
        boolean contains=col1.contains(123);
        System.out.println(contains);//true
        System.out.println(col1.contains(new String("tom")));
        //判断内容 因为string重写过equals 所以为true
        System.out.println(col1.contains(new Person("fao",18)));
        //自定义类没重写就是false 但上面我们自己重写过 所以这里还是ture
        //containsall(collection c2) 判断c2是否都在当前集合中
        Collection col2=new ArrayList();
        System.out.println(col1.containsAll(col2));//true
    }
    @Test
    public void test3(){
     
        Collection col1=new ArrayList();
        col1.add(123);
        col1.add(456);
        col1.add(new String("tom"));
        col1.add(false);
        col1.add(new Person("fao",28));
        
  	    //remove(object obj)
        col1.remove(123);
        System.out.println(col1);//重写equals以后才能移除那些值一样的对象
        //[456, tom, false, Person{name='fao', age=28}]
        //removeAll(Collection c2) 从当前集合中移除c2包含元素
        Collection col2=new ArrayList();
        col2.add(123);
        col2.add(222);
        col2.add(new String("tom"));
        col2.add(new Person("fao",28));
        col1.removeAll(col2);
        System.out.println();
        System.out.println(col1);//[456, false]
        //retainAll(collection c2) 获取当前集合和c2集合的交集
        Collection col3=new ArrayList();
        col3.add(456);
        col1.retainAll(col3);
        System.out.println();
        System.out.println(col1);//[456]
        //equals(Object obj) 判断是否相等 顺序得看具体容器
        System.out.println();
        System.out.println(col1.equals(col3));
        //true 因为是有序队列,换了顺序序就是false
    }
    @Test
    public void test4(){
        Collection col1=new ArrayList();
        col1.add(123);
        col1.add(456);
        col1.add(new String("tom"));
        col1.add(false);
        col1.add(new Person("fao",28));
        //hashcode()返回当前对象的哈希值
        System.out.println(col1.hashCode());//698073098
        //集合-->数组 toArray
        Object[] objects = col1.toArray();
        for (int i=0;i<objects.length;i++){
            System.out.println(objects[i]);
        }
        //拓展数组-->集合 调用arrays的静态方法 asList
        List<String> strings = Arrays.asList(new String[]{"aa", "bb", "cc"});
        System.out.println(strings);//[aa, bb, cc]
    }  
}
 2.2 集合元素遍历:使用迭代器Iterator接口
- Collection接口继承了java.lang.iterable接口,该接口有一个iterator()方法,那么所以事先了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了iterator接口的对象
- iterator仅由于遍历集合,它本身并不提供承载对象的能力,如果需要创建iterator对象,则必须有一个被迭代的集合
- 内部的方法:hasNext()和next()
- 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前
- 内部定义了remove() 可以在遍历时删除集合元素,不同于集合直接调用remove,需要注意重新生成,一定要先next再remove 也不能再下一次next前再调一次remove
- 只遍历collection 不遍历map
- jdk5.0新增了foreach,用于遍历集合和数组

public class G37IteratorTest {
    @Test
    public void test1(){
        Collection col1=new ArrayList();
        col1.add(123);
        col1.add(456);
        col1.add(new String("tom"));
        col1.add(false);
        col1.add(new Person("fao",28));
        Iterator iterator = col1.iterator();
        //方式1 不用
//        System.out.println(iterator.next());//123
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());
//        System.out.println(iterator.next());//多写一下就报异常
        //方式二 也不用
//        for (int i=0;i<col1.size();i++){
//            System.out.println(iterator.next());
//        }
        //方式三:推荐
        while (iterator.hasNext()){
            //next:指针下移,然后返回指针所指元素
            System.out.println(iterator.next());
        }
    }
    @Test
    public void test2(){
        Collection col1=new ArrayList();
        col1.add(123);
        col1.add(456);
        col1.add(new String("tom"));
        col1.add(false);
        col1.add(new Person("fao",28));
        Iterator iterator = col1.iterator();
        //删除集合中的tom
        while (iterator.hasNext()){
            Object next = iterator.next();
            if ("tom".equals(next)){//注意这里"tom"放前面防止空指针
                iterator.remove();
            }
        }
        //因为指针已经末尾了 所以要重新上传!!
        iterator=col1.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());//此时tom已经被删了
        }
    }
    @Test
    public void test3(){
        Collection col1=new ArrayList();
        col1.add(123);
        col1.add(456);
        col1.add(new String("tom"));
        col1.add(false);
        col1.add(new Person("fao",28));
        //for(集合中元素的类型 局部变量: 集合对象)也可以是数组
        //内部仍然调用迭代器
        for (Object obj:col1){
            System.out.println(obj);
        }
        int[] ints = {1, 2, 3, 4};
        for (int i:ints){
            System.out.println(i);
        }
        System.out.println();
        String[] arr = {"mm", "mm", "mm"};
        //普通for循环
        for (int i=0;i<arr.length;i++){
            arr[i]="gg";
        }
        for (int i=0;i<arr.length;i++){
            System.out.println(arr[i]);
        }
        
        String[] arr1 = {"mm", "mm", "mm"};
        //增强for循环
        for(String s:arr1){
            s="gg";
        }
       for (String s:arr1){
            System.out.println(s);
        }
    }
}
3 Collection子接口-List接口
 3.1 概述
- List接口:存储有序的可重复的数据,动态数组
- ArrayList LinkedList Vector
- ArrayList:作为List接口的主要实现类,线程不安全的,效率高,底层使用Objcet[]数组存储
- LinkedList:对于频繁插入删除操作比ArrayList高,底层使用双向链表存储
- Vector:作为List接口的古老实现类,线程安全的,效率低,底层使用Objcet[]数组存储
 3.2 ArrayList源码分析:JDK7和JDK8不同
 JDK7
- ArrayList list=new ArrayList();//底层创建了长度是10的Object数据elementData[]
- list.add(123);//如果添加导致容量不够 扩容 默认扩充1.5倍 同时将原来数组复制到新的数组中
- 结论:建议开发中使用带参的构造器 实现决定好容量 ArrayList(int capacity)
 JDK8
- ArrayList list=new ArrayList();底层Object数据elementData[]并没有创建长度为10的数组
- list.add(123)第一次调用add()时,底层才创建了长度10的数组
- 后续操作和前面一样
- 小结:7中ArrayList对象创建类似于饿汉式,8中ArrayList对象创建类似于懒汉式
 3.3 LinkedList源码分析
- LinkedList list=new LinkList()内部声明了Node类型的first和last
- 其中Node定义看源码 就是双向列表
 3.4 Vector源码分析
- 创建了长度为10的数组
- 扩容扩展为原来2倍
 3.5 新增方法
- void add(int index,Object ele):在Index位置插入ele元素
- boolean addAll(int index,Collection eles):从index位置开始讲eles中的所有元素添加进来
- Object get(int index):获取指定index位置的元素
- int indexOf(Object obj):返回obj在集合中首次出现的位置
- int lastindexOf(Object obj):返回obj在集合中最后出现的位置
- Object remove(int index):移除指定index位置的元素,并返回此元素
- Object set(int index,Object ele):设置指定Index位置的元素为ele
- List subList(int fromIndex, int toIndex):返回从fromIndex到tolndex位置的子集合
 3.6 总结常用方法
- 增 add(Object obj)
- 删 remove(int index)/ remove(Object obj)
- 改 set(int index, Object ele)
- 查 get(int index)
- 插 add(int index, Object ele)
- 长度 size()
- 遍历 1Iterator 2增强for循环 3普通循环
public class G38List {
    @Test
    public void test1(){
        ArrayList list=new ArrayList();
        list.add(123);
        list.add(456);
        list.add("aa");
        list.add(new Person("aoao",22));
        list.add(456);
        System.out.println(list);
        //[123, 456, aa, Person{name='aoao', age=22}, 456]
        //void add(int index, Object ele)在index位置插入ele
        list.add(1,"bb");
        System.out.println(list);
        //[123, bb, 456, aa, Person{name='aoao', age=22}, 456]
        //void add(int index, Collection eles)在index位置插入eles
        ArrayList list1=new ArrayList();
        list1.add("fao");
        list1.add("shuaiqi");
        list.addAll(4,list1);
        System.out.println(list);
      //[123, bb, 456, aa, fao, shuaiqi, Person{name='aoao', age=22}, 456]
        //Object get(int index)获取index位置元素
        System.out.println(list.get(1));//bb
        //int indexOf(Object obj)返回当前元素在指定集合所在索引位置没有返回-1
        System.out.println(list.indexOf("fao"));//4
        //int LastindexOf(Object obj)返回当前元素在指定集合最后所在索引位置没有返回-1
        //Object remove(int index)删除指定位置的元素 和Collection不一样 这里是位置
        System.out.println();
        Object remove = list.remove(4);
        System.out.println(list);
        //[123, bb, 456, aa, shuaiqi, Person{name='aoao', age=22}, 456]
        System.out.println(remove);
        //fao
        //Object set(int index, Object ele)设置指定index位置为ele
        list.set(0,"zzz");
        System.out.println(list);
        //[zzz, bb, 456, aa, shuaiqi, Person{name='aoao', age=22}, 456]
        //List subList(int fromIndex, int toIndex)返回从fromIndex到toIndex的子集合左闭右开
        List list2 = list.subList(1, 3);
        System.out.println();
        System.out.println(list2);
        //[bb, 456]
        System.out.println(list);
        //[zzz, bb, 456, aa, shuaiqi, Person{name='aoao', age=22}, 456]
    }
    //遍历
    @Test
    public void test2(){
        ArrayList list=new ArrayList();
        list.add(123);
        list.add(456);
        list.add("aa");
        list.add(new Person("aoao",22));
        list.add(456);
        //方式1:iterator
        Iterator iterator=list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //方式二:增强for循环
        System.out.println();
        for (Object obj:list){
            System.out.println(obj);
        }
        //方式三:普通for循环
        System.out.println();
        for (int i=0;i<list.size();i++){
            System.out.println(list.get(i));
        }
    }
}
4 Collection子接口-Set接口
 4.1 简介
- Set接口是Collection子接口,set接口没有提供额外的方法
- Set接口:存储无序的不可重复的数据,高中讲的集合
- Set集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set集合中,则添加失败
- HashSet LinkedHashSet TreeSet
- HashSet:作为set接口的主要实现类,线程不安全的,可以存储null值
- LinkedHashSet:HashSet子类,遍历其内部数据时可以按照添加数据遍历
- TreeSet:红黑树存储,可以按照添加对象的指导属性进行排序,只能添加统一类数据
- Set判断两个对象是否相同不是使用==运算符,而是根据equals()方法
- 要求:向set中添加的数据,其所在类一定要重写hashcode()和equals()
- hashcode()和equals()要保持一致性,即相同的对象要有相同的哈希值
 4.2 特点
- set:存储无序的,不可重复的数据(以HashSet为例说明)
- 无序性:不等于随机性,存储的数据在底层数组中并非按照数组索引的顺序添加;而是根据数据的Hash值确定的
- 不可重复性:保证添加的元素按照equals判断时,不能返回true;相同的元素只能添加一个
 4.3 添加元素的过程(HashSet为例)
- 1我们想在HashSet中添加a,首先调用a的hashCode方法,计算a哈希值
- 2此哈希值通过哈希函数计算出hashset数组存放位置
- 3数组此位置上是否已经有元素
- 3.1如果此位置没有元素,则a添加成功--情况1; 3.2 如此位置有其他元素b(或链表形式存在的多个元素)
- 4比较ab哈希值:
- 4.1哈希值不同,则添加成功--情况2;如果相同
- 5 进而需要调元素a的equals方法
- 5.1 equals方法返回false则添加成功,--情况3,; 如果返回true 则添加失败
- 对于添加成功情况2和情况3 a和已经存储元素按照链表方式存储(jdk7中a放到数组中,指向原来元素;jdk8中原来元素在数组中,指向a,(七上八下))
- Hashset底层就是数组+链表方式
//Class一 PERSON-重写了equals方法和hashcode方法
class Person{
    private String name;
    private int age;
    public Person() {
    }
    public Person(String name, int age){
        this.name=name;
        this.age=age;
    }
    public void walk(){
        System.out.println("人走路");
    }
    public void eat(){
        System.out.println("人吃饭");
    }
}
//Class二 USER-重写了equals方法和hashcode方法
class User implements Comparable{
    private String name;
    private int age;
    public User(){
    }
    public User(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 "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    //注意equals要和hashCode判定方式一样
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return age == user.age && Objects.equals(name, user.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    //按照姓名从小到大排序
    @Override
    public int compareTo(Object o) {
        if (o instanceof User) {
            User user=(User) o;
            return this.name.compareTo(user.name);
        }else{
            throw new RuntimeException("不匹配");
        }
    }
}
 4.4 Set实现类一:HashSet
- HashSet是Set接口的典型实现,大多数时候使用Set集合时都使用这个类
- HashSet按Hash算法来存储集合中的元素,因此具有很好的存取,查找,删除性能
- HashSet具有以下特点:a不能保证元素的排列顺序 bHashSet不是线程安全的 c集合元素可以是null
- HashSet集合判断两个元素相等的标准:两个对象通过hashCode()方法比较相等,并且两个对象的equals()方法返回值也相等
- 对于存放在Set容器的对象,对应的类一定要重写equals()和hashCode(Object obj)方法,以实现对象相等的规则,即“相等的对象必须具有相等的散列码”
 @Test
    public void test1(){
        Set set=new HashSet();
        set.add(456);
        set.add(123);
        set.add("aa");
        set.add("cc");
        set.add(new Person("p",99));
        set.add(new Person("p",99));//没有重写equals和hashcode就会添加重复
        set.add(new User("u",99));
        set.add(new User("u",99));
        set.add(123);
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //aa
        //cc
        //Person{name='p', age=99} 
        //Person{name='p', age=99} 重复了!
        //456
        //User{name='u', age=99}
        //123
    }
 4.5 Set实现类二:LinkedHashSet
- LinkedHashSet是HashSet的子类
- LinkedHashSet根据元素的hashCode只来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的
- LinkedHashSet插入性能略低于HashSet,但在迭代访问Set里的全部元素时有很好的性能(即对于频繁的遍历操作要比hashcode更高效)
- LinkedHashSet不允许集合元素重复
 @Test
    public void test2(){
        Set set=new LinkedHashSet();
        set.add(456);
        set.add(123);
        set.add("aa");
        set.add("cc");
        set.add(new Person("p",99));
        set.add(new Person("p",99));
        set.add(new User("u",99));
        set.add(new User("u",99));
        set.add(123);
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        //456
        //123
        //aa 
        //cc
        //Person{name='person', age=99}
        //Person{name='person', age=99} 重复
        //User{name='user', age=99}
    }
 4.6 Set实现类三:TreeSet
- TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态,需要内部元素一致
- TreeSet底层使用红黑树结构存储数据
- TreeSet两种方法:自然排序(comparable接口)和定制排序(comparator),默认情况下,TreeSet采用自然排序
- 自然排序中,比较两个对象是否相等的标准为compareto方法是否返回0不再是equals方法
- 定制排序中,比较两个对象是否相等的标准为compare()方法是否为0,不再是equals方法
//自然排序
@Test
    public void test3(){
        TreeSet set=new TreeSet();
        //失败的 ClassCastException
//        set.add(456);
//        set.add(123);
//        set.add("aa");
//        set.add(new Person("lala",99));
        //举例1
        //set.add(32);
        //set.add(33);
        //set.add(-82);
        //set.add(92);
        //set.add(132);
        //System.out.println(set);
        //举例2
        set.add(new User("tom",22));
        set.add(new User("fa",32));
        set.add(new User("aa",21));
        set.add(new User("zt",5));
        set.add(new User("ee",55));
        set.add(new User("ee",55));
        System.out.println(set);
    }
//定制排序
 @Test
    public void test4(){
        Comparator com=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 Integer.compare(u1.getAge(),u2.getAge());
                }else {
                    throw new RuntimeException("不一致");
                }
            }
        };
        TreeSet set=new TreeSet(com);
        set.add(new User("tom",22));
        set.add(new User("fa",22));
        set.add(new User("aa",21));
        set.add(new User("zt",5));
        set.add(new User("ee",55));
        set.add(new User("ee",55));
        System.out.println(set);
  //[User{name='zt', age=5}, User{name='aa', age=21}, User{name='tom', age=22}, User{name='ee', age=55}]
        //相同年龄的会没有
    }
5 Map接口

 5.1 简介
- 
Map接口:双列集合,用于存储一对一对的对象,高中函数y=f(x) 
- 
分为:HashMap( LinkedHashMap )TreeMap Hashtable ( Properties) 
- 
HashMap:作为map的主要实现类,线程不安全,效率高,可以存储null的key和value;HashMap底层:数组+链表(jdk7之前),数组+链表+红黑树(jdk8之后) 
- 
LinkedHashMap:保证在遍历map元素时,可以按照添加顺序进行遍历;原因:在原有基础上添加了前后指针,对于频繁的遍历操作效率更高 
- 
TreeMap:保证按照添加的key-value进行排序,此时考虑key的自然排序或定制排序;底层使用的红黑树 
- 
Hashtable:古老实现类,线程安全,效率低,不可以存储null的key和value 
- 
Properties:常用来处理配置文件,key和value都是string类型的 5.2 Map结构理解 
- 
Map中的key:无序的,不可重复的,使用set存储所有key--->key所在类重写equals和hashcode(以hashmap来说) 
- 
Map中的value:无序的,可重复的,使用collection存储所有的value-->value所在类重写equals 
- 
一个键值队:key-value构成Entry对象, 
- 
Map中的Entry:无序的,不可重复的,使用set存储所有entry 
 5.3 Map常用方法
- Object put(Object key,Object value):将指定key-value添加到或修改到当前map对象中
- void putAll(Map m):将m中的所有key-value对存放到当前map中
- Object remove(Object key):移除指定key的key-value对,并返回value
- void clear():清空当前map中的所有数据
- Object get(Object key):获取指定key对应的value
- boolean containsKey(Object key):是否包含指定的key
- boolean containsValue(Object value):是否包含指定的value
- int size():返回map中的key-value对的个数
- boolean isEmpty():判断当前map是否为空
- boolean equals(Object obj):判断当前map和参数对象obj是否相等
- Set keySet():返回所有key构成的Set集合
- Collection values():返回所有value构成的Collection集合
- Set entrySet():返回所有key-value对构成的Set集合
- Map接口定义方法总结
- 增 put
- 删 remove
- 改 put
- 查 get
- 长度 size
- 遍历 keySet values entrySet
 5.4 HashMap
 HashMap底层实现原理(JDK7)
- a.实例化:HashMap map=new HashMap()
- 在实例化以后底层创建了长度是16的一维数组Entry[] table
- b.添加:map.put(key1,value1);
- 首先调用key1所在的类的hashcode()就是key1的哈希值,通过哈希函数得到Entry数组中的位置
- 如果此位置上数据为空,此时key1-value1添加成功--情况1
- 如果此位置上数据不为空,即存在一个或多个数据(链表)比较key1和存在数据的key的哈希值
- 如果key1哈希值和它们都不一样,则添加成功--情况2
- 如果key1哈希值和某一个相同,继续比较key1所在的equals方法
- 如果equals放回false,则添加成功--情况3
- 如果equals返回true,使用value1替换相同key的value值(新的换旧的)
- 关于情况2和情况3:此时key1和value1和原来数组以链表方式存储
- 在不断添加过程中,会涉及扩容问题:当超出临界值(且要存放位置非空时)扩容为原来容量2倍,并将原来数据复制过来
 HashMap底层实现原理(JDK8)
- HashMap map=new HashMap()底层没有创建一个长度16的数组
- 底层的数组是Node[] 而不是Entry[],换了个名字
- 首次调用put方法时,底层创建长度是16的数组
- jdk7底层结构只有数组+链表 8变成数组+链表+红黑树
- 当数组某一个索引位置上元素以链表形式存在的数据个数>8且当前数组长度>64(小于64先扩容), 此时索引位置上的所有数据改为红黑数存储
 HashMap源码中的重要常量
- DEFAULT_INITIAL_CAPACITY:HashMap的默认容量,16
- MAXIMUN_CAPACITY:HashMap的最大支持容量,2^30
- DEFUAL_LOAD_FACTOR:默认加载因子,0.75
- loadFactor:填充因子
- threshold:扩容的临界值=容量*填充因子
 5.5 LinkedHashMap(底层结构了解即可)
//HashMap中的内部类
  static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;
        final K key;
        V value;
        Node<K,V> next;
  }
//LinkedHashMap中的内部类
  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);
        }
    }
public class G41Map {
    @Test
    public void test1(){
        //put
        Map map199=new LinkedHashMap();
        Map map=new HashMap();
        map.put("aa",123);
        map.put("bb",222);
        map.put("cc",123);
        map.put("aa",923);
        System.out.println(map);
        //{aa=923, bb=222, cc=123}
        //putall
        Map map1=new HashMap();
        map1.put("ee",273);
        map1.put("dd",444);
        map.putAll(map1);
        System.out.println(map);
        //{aa=923, bb=222, cc=123, ee=273, dd=444}
        //remove(key)
        Object cc = map.remove("cc");//不存在返回null
        System.out.println(cc);//123
        System.out.println(map);
        //{aa=923, bb=222, ee=273, dd=444}
        //clear
        map.clear();
        System.out.println(map);//{}
        System.out.println(map.size());//0
    }
    @Test
    public void test2(){
        Map map=new HashMap();
        map.put("aa",123);
        map.put("bb",222);
        map.put("cc",123);
        //get(key)
        System.out.println(map.get("cc"));//123
        //containsKey(key)
        boolean bb = map.containsKey("bb");
        System.out.println(bb);//true
        //containsValue(value)
        System.out.println(map.containsValue(123));//true
        //size
        System.out.println(map.size());//3
        //isEmpty
        //boolean equals(Object obj)
    }
    //遍历 元视图操作
    @Test
    public void test3(){
        Map map=new HashMap();
        map.put("aa",123);
        map.put("bb",222);
        map.put("cc",123);
        //遍历所有key集 keySet()
        Set set = map.keySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());// aa bb cc
        }
        //遍历所有value values()
        Collection values = map.values();
        Iterator iterator1 = values.iterator();
        while (iterator1.hasNext()){
            System.out.println(iterator1.next());//123 222 123
        }
        
        //遍历所有key-value entrySet()
        Set set1 = map.entrySet();
        Iterator iterator2 = set1.iterator();
//        while (iterator2.hasNext()){
//            System.out.println(iterator2.next());
//        }
        while (iterator2.hasNext()){
            Object obj = iterator2.next();
            //entrySet集合中的元素都是entry
            Map.Entry entry=(Map.Entry) obj;
            System.out.println(entry.getKey()+"-->"+entry.getValue());
        }
        //方式二
        Set set2 = map.keySet();
        Iterator iterator3 = set2.iterator();
        while (iterator3.hasNext()){
            Object key = iterator3.next();
            Object value=map.get(key);
            System.out.println(key+"--->"+value);
        }
    }
}
 5.6 treeMap
- 向treemap中添加key-value要求key必须是同一类创建的对象
- 因为要按照key进行自然排序,定制排序
public class G42TreeMap {
    //自然排序
    @Test
    public void test1(){
        TreeMap map=new TreeMap();
        User u1=new User("fao",22);
        User u2=new User("tom",12);
        User u3=new User("jack",33);
        User u4=new User("zz",55);
        map.put(u1,98);
        map.put(u2,88);
        map.put(u3,89);
        map.put(u4,68);
        Set set1 = map.entrySet();
        Iterator iterator2 = set1.iterator();
        while (iterator2.hasNext()){
            Object obj = iterator2.next();
            //entrySet集合中的元素都是entry
            Map.Entry entry=(Map.Entry) obj;
            System.out.println(entry.getKey()+"-->"+entry.getValue());
        }
        //Person{name='fao', age=22}-->98
        //Person{name='jack', age=33}-->89
        //Person{name='tom', age=12}-->88
        //Person{name='zz', age=55}-->68
    }
    //定制排序
    @Test
    public void test2(){
        Comparator comparator=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 Integer.compare(u1.getAge(),u2.getAge());
                }else {
                    throw new RuntimeException("不一致");
                }
            }
        };
        TreeMap map1=new TreeMap(comparator);
        User u1=new User("fao",22);
        User u2=new User("tom",12);
        User u3=new User("jack",33);
        User u4=new User("zz",55);
        map1.put(u1,98);
        map1.put(u2,88);
        map1.put(u3,89);
        map1.put(u4,68);
        System.out.println(map1);
        //{Person{name='tom', age=12}=88, Person{name='fao', age=22}=98, Person{name='jack', age=33}=89, Person{name='zz', age=55}=68}
    }
}
class User implements Comparable{
    private String name;
    private int age;
    public User(){
    }
    public User(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 boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return age == user.age && Objects.equals(name, user.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    //按照姓名从小到大排序
    @Override
    public int compareTo(Object o) {
        if (o instanceof User) {
            User user=(User) o;
            return this.name.compareTo(user.name);
        }else{
            throw new RuntimeException("不匹配");
        }
    }
}
 5.7 Properties
- Properties类是Hashtable的子类,该对象用于处理属性文件
- 由于属性文件里的key,value都是字符串类型,所以Properties里的key和value都是字符串类型
- 存取数据时,建议使用setProperty(String key, String value)方法和getProperty(String key)方法
public class G43Properties {
    public static void main(String[] args) throws Exception{
        Properties properties=new Properties();
        
        FileInputStream fis=new FileInputStream("jdbc.properties");
        properties.load(fis);
        String name = properties.getProperty("name");
        String password = properties.getProperty("password");
        System.out.println(name);//Tom
        System.out.println(password);//abc123
    }
}
//jdbc.properties中
name=Tom
password=abc123
6 Collections工具类
 简介
- Collections是一个操作Set,List,Map等集合的工具类
- Collections中提供了一系列静态的方法堆集合元素进行排序,查询和修改等操作,还提供了对集合对象设置不可变,对集合对象实现同步控制等方法
 常用方法
- reverse(List):反转List中元素的顺序
- shuffle(List):对List集合进行随机排序
- sort(List):根据元素的自然排序对指定List集合元素进行升序排序
- sort(List, Comparator):根据指定的Comparator产生的顺序对List集合元素进行排序
- swap(List,int , int):将指定list集合中的i处元素和j处元素进行排序
- Object max(Collection):根据元素的自然排序,返回指定集合中的最大元素,后面参数加Comparator就是定制排序
- Objectmin(Collection):根据元素的自然排序,返回指定集合中的最小元素,后面参数加Comparator就是定制排序
- int frequency(Collection, Object):返回指定集合中指定元素的出现次数
- void copy(List dest,List src):将src中的内容复制到dest中
- boolean replaceAll(List list,Object oldVal, Object newVal):使用新值替换List对象的所有旧值
public class G44CollectionsGongJuLei {
    @Test
    public void test1(){
        List list=new ArrayList();
        list.add(123);
        list.add(73);
        list.add(1);
        list.add(999);
        System.out.println(list);//[123, 73, 1, 999]
        //reverse(list)
        Collections.reverse(list);
        System.out.println(list);//[999, 1, 73, 123]
        //shuffle(list)随机排列
        Collections.shuffle(list);
        System.out.println(list);//[123, 1, 999, 73]
        //sort(list, comparator) 自然排序
        Collections.sort(list);
        System.out.println(list);//[1, 73, 123, 999]
        //swap(list,index1,index2)
        Collections.swap(list,1,2);
        System.out.println(list);//[1, 123, 73, 999]
        //max(list)最大值
        //min(list)
        //frequency(list,data)
        System.out.println(  Collections.frequency(list,1));//1
    }
    @Test
    public void test2(){
        List list=new ArrayList();
        list.add(123);
        list.add(73);
        list.add(1);
        list.add(999);
        
        //copy
        //错误的  size不够
//      List dest=new ArrayList();
//      Collections.copy(dest,list);
//      System.out.println(dest);
        //正确的
        List dest= Arrays.asList(new Object[list.size()]);
        System.out.println(dest.size());//4
        Collections.copy(dest,list);
        System.out.println(dest);//[123, 73, 1, 999]
        //replaceAll()
        //Collections提供了多个synchronizedXxx方法将线程不安全的转换为线程安全的
        List list1 = Collections.synchronizedList(list);
        //返回的list1就是线程安全的list1
    }
}
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号