Java 集合框架

一、集合

  • 概念:对象的容器,定义了对多个对象进行操作的常用方法。实现了类似数组的功能。
  • 和数组的区别:
    1. 数组长度固定,集合长度不固定;
    2. 数组可以存储基本类型和引用类型,集合只能存储引用类型;
  • 位置:java.util.*;

二、Collection体系集合

java 集合体系

  • 该体系结构的根接口,代表一组对象,称为”集合“。
  • List接口的特点:
    • 有序、有下标、元素可重复
  • Set接口的特点:
    • 无序、无下标、元素不能重复

三、Collection父接口

  • 特点:代表一组任意类型的对象,无序,无下标、不能重复。
  • 方法:
    1. boolean add(Object obj) //添加一个对象。
    2. boolean addAll(Collection c) //将一个集合中的所有对象添加到此集合中。
    3. void clear()//清空此集合中的所有对象。
    4. boolean contains(Object o)//检查此集合中是否包含0对象
    5. boolean equals(Object o) //比较此集合是否与指定对象相等
    6. boolean isEmpty()//判断此集合是否为空
    7. boolean remove(Object o) //在此集合中移除对象
    8. int size()//返回此集合中的元素个数。
    9. Object[] toArray()//将此集合转换成数组。
    10. Iterator iterator() //迭代器 重点
package com.set.collection;

/*
* Collection接口的使用
* (1)添加远胜于
* (2)删除元素
* (3)遍历元素
* (4)判断
* */

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Demo01 {
    public static void main(String[] args) {
        //创建集合
        Collection collection = new ArrayList();
        //(1)添加远胜于
        collection.add("苹果");
        collection.add("西瓜");
        collection.add("榴莲");
        System.out.println("元素个数"+collection.size());
        System.out.println(collection.toString());
        //(2)删除元素
        // collection.remove("榴莲");
        // collection.clear(); //清空
        System.out.println(collection.size());
        //(3)遍历元素[重点!!!]
        //第一种方式
        System.out.println("---------第一种方式:增强for---------");
        for (Object object: collection){
            System.out.println(object);
        }
        //第二种饭方式 迭代器 专门用来遍历集合的方法
        System.out.println("---------第一种方式:iterator---------");
        //hasNext() 有没有下一个元素
        //next()  获取下一个元素
        // remove() 删除当前元素
        Iterator it =  collection.iterator();
        while (it.hasNext()){
            String s = (String)it.next();
            System.out.println(s);
            //迭代过程中不允许collection删除方法: collection.remove(s)
            // 否则会出现异常ConcurrentModificationException(并发修改异常)
            //collection.remove(s);
            it.remove();
        }
        System.out.println("元素个数:"+collection.size());

        //(4)判断
        System.out.println(collection.contains("西瓜"));
        System.out.println(collection.isEmpty());


    }
}

package com.set.collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

//Collection的使用二 Student类
public class Demo02 {
    public static void main(String[] args) {
        //1、创建Collection对象
        Collection collection = new ArrayList();
        //2、创建Student对象
        Student s1 = new Student("张三",18);
        Student s2 = new Student("李四",19);
        Student s3 = new Student("王五",20);
        //3、添加数据
        collection.add(s1);
        collection.add(s2);
        collection.add(s3);
        System.out.println("元素个数"+collection.size());
        System.out.println(collection.toString());
        //4、删除
        collection.remove(s1);
        //collection.remove(new Student("王五",20));//并不能删除集合中的s3,用为new  地址不同
        //collection.clear();//清空
        //集合中存的是对象的地址 清空后这几个对象并没有消失,删除的是地址,对象还在堆中
        System.out.println("删除之后:"+collection.size());
        //5、遍历
        System.out.println("------一、增强for来遍历--------");
        for (Object obj:collection) {
            Student stu1 = (Student) obj;
            System.out.println(stu1.toString());
        }
        System.out.println("------二、迭代器遍历--------");
        Iterator it = collection.iterator();
        while (it.hasNext()){
            Student s = (Student) it.next();//强制转换
            System.out.println(s.toString());
        }
        //5、判断
        System.out.println("------判断--------");
        System.out.println(collection.contains(s2));
        System.out.println(collection.isEmpty());

    }
}

四、List子接口

  • 特点:有序、有下标、元素可以重复。
  • 方法(具有父接口Collection的所有方法)
    1. void add( int index, Object o ) //在index位置插入对象。
    2. boolean addAll(int index , Collection c ) //将一个集合的元素添加到此集合中的index位置。
    3. Object get( int index) //返回集合中指定位置的元素
    4. List subList(int fromIndex,int toindex)v //返回fromIndex和toIndex之间的集合元素。
package com.set.List;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

//List子接口的使用
/*
* 特点:有序、有下标、可以重复
* */
public class Demo01 {
    public static void main(String[] args) {
        //先创建一个集合
        List list = new ArrayList<>();
        //1、添加元素
        list.add("小米");
        list.add("苹果");
        list.add("华为");
        System.out.println("元素个数:"+list.size());
        System.out.println(list.toString());
        //2、删除元素
        //list.remove("苹果");
        //list.remove(0);
        System.out.println(list.size());
        System.out.println(list.toString());

        //3、遍历【重点!!!】
        //使用for遍历
        System.out.println("-------3、1for遍历-------");
        for (int i = 0; i < list.size() ; i++) {
            System.out.println(list.get(i));
        }
        System.out.println("-------3、2增强for遍历-------");
        for (Object obj:list) {
            System.out.println(obj);
        }
        System.out.println("-------3、3迭代器遍历-------");
        Iterator it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        System.out.println("-------3、4列表迭代器-------");
        ListIterator lit = list.listIterator();
        System.out.println("-----------3、4、1列表迭代器从前往后-----------");
        while (lit.hasNext()){
            System.out.println(lit.nextIndex()+":"+lit.next());

        }
        System.out.println("-----------3、4、1列表迭代器从后往前-----------");
        /*while (lit.hasPrevious()){
            System.out.println(lit.previousIndex()+":"+lit.previous());
        }*/
        //4、判断
        System.out.println("-------3、5判断-------");
        System.out.println(list.contains("苹果"));
        System.out.println(list.isEmpty());

        //5、获取位置
        System.out.println(list.indexOf("华为"));


    }
}

五、List实现类

  • ArrayList(重点)

    • 数组结构实现,查询快、增删慢;
    • JDK1.2版本,运行效率快、线程不安全。
  • Vector:

    • 数组结构实现,查询快、增删慢;
    • JDK1.0版本,运行效率慢、线程安全。
  • LinkedList:

    • 链表结构实现,增删快,查询慢。

5、1 ArrayList

  • 存储结构:数组 查找遍历速度快,增删慢
  • 存储地址是连续的
  • 创建集合
//创建集合
        ArrayList arraylist = new ArrayList<>();
  • 方法和List的方法基本一样
//1、添加元素
        Student s1 = new Student("张三",18);
        Student s2 = new Student("李四",19);
        Student s3 = new Student("王五",20);
        Student s4 = new Student("王麻子",21);
        arraylist.add(s1);
        arraylist.add(s2);
        arraylist.add(s3);
        arraylist.add(s4);
        System.out.println("-------1、添加元素--------");
        System.out.println("元素个数:"+arraylist.size());
        System.out.println(arraylist.toString());
        //2、删除元素
        System.out.println("-------2、删除元素--------");
        //arraylist.remove(s1);
        //arraylist.remove(new Student("李四",19));//equals(this == obj)方 法比较的是地址
        System.out.println("删除之后:"+arraylist.size());
        System.out.println(arraylist.toString());

        //3、遍历元素【重点】
        System.out.println("-------3、遍历元素--------");
        //3、1迭代器遍历
        System.out.println("-------3、1使用迭代器iterator--------");
        Iterator it = arraylist.iterator();
        while (it.hasNext()){
            Student student1 = (Student) it.next();
            System.out.println(student1.toString());
        }
        //ListIterator列表迭代器
        System.out.println("-------3、2使用列表迭代器LisIterator--------");
        System.out.println("-------从前往后-------");
        ListIterator lit = arraylist.listIterator();
        while (lit.hasNext()){
            Student student2 = (Student) lit.next();
            System.out.println(student2.toString());
        }
        System.out.println("-------从后往前-------");
        while(lit.hasPrevious()){
            Student student3 = (Student) lit.previous();
            System.out.println(student3.toString());
        }

        //4、判断
        System.out.println("-------4、判断元素--------");
        System.out.println(arraylist.contains(new Student("张三",18)));
        System.out.println(arraylist.isEmpty());
        //3、查找
        System.out.println("-------5、查找元素--------");
        System.out.println(arraylist.indexOf(s1));
        System.out.println(arraylist.indexOf(new Student("王麻子",21)));

  • equals方法重写
@Override
    public boolean equals(Object obj) {
        //1、比较是不是同一个引用
        if(this == obj){
            return true;
        }
        //2、判断是否为空
        if(obj == null){
            return false;
        }
        //3、判断是不是Student类型
        if(obj instanceof Student){
            Student student = (Student) obj;
            //4、比较属性
            if (Objects.equals(this.name, student.getName()) &&this.age==student.getAge()){
                return true;
            }
        }
        return false;
    }

5、2 ArrayList源码分析

  • 默认容量大小:int DEFAULT_CAPACITY = 10;

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

  • 实际元素个数:size;

  • add():添加元素

    public boolean add(E e) {
            ensureCapacityInternal(size + 1);  // Increments modCount!!
            elementData[size++] = e;
            return true;
        }
    
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
            if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
                return Math.max(DEFAULT_CAPACITY, minCapacity);
            }
            return minCapacity;
        }
    
    private void ensureExplicitCapacity(int minCapacity) {
            modCount++;
    
            // overflow-conscious code
            if (minCapacity - elementData.length > 0)
                grow(minCapacity);
        }
    
    //数组扩容核心
    private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                newCapacity = hugeCapacity(minCapacity);
            // minCapacity is usually close to size, so this is a win:
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
    

5、3 Vector使用

  • Vector:

    • 数组结构实现,查询快、增删慢;
    • JDK1.0版本,运行效率慢、线程安全。
  • 创建Vector集合

     //创建集合
            Vector vector = new Vector<>();
    //1、添加元素
            System.out.println("------1、添加元素------");
            vector.add("草莓");
            vector.add("芒果");
            vector.add("苹果");
     //2、遍历
    Enumeration en = vector.elements();
            while (en.hasMoreElements()){
                String o = (String) en.nextElement();
                System.out.println(o);
            }
    //其他方法和ArrayList的方法类似
    

5、4 LinkedList使用

  • LinkedList

    • 双向链表 增删快 查询慢
    • 存储地址不是连续的
  • 创建LinkedList以及常用方法

    • //创建集合
             LinkedList<Object> linkedList = new LinkedList<>();
             System.out.println(linkedList.getFirst());//获取第一个元素
             System.out.println(linkedList.getLast());//获取最后一个元素
       
      
  • 其他方法和ArrayList类似。

5、5泛型

5、5、1泛型类

  • Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。

  • 注意:

    1. 泛型只能传引用类型。

    2. 不同泛型对象之间不能相互赋值

       //Demo01<String> stringDemo011 = integerDemo01; //不同泛型对象不能相互复制
      
  • 常见形式有泛型类、泛型接口、泛型方法。

  • 语法:

    • <T,…> T称为类型占位符,表示一种引用类型。
  • 好处:
    (1)提高代码的重用性。
    (2)防止类型转换异常,提高代码的安全性。

package com.set.Generic;
//泛型类
//语法 类名<T> T是类型占位符,表示是一种引用类型,可以写多个,用逗号隔开
public class Demo01<T> {
    //使用泛型创建变量
    //1、创建变量
    T t;
    //2、作为方法的参数
    public void show(T t){
       // T t1 = new T(); 不能这样直接实例化 因为不能保证传过来的类型构造方法一定能用
        System.out.println(t);
    }
    //3、使用泛型作为方法的返回值
    public T getT(){
        return t;
    }

}
package com.set.Generic;

public class Application {
    public static void main(String[] args) {
        //泛型类创建对象
        //注意:1、泛型只能是引用类型 2、不同泛型对象之间不能相互赋值
        Demo01<String> stringDemo01 = new Demo01<>();
        stringDemo01.t = "hello";
        stringDemo01.show("大家好,学个屁的Java,别学了");
        String result = stringDemo01.getT();
        System.out.println(result);

        Demo01<Integer> integerDemo01 = new Demo01<>();
        integerDemo01.t = 20;
        integerDemo01.show(30);
        System.out.println(integerDemo01.getT());

        //Demo01<String> stringDemo011 = integerDemo01; //不同泛型对象不能相互复制

    }
}

5、5、2泛型接口

  • 注意:泛型接口类不能创建泛型常量
  • 语法 :接口名:
  1. 创建泛型接口:

    package com.set.Generic.Myinterfece;
    //泛型接口
    //语法 接口名:<T>
    //注意:不能创建泛型常量
    public interface Demo01 <T>{
        String name = "张三";
        T server(T t);
    }
    
  2. 实现类第一种 第一种实现方式(实例化之前确定泛型类的引用类型)

    package com.set.Generic.Myinterfece;
    public class Demo01Impl implements Demo01<String> {
        @Override
        public String server(String t) {
            System.out.println(t);
            return t;
        }
    }
    
  3. 实现类第二种 第二种实现方式(实例化的时确定泛型类的引用类型)

    package com.set.Generic.Myinterfece;
    
    public class Demo01Impl2<T> implements Demo01<T> {
        @Override
        public T server(T t) {
            System.out.println(t);
            return t;
        }
    }
    
  4. 启动类

    package com.set.Generic.Myinterfece;
    
    public class Application {
        public static void main(String[] args) {
            //第一种实现方式(实例化之前确定泛型类的引用类型)
            Demo01Impl demo01 = new Demo01Impl();
            demo01.server("hello");
            //第二种实现方式(实例化的时确定泛型类的引用类型)
            Demo01Impl2<Integer> integerDemo01Impl2 = new Demo01Impl2<>();
            integerDemo01Impl2.server(1000);
        }
    }
    

5、5、3 泛型方法

5、5、3 、1 无界泛型方法
  • 下面是定义泛型方法的规则:

    1. 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的 )。
    2. 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
    3. 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
    4. 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像 int、double、char 等)。
    5. 语法:放在方法返回值的前面 T 方法返回值类型 方法名(T t)
  • java 中泛型标记符:

    1. E - Element (在集合中使用,因为集合中存放的是元素)

    2. T - Type(Java 类)

    3. K - Key(键)

    4. V - Value(值)

    5. N - Number(数值类型)

    6. ? - 表示不确定的 java 类型

  • <? extends T>和<? super T>的区别
    1. <? extends T>表示该通配符所代表的类型是T类型的子类
    2. <? super T>表示该通配符所代表的类型是T类型的父类
package com.set.Generic.Methods;

//泛型方法
//语法:放在方法返回值的前面 T 方法返回值类型 方法名(T t)
public class Demo01 {
    //打印不同类型的数组
    public <T> void arrayPrint(T[] inputArray){
        for (T t:inputArray) {
            System.out.print(t+",");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Demo01 demo01 = new Demo01();
        Integer[] integers ={1,2,4,5,6};
        Double[] doubles = {1.2,3.4,5.6};
        Character[] characters = {'h','e','l','l','o'};
        System.out.println("--------整形数组-------");
        demo01.arrayPrint(integers);
        System.out.println("--------双精度数组-------");
        demo01.arrayPrint(doubles);
        System.out.println("--------字符数组-------");
        demo01.arrayPrint(characters);
    }
}

5、5、3 、2 有界泛型方法
  • 可能有时候,你会想限制那些被允许传递到一个类型参数的类型种类范围。例如,一个操作数字的方法可能只希望接受Number或者Number子类的实例。这就是有界类型参数的目的。
  • 要声明一个有界的类型参数,首先列出类型参数的名称,后跟extends关键字,最后紧跟它的上界。

实例

  • 下面的例子演示了"extends"如何使用在一般意义上的意思"extends"(类)或者"implements"(接口)。该例子中的泛型方法返回三个可比较对象的最大值。
package com.set.Generic.Methods;

//泛型方法 有界的类型参数
public class MaximumTest {
    public <T extends Comparable<T>> T maximum(T t1,T t2,T t3){
        T max = t1;
        if(t2.compareTo(max)>0){
            max = t2;
        }
        if(t3.compareTo(max)>0){
            max = t3;
        }
        System.out.println("最大值为:"+max);
        return max;
    }

    public static void main(String[] args) {
        MaximumTest maximumTest = new MaximumTest();
        maximumTest.maximum(4,3,8);
        maximumTest.maximum(1.1,2.2,3.3);
        maximumTest.maximum("java","c","php");
    }

}
5、5、3 、3 类型通配符
  • 类型通配符一般是使用 **?**代替具体的类型参数例如List<?>在逻辑上是 List, List, List,等所有List<具体的实参类型>的父类。
  • 实例 因为getData()放法的参数是List<?>,所以stringgs,integers,doubles都可以作为这个方法的实参,这就是通配符的作用。
  • 类型通配符上限通过形如List来定义,如此定义就是通配符泛型值接受Number及其下层子类类型。
  • //demo01.getUperNumber(strings);//这里会报错,因为getUperNumber()放法中的参数已经定义了参数泛型上限为Number,所以泛型为String是不在这个范围内,所以会报错。
package com.set.Generic.Methods;
//实例
import java.util.ArrayList;
import java.util.List;

public class Demo01 {
    //根据List的不同类型打印下标为0的元素
    public void getData(List<?> data){
        System.out.println("data:"+data.get(0));
    }
    public void getUperNumber(List<? extends Number> data){
        System.out.println("data:"+data.get(0));
    }
    public static void main(String[] args) {
        List<String> strings = new ArrayList<>();
        List<Double> doubles = new ArrayList<>();
        List<Integer> integers = new ArrayList<>();
        strings.add("hello");
        doubles.add(1.2);
        integers.add(30);
        Demo01 demo01 = new Demo01();
        //demo01.getUperNumber(strings);//
        demo01.getUperNumber(doubles);
        demo01.getUperNumber(integers);
        demo01.getData(strings);
    }
}

5、5、4 泛型集合

  • 概念:参数化类型、类型安全的集合,强制集合元素必须一致
  • 特点:
    • 编译时即可检查,而非运行是抛出异常
    • 访问时,不必类型转换(拆箱)
    • 不同泛型之间不能相互赋值,泛型不存在多态。
package com.set.Generic.GenericSet;

import com.set.Collection.Student;
import java.util.ArrayList;
import java.util.Iterator;

public class Demo01 {
    public static void main(String[] args) {
        ArrayList <String> arrayList = new ArrayList<String>();
        arrayList.add("张三");
        arrayList.add("李四");
        arrayList.add("王五");
        arrayList.add("王麻子");
        for (String str:arrayList) {
            System.out.println(str);
        }
        ArrayList <Student> arrayList2 = new ArrayList<Student>();
        Student s1 = new Student("张三",18);
        Student s2 = new Student("李四",19);
        Student s3 = new Student("王五",20);
        Student s4 = new Student("王麻子",21);
        arrayList2.add(s1);
        arrayList2.add(s2);
        arrayList2.add(s3);
        arrayList2.add(s4);
        Iterator<Student> it = arrayList2.iterator();
        while (it.hasNext()){
            Student st = it.next();//不用强制转换
            System.out.println(st);
        }
    }
}

六 、Set集合

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

import java.lang.ref.SoftReference;
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<>();
        //1、添加数据
        set.add("小米");
        set.add("苹果");
        set.add("vivo");
        set.add("oppo");
        System.out.println("元素个数:"+set.size());
        System.out.println(set.toString());//无顺序
        //2、删除元素
        //set.remove("苹果");
        //System.out.println("删除后:"+set.toString());
        //3、遍历
        //3、1 增强for
        System.out.println("------增强for遍历------");
        for (String str:set) {
            System.out.println(set.toString());
        }
        //3、2迭代器便利
        System.out.println("------迭代器遍历------");
        Iterator<String> it = set.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        //判断
        System.out.println(set.contains("小米"));
        System.out.println(set.isEmpty());
    }
}

七、Set实现类

  • HashSet [重点]:

    1. 基于HshCode计算元素的存放位置。

    2. 当存入元素的哈希码相同时,会调用equals进行确认,如果为true,则拒绝后者存入。

  • TreeSet:

    1. 基于排列顺序实现元素不重复。
    2. 实现了SortedSet接口,对集合元素自动排序。
    3. 元素对象的类型必须实现Comparable接口,指定排序规则。
    4. 通过compareTo方法确定是否为重复元素

7、1 HashSet的使用

  • HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。
  • HashSet 允许有 null 值。
  • HashSet 是无序的,即不会记录插入的顺序。
  • HashSet 不是线程安全的, 如果多个线程尝试同时修改 HashSet,则最终结果是不确定的。 您必须在多线程访问时显式同步对 HashSet 的并发访问。
  • HashSet 实现了 Set 接口。
  • 存储过程
    1. 根据hashcode计算保存的位置,如果此位置为空,则直接保存,不为空则执行第二部。
    2. 再执行equals方,如果equals方法为true,则认为是重复的,否则形成链表。
package com.Set.HashSet;
import java.util.HashSet;
import java.util.Iterator;
//HashSet的使用
//存储结构:数组+链表+红黑树
public class Demo01 {
    public static void main(String[] args) {
        //创建集合
        HashSet<String> hashSet = new HashSet<>();
        //添加元素
        hashSet.add("张三");
        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());
        //遍历
        System.out.println("-------增强for遍历-------");
        for (String str:hashSet) {
            System.out.println(str);
        }
        System.out.println("-------迭代器遍历-------");
        Iterator<String> it = hashSet.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        //判断
        System.out.println(hashSet.contains("李四"));
        System.out.println(hashSet.isEmpty());
    }
}
package com.Set.HashSet;

import java.util.Objects;

public class Person {
    private String name;
    private int 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 Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person() {
    }

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

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || this.getClass() != obj.getClass()) {
            return false;
        }
        Person person = (Person) obj;
        return Objects.equals(this.name, person.getName()) && this.age == person.getAge();

    }

    @Override
    public int hashCode() {
        //return Objects.hash(name, age);
        int n1 = this.name.hashCode();
        //(1) 31是一个质数,减少散列冲突(尽量是计算出的hashcode不冲突)
        //(2) 31 提高执行效率 31*i = (i<<5)-i
        int n2 = this.age+31;
        return n1*n2;
    }
}

package com.Set.HashSet;

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

//HashSet的使用
//存储结构:数组+链表+红黑树
/*
* (1)根据hashcode计算的保存位置,如果此位置为空,则直接把保存,如果不为空执行第二步
* (2)再执行equals方法,如果equals方法为true,则认为是重复的,否则,形成链表
* */
public class Demo02 {
    public static void main(String[] args) {
        //创建集合
        HashSet<Person> persons = new HashSet<>();
        //添加数据
        Person p1 = new Person("张三",18);
        Person p2 = new Person("李四",19);
        Person p3 = new Person("王五",20);
        Person p4 = new Person("王麻子",21);
        //1、添加元素
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        persons.add(p4);
        persons.add(new Person("王麻子",21));//这里的是新的一个对象,地址不相同,所以能添加进去
        //perosns.add(p4);//重复元素不能添加
        System.out.println("元素个数:"+persons.size());
        System.out.println(persons.toString());

        //2、删除
       // persons.remove(p1);
        //persons.remove(new Person("王麻子",21));
        // 现在能删除,没有重写hashCode和equals方法的时候是不可以的
        System.out.println("删除之后:"+persons.size());
        System.out.println(persons.toString());
        //3、遍历
        System.out.println("------增强for遍历-------");
        for (Person perosn:persons) {
            System.out.println(perosn.toString());
        }
        System.out.println("------迭代器遍历-------");
        Iterator<Person> it = persons.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
        //4、判断
        System.out.println(persons.contains(p1));
        System.out.println(persons.isEmpty());
        System.out.println(persons.contains(new Person("张三",18)));//true
    }
}

7、2 TreeSet的使用

  • TreeSet:
    1. 基于排列顺序实现元素不重复。
    2. 实现了SortedSet接口,对集合元素自动排序。
    3. 元素对象的类型必须实现Comparable接口,指定排序规则。
    4. 通过compareTo方法确定是否为重复元素
    5. 出现如例子类似的情况时候需要在Comparable实现类里重写compareTo方法,定义比较规则

例子 :

package com.Set.HashSet;

import java.util.Objects;

public  class Person implements Comparable<Person> {
    private String name;
    private int 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 Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person() {
    }

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

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || this.getClass() != obj.getClass()) {
            return false;
        }
        Person person = (Person) obj;
        return Objects.equals(this.name, person.getName()) && this.age == person.getAge();

    }

    @Override
    public int hashCode() {
        //return Objects.hash(name, age);
        int n1 = this.name.hashCode();
        //(1) 31是一个质数,减少散列冲突(尽量是计算出的hashcode不冲突)
        //(2) 31 提高执行效率 31*i = (i<<5)-i
        int n2 = this.age+31;
        return n1*n2;
    }

    @Override
    public int compareTo(Person person) {
        int n1 = this.getName().compareTo(person.getName());
        int n2 = this.age-person.getAge();
        return n1==0?n2:n1;
        //先按姓名比,再按年龄比
    }
}
package com.Set.TreeSet;
//TreeSet的使用
//存储结构 红黑树
//要求:元素必须要实现Comparable接口 compareTo()方法的返回值为0 认为是重复元素
import com.Set.HashSet.Person;

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

public class Demo02 {
    public static void main(String[] args) {
        //创建集合
       TreeSet<Person> persons = new TreeSet<>();
        Person p1 = new Person("zhangsan",18);
        Person p2 = new Person("lisi",19);
        Person p3 = new Person("wangwu",20);
        Person p4 = new Person("wangmazi",21);
        Person p5 = new Person("wangmazi",22);
        //1、添加元素
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        persons.add(p4);
        persons.add(p5);
        System.out.println("元素个数:"+persons.size());
        System.out.println(persons.toString());
        //2、删除
        persons.remove(p1);
        //persons.remove(new Person("lisi",19));
        System.out.println("删除之后:"+persons.size());
        System.out.println(persons.toString());
        //3、遍历
        System.out.println("------增强for------");
        for (Person person:persons) {
            System.out.println(person);
        }
        System.out.println("------迭代器------");
        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());

    }
}

7、3 Comparator接口

  • TreeSet的使用

  • 注意:

    1. 自定义比较规则和comparable中的compare方法和compareTo的返回值添加负号和不添加负号的区别、

    2. 如果是int类型添加负号是从大到小排序,否则是从小到大排序,入如果是String类型的比较,返回值添加负号是按字母表逆序排序,否则按正序排序。

    TreeSet<String> strings = 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;//n2大于0,按字母表正序,否则按逆序。n2大于0 按length从小到大,否则从大到小
        }
    });
    
  • Comparator:实现定制比较(比较器)

    //创建集合,并指定了比较规则
            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;//如果年龄相等比较名字,如果年龄不相等则比较年龄
                }
            });
    
  • Comparable:可比较的

package com.Set.TreeSet;

import com.Set.HashSet.Person;

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

public class Demo03 {
    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("zhangsan",18);
        Person p2 = new Person("lisi",19);
        Person p3 = new Person("wangwu",20);
        Person p4 = new Person("lisi",20);
        //1、添加元素
        persons.add(p1);
        persons.add(p2);
        persons.add(p3);
        persons.add(p4);
        System.out.println("元素个数:"+persons.size());
        System.out.println(persons.toString());
    }
}

7、4 TreeSet案例

  • 通过TreeSet 实现字符串按长度添加到集合
package com.Set.TreeSet;

import java.util.Comparator;
import java.util.TreeSet;
/*
* 实现字符串类型按长度排序
* */
public class Demo04 {
    public static void main(String[] args) {
        TreeSet<String> strings = 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;//n2大于0,按字母表正序,否则按逆序。n2大于0 按length从小到大,否则从大到小
            }
        });
        strings.add("helloworld");
        strings.add("lisi");
        strings.add("wangwu");
        strings.add("beijing");
        strings.add("xian");
        strings.add("nanjing");
        System.out.println("原素材个数:"+strings.size());
        System.out.println(strings.toString());
    }
}

八、Map体系集合

Map 体系集合

  • Map接口的特点:
    1. 用于存储任意键值对(Key-Value)
    2. 键:无序、无下标、不允许重复(唯一)
    3. 值:无序、无下标、允许重复
  • 方法:
    1. V put(K key , V value):将对象存入到集合中,关联键值。key重复则覆盖原值。
    2. Object get(Object key):根据键获取对应的值。
    3. keySet(K):返回所有的key。(重点)
    4. Collection values:返回包含所有值的Collection集合。
    5. Set<Map.Entry<K,V>>:键值匹配的Set集合。

8、1 Map接口使用

  • 创建map集合
 //创建map集合
          Map<String,String> map = new HashMap<>();
  • 添加元素
 //1、添加元素
         map.put("名字","张三");
         map.put("年龄","18");
         map.put("性别","男");
        // map.put("专业","计算机");//添加重复的,value会替换掉之前的value
  • 删除元素
 //2、删除
        map.remove("专业");
  • 遍历map集合
//3、遍历
        System.out.println("-------3、1keySet-------");
       //Set<String> keySet= map.keySet();
        for (String key: map.keySet()) {
            System.out.println(key+":"+map.get(key));
        }
        System.out.println("-------3、2 entrySet-------");
        //Set<Map.Entry<String,String>> entries =  map.entrySet();
        for (Map.Entry<String,String> entry: map.entrySet()) {
            System.out.println(entry.getKey()+":"+ entry.getValue());
        }
  • 判断
   //4、判断
        System.out.println(map.containsKey("姓名"));
        System.out.println(map.containsValue("张三"));
        System.out.println(map.isEmpty());
package com.Map;
/*
* Map接口的使用
* 特点:(1)存储键值对 (2)键不能重复,值可以重复 (3)无序
* */

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

public class Demo01 {
    public static void main(String[] args) {
        //创建map集合
        Map<String,String> map = new HashMap<>();
        //1、添加元素
        map.put("名字","张三");
        map.put("年龄","18");
        map.put("性别","男");
        map.put("专业","软件工程");
       // map.put("专业","计算机");//添加重复的,value会替换掉之前的value
        System.out.println("元素个数:"+map.size());
        System.out.println(map.toString());
        //2、删除
        map.remove("专业");
        System.out.println("删除之后:"+map.size());
        System.out.println(map.toString());
        //3、遍历
        System.out.println("-------3、1keySet-------");
       //Set<String> keySet= map.keySet();
        for (String key: map.keySet()) {
            System.out.println(key+":"+map.get(key));
        }
        System.out.println("-------3、2 entrySet-------");
        //Set<Map.Entry<String,String>> entries =  map.entrySet();
        for (Map.Entry<String,String> entry: map.entrySet()) {
            System.out.println(entry.getKey()+":"+ entry.getValue());
        }
        //4、判断
        System.out.println(map.containsKey("姓名"));
        System.out.println(map.containsValue("张三"));
        System.out.println(map.isEmpty());

    }
}

九、Map集合的实现类

  • HashMap[重点]:
    • JDK1.2版本,线程不安全,运行效率快;允许null的值和null键。
  • HashTable:
    • JDK1.0版本,线程安全,运行效率慢;不允许null的值和null键。
  • Properties:
    • HashTable的子类。要求key和Value都是String。通常用于配置文件的读取。
  • TreeMap:
    • 实现了SortedMap接口(是Map的子接口),可以对Key自动排序。

9、1 HashMap

  • HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。
  • HashMap 实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步。允许null的值和null键。
  • HashMap 是无序的,即不会记录插入的顺序。
  • HashMap 继承于AbstractMap,实现了 Map、Cloneable、java.io.Serializable 接口。
  • 存储结构:哈希表:数组+链表+红黑树
  • 使用key的hashcode和equals作为重复一依据
  1. 创建HashMap集合
 //创建集合
        HashMap<Student,String> students = new HashMap<>();
  1. 添加元素
//1、添加元素
Student s1 = new Student("张三",111);
Student s2 = new Student("李四",112);
Student s3 = new Student("王五",113);
students.put(s1,"北京");
students.put(s2,"天津");
students.put(s3,"上海");
students.put(new Student("张三",111),"北京");
  1. 删除元素
//2、删除
//students.remove(s1);
System.out.println("删除之后:"+students.size());
System.out.println(students.toString());
  1. 遍历HashMap集合
//3、遍历
Set<Student> studentSet = students.keySet();
System.out.println("-------3、1 keySet--------");
for (Student key: studentSet) {
    System.out.println(key+":"+students.get(key));
}
System.out.println("-------3、1 keySet--------");
Set<Map.Entry<Student,String>> entries = students.entrySet();
for (Map.Entry<Student,String> entry:entries) {
    System.out.println(entry.getKey()+":"+entry.getValue());
}
  1. 判断
//4、判断
System.out.println(students.containsKey(s1));
System.out.println(students.containsKey(new Student("张三",111)));
System.out.println(students.containsValue("北京"));
System.out.println(students.isEmpty());

9、2 HshMap源码分析

  • static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // HshMap初始容量大小

  • static final int MAXIMUM_CAPACITY = 1 << 30; // HshMap的数组最大容量

  • 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; //哈希表中的数组

  • size ; //元素个数

  • 无参构造

public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
  • put方法
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}
  • 总结:

    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以后时是尾插入

9、3 HashTable

  • 该类实现了一个哈希表,它将键映射到值。 任何非null对象都可以用作键值或值。
  • 方法和HashMap的方法类似。
  • 子类Properties(IO流中使用)
    • Properties类表示一组持久的属性。 Properties可以保存到流中或从流中加载。 属性列表中的每个键及其对应的值都是一个字符串。

9、4 TreeMap

  • 实现了SortedMap接口(是Map的子接口),可以对Key自动排序。
  • 存储结构:红黑树
  • 方法和HashMap的方法类似
  1. 创建集合和自定义比较规则
//创建集合
        TreeMap<Student,String> treeMap = new TreeMap<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                int n1 = o1.getStuNo()-o2.getStuNo();
                int n2 = o1.getName().compareTo(o2.getName());
                return n1==0 ? n2:n1;
            }
        });
  1. 添加元素
//1、添加元素
Student s1 = new Student("张三",111);
Student s2 = new Student("李四",112);
Student s3 = new Student("王五",113);

treeMap.put(s1,"北京");
treeMap.put(s2,"天津");
treeMap.put(s3,"上海");
treeMap.put(new Student("王五",113),"南京");
  1. 删除元素
//treeMap.remove(new Student("王五",113));
//treeMap.remove(s1);
  1. 遍历
//3、遍历
System.out.println("---------3、1 keySet()-------");
//Set<Student> keyset = treeMap.keySet();
for (Student st:treeMap.keySet()) {
    System.out.println(st+"-----"+treeMap.get(st));
}
System.out.println("---------3、2 entrySet()-------");
for (Map.Entry<Student,String> entry: treeMap.entrySet()) {
    System.out.println(entry.getKey()+"-----"+entry.getValue());
}
  1. 判断
//4、判断
System.out.println(treeMap.containsKey(s1));
System.out.println(treeMap.containsValue("北京"));

十、Collection工具类

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

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

/*
* Collections工具类的使用
* */
public class Demo01 {
    public static void main(String[] args) {
        //创建集合
        List<Integer> list = new ArrayList<>();
        list.add(5);
        list.add(20);
        list.add(30);
        list.add(36);
        list.add(34);
        list.add(44);
        //sort排序
        System.out.println("排序之前:"+list.toString());
        Collections.sort(list);
        System.out.println("排序之后:"+list.toString());

        //binarySearch 二分查找
        int i = Collections.binarySearch(list,36);
        System.out.println("找到的位置:"+i);
        //copy 复制
        List<Integer> dest = new ArrayList<>();
        for (int j = 0; j < list.size(); j++) {
            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 转为数组
        System.out.println("-----List 转为数组----");
        Integer[] arr =  list.toArray(new Integer[0]);
        System.out.println("数组长度:"+arr.length);
        System.out.println("转换的数组:"+Arrays.toString(arr));
        //数组转为集合
        System.out.println("-----List 转为数组----");
        String[] strings ={"张三","李四","王五","王麻子"};
        System.out.println("----原数组为:------");
        for (String string : strings) {
            System.out.print(string + "\t");
        }
        System.out.println();
        List<String> list1 =  Arrays.asList(strings);
        //数组转换为集合后,不能添加和删除,因为数组的长度是固定的,转换为集合后也是固定的
        System.out.println("数组转换为集合:"+list1.size());
        System.out.println("数组转换为集合:"+list1.toString());
        //把基本类型的数组转化为集合需要先转换为包装类
        Integer[] nums = {1,4,5,23,6};
        List<Integer> list2 = Arrays.asList(nums);
        System.out.println(list2);


    }
}

十一、总结

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值