当前位置: 首页 > news >正文

DAY08 List接口、Collections接口、Set接口

学习目标

能够说出List集合特点
	1.有序
	2.允许存储重复的元素
	3.有带索引的方法(练习 add,remove,set,get)
能够使用集合工具类
	Collections:
		static void sort(List<T> list) 根据元素的自然顺序 对指定列表按升序进行排序。
        static <T> void sort(List<T> list, Comparator<? super T> c) 根据指定比较器产生的顺序对指定列表进行排序。
        static void shuffle(List<?> list)  随机打乱集合中元素的顺序
能够使用Comparator比较器进行排序
	Collections.sort(list01, new Comparator<Integer>() {
		@Override
		public int compare(Integer o1, Integer o2) {
			//降序: o2-o1  升序:o1-o2
			return o2-o1;
		}
	});
能够使用可变参数
	public static void method(int...arr){}
	调用method方法,参数是一个可变参数,可以接收任意个同种数据类型的数据
	method(),method(10),method(10,20)...
能够说出Set集合的特点
	1.不允许存储重复的元素
	2.不包含带索引的方法
能够说出哈希表的特点
	JDK1.8之前:数组+单向链表
	JDK1.8之后:数组+单向链表|数组+红黑树
	查询的效率高
使用HashSet集合存储自定义元素(重点)
	想要保证存储的元素(Person对象,Student对象...)同名和同年龄的人视为同一个人
	自定义类型(Person对象,Student对象...)必须重写hashCode和equals方法

第一章 List接口

1.List接口的概述

/*
    java.uil.List<E>接口 extends Collection<E>接口
    List接口的特点:
        1.是一个有序的集合:存储元素和取出元素的顺序是一致的  存储:123  取出:123
        2.允许存储重复的元素  add(10)  add(10)
        3.包含一些带索引的特有方法
    List接口特有的带索引的方法:
        void add(int index, E element)  在指定索引处,添加一个新的元素
        E get(int index)  获取指定索引处的元素
        E remove(int index)  移除并返回指定索引处的元素,返回的就是被移除的元素
        E set(int index, E element)  替换并返回指定索引处的元素,返回的是被替换的元素
    注意:
        使用带索引的方法,必须防止索引越界异常(不要超过集合索引的使用范围:0-->集合的长度-1)         
 */

2.List接口中常用的方法(重点)

package com.itheima.demo01List;

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

/*
    索引越界异常:
        IndexOutOfBoundsException:索引越界异常,集合会报
            ArrayIndexOutOfBoundsException:数组索引越界异常
            StringIndexOutOfBoundsException:字符串的索引越界异常
 */
public class Demo01List {
    public static void main(String[] args) {
        //创建List集合对象,给集合添加元素
        List<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("aaa");
        list.add("ddd");         //  0    1   2    3     4
        System.out.println(list);//[aaa, bbb, ccc, aaa, ddd]

        //void add(int index, E element)  在指定索引处,添加一个新的元素
        //在索引2处添加一个新的元素"哈哈"
        list.add(2,"哈哈");
        System.out.println(list);//[aaa, bbb, 哈哈, ccc, aaa, ddd]


        //E get(int index)  获取指定索引处的元素
        String s1 = list.get(0);
        System.out.println("s1:"+s1);//s1:aaa
        String s2 = list.get(1);
        System.out.println("s2:"+s2);//s2:bbb
        //list.get(10);//IndexOutOfBoundsException: Index: 10, Size: 6

        //E remove(int index)  移除并返回指定索引处的元素,返回的就是被移除的元素
        System.out.println(list);//[aaa, bbb, 哈哈, ccc, aaa, ddd]
        //删除集合中第二个aaa
        String s3 = list.remove(4);
        System.out.println("s3:"+s3);//s3:aaa
        System.out.println(list);//[aaa, bbb, 哈哈, ccc, ddd]

        //E set(int index, E element)  替换并返回指定索引处的元素,返回的是被替换的元素
        //把索引2处哈哈,替换为呵呵
        String s4 = list.set(2, "呵呵");
        System.out.println("s4:"+s4);//s4:哈哈
        System.out.println(list);//[aaa, bbb, 呵呵, ccc, ddd]
        System.out.println("------------------------------------------");
        //使用普通for循环遍历List集合  list.fori
        for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            System.out.println(s);
        }
        System.out.println("------------------------------------------");
        //使用增强for循环遍历List集合 list.for
        for (String s : list) {
            System.out.println(s);
        }
        System.out.println("------------------------------------------");
        //使用迭代器遍历List集合
        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }
    }
}

3.ArrayList集合(数组)

/*
	java.util.ArrayList<E>集合 implements List<E>接口
	List 接口的大小可变数组的实现。
	ArrayLis集合底层采用的就是数组结构:查询快,增删慢
	工作中:查询多的时候使用,不对集合的长度进行修改(添加,删除)
*/
public class ArrayList<E>{
    transient Object[] elementData = {};
    add方法:
    list.add("aaa");	
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    ...
    //add方法底层:创建一个新的数组,长度是源数组长度+1,把源数组中的元素使用System类中的arraycopy方法复制到新的数组中    
    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }   
    
}

4.LinkedList集合(双向链表)

a.LinkedList集合概述

请添加图片描述

/*
	java.util.LinkedList<E> implements List<E>接口
	List 接口的链接列表实现。
	LinkedList集合底层是一个双向链表:查询慢,增删快
	双向:是一个有序的集合
	LinkedList集合中含有一些操作链表首尾元素的方法:
		public void addFirst(E e) :将指定元素插入此列表的开头。
		public void push(E e) :将元素推入此列表所表示的堆栈。
        public void addLast(E e) :将指定元素添加到此列表的结尾。
        
        public E getFirst() :返回此列表的第一个元素。
        public E getLast() :返回此列表的最后一个元素。
        public boolean isEmpty() :如果列表不包含元素,则返回true
        
        public E removeFirst() :移除并返回此列表的第一个元素。
        public E pop() :从此列表所表示的堆栈处弹出一个元素。
        public E removeLast() :移除并返回此列表的最后一个元素。

   注意:
   		使用LinkedList集合特有的方法,不能使用多态创建对象
   		List<String> list = new LinkedList<>();弊端:不能是实现类特有的方法
   		LinkedList<String> linked = (LinkedList<String>)list; 向下转型
   		Collection<String> list = new LinkedList<>();弊端:不能是实现类特有的方法
   		LinkedList<String> list = new LinkedList<>();
*/

b.LinkedList集合特有的方法(使用)

package com.itheima.demo01List;

import java.util.LinkedList;

/*
    LinkedList集合特有的方法
 */
public class Demo02LinkedList {
    public static void main(String[] args) {
        show04();
    }

    /*
        public E removeFirst() :移除并返回此列表的第一个元素。
        public E pop() :从此列表所表示的堆栈处弹出一个元素。 此方法等效于 removeFirst()。
        public E removeLast() :移除并返回此列表的最后一个元素。
     */
    private static void show04() {
        LinkedList<String> linked = new LinkedList<>();
        linked.add("aaa");
        linked.add("bbb");
        linked.add("ccc");
        linked.add("ddd");
        System.out.println(linked);//[aaa, bbb, ccc, ddd]

        if(linked.size()!=0){
            //String first = linked.removeFirst();
            String first = linked.pop();
            System.out.println("first:"+first);//first:aaa

            String last = linked.removeLast();
            System.out.println("last:"+last);//last:ddd

            System.out.println(linked);//[bbb, ccc]
        }
    }

    /*
        public E getFirst() :返回此列表的第一个元素。
        public E getLast() :返回此列表的最后一个元素。
        public boolean isEmpty() :如果列表不包含元素,则返回true
     */
    private static void show03() {
        LinkedList<String> linked = new LinkedList<>();
        linked.add("aaa");
        linked.add("bbb");
        linked.add("ccc");
        linked.add("ddd");

        linked.clear();//清空集合

        //为了防止NoSuchElementException:没有元素异常,增加一个判断,集合不是空的在获取
        if(!linked.isEmpty()){//return size() == 0;
            String first = linked.getFirst();
            System.out.println("first:"+first);//first:aaa

            String last = linked.getLast();
            System.out.println("last:"+last);//last:ddd
        }

        if(linked.size()!=0){
            String first = linked.getFirst();
            System.out.println("first:"+first);//first:aaa

            String last = linked.getLast();
            System.out.println("last:"+last);//last:ddd
        }
    }

    private static void show02() {
        LinkedList<String> linked = new LinkedList<>();
        linked.addFirst("1");
        linked.addFirst("2");
        linked.addFirst("3");
        linked.addLast("a");
        linked.addLast("b");
        linked.addLast("c");
        System.out.println(linked);//[3, 2, 1, a, b, c]
    }

    /*
        public void addFirst(E e) :将指定元素插入此列表的开头。
		public void push(E e) :将元素推入此列表所表示的堆栈。此方法等效于 addFirst(E)。
        public void addLast(E e) :将指定元素添加到此列表的结尾。此方法等效于add()
     */
    private static void show01() {
        LinkedList<String> linked = new LinkedList<>();
        linked.add("aaa");
        linked.add("bbb");
        linked.add("ccc");
        linked.add("ddd");
        System.out.println(linked);//[aaa, bbb, ccc, ddd]

        //public void addFirst(E e) :将指定元素插入此列表的开头。
        //linked.addFirst("www");
        linked.push("www");
        System.out.println(linked);//[www, aaa, bbb, ccc, ddd]

        //public void addLast(E e) :将指定元素添加到此列表的结尾。此方法等效于add()
        //linked.addLast("com");
        linked.add("com");
        System.out.println(linked);//[www, aaa, bbb, ccc, ddd, com]
    }
}

c.LinkedList源码分析(了解即可)

5.Vector集合(面试)

/*
	java.util.Vector<E> implements List<E>(jdk1.2之后)
	Vector是JDK1.0时期存在的单列集合,Collection下边的其他集合(ArrayList,LinkedList...)是JDK1.2之后出现的
	Vector 类可以实现可增长的对象数组。Vector集合底层和ArrayList集合是一样的,也是一个数组结构(查询快,增删慢)
	Vector集合1.0时期有一些特有的方法:
    	void addElement(E obj)  往集合中添加元素
    	Enumeration<E> elements() 返回此向量的组件的枚举。 
    	Enumeration<E>接口:向量枚举,是1.0时期的迭代器
    		boolean hasMoreElements()  判断集合中还有没有元素==>hasNext
    		E nextElement()  取出集合的元素==>next
	与新 collection 实现不同,Vector 是同步的。 
	同步技术:可以保证多线程的安全
    同步技术:集合存储数据效率低
    所以Vector集合被效率更高的ArrayList集合取代了
*/

第二章 Collections类

1.Collections的常用功能(重点)

package com.itheima.demo02Collections;

import java.util.ArrayList;
import java.util.Collections;

/*
    java.util.Collections:操作集合的工具类,里边的方法都是静态的
        通过类名.方法名(参数)可以直接使用
    常用的方法:
        static void  sort(List<T> list) 根据元素的自然顺序 对指定集合按升序进行排序。
        static <T> void sort(List<T> list, Comparator<? super T> c)  根据指定比较器产生的顺序对指定列表进行排序。
        static void shuffle(List<?> list)  随机打乱集合中元素的顺序
     注意:
        以上3个方法,参数都是List,只能传递List接口下的实现类对象(ArrayList,LinkedList),不能使用Set接口下的集合
 */
public class Demo01Collections {
    public static void main(String[] args) {
        //创建ArrayList集合对象
        ArrayList<Integer> list01 = new ArrayList<>();
        list01.add(1);
        list01.add(3);
        list01.add(2);
        list01.add(4);
        System.out.println(list01);//[1, 3, 2, 4]

        /*
            static void  sort(List<T> list) 根据元素的自然顺序 对指定集合按升序进行排序。
            升序: 小->大
            降序: 大->小
         */
        Collections.sort(list01);
        System.out.println(list01);//[1, 2, 3, 4]

        /*
            static void shuffle(List<?> list)  随机打乱集合中元素的顺序
         */
        Collections.shuffle(list01);
        System.out.println(list01);//[4, 1, 3, 2]  [3, 4, 1, 2]  [2, 4, 1, 3]...

        ArrayList<String> list02 = new ArrayList<>();
        list02.add("ab");
        list02.add("aa");
        list02.add("12");
        list02.add("AB");
        list02.add("CC");
        System.out.println(list02);//[ab, aa, 12, AB, CC]

        /*
            static void  sort(List<T> list) 根据元素的自然顺序 对指定集合按升序进行排序。
            升序: 小->大
            降序: 大->小
            自然顺序:编码表的顺序  ASCII  0:48   A:65   a:97
         */
        Collections.sort(list02);
        System.out.println(list02);//[12, AB, CC, aa, ab]
    }
}

2.Comparator比较器(重点)

package com.itheima.demo02Collections;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/*
    static <T> void sort(List<T> list, Comparator<? super T> c)  根据指定比较器产生的顺序对指定列表进行排序。
    参数:
        List<T> list:要排序的List集合
        Comparator<? super T> c:对集合进行排序的比较器
        jav.util.Comparator<T>接口
            强行对某个对象 collection 进行整体排序 的比较函数。
        Comparator接口中抽象方法:
            int compare(T o1, T o2) 比较用来排序的两个参数。
            参数:
                 T o1, T o2:依次比较的集合中的元素[1,1,3, 2, 4]
            比较的规则:(重点)
                升序: o1-o2
                降序: o2-o1
                两个元素相等: o1==o2
 */
public class Demo02Collections {
    public static void main(String[] args) {
        //创建ArrayList集合对象
        ArrayList<Integer> list01 = new ArrayList<>();
        list01.add(1);
        list01.add(3);
        list01.add(2);
        list01.add(4);
        System.out.println(list01);//[1, 3, 2, 4]

        //使用Collections集合中工具类中的sort方法,对集合中的元素根据比较器产生的规则排序
        Collections.sort(list01, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                //降序: o2-o1
                return o2-o1;
            }
        });
        System.out.println(list01);//[4, 3, 2, 1]

        //使用Collections集合中工具类中的sort方法,对集合中的元素根据比较器产生的规则排序
        Collections.sort(list01, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                //升序: o1-o2
                return o1-o2;
            }
        });
        System.out.println(list01);//[1, 2, 3, 4]
    }
}

扩展:

package com.itheima.demo02Collections;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Demo03Collections {
    public static void main(String[] args) {
        //创建ArrayList集合,泛型使用Person
        ArrayList<Person> list = new ArrayList<>();
        list.add(new Person("azhansan",18));
        list.add(new Person("lisi",20));
        list.add(new Person("wangwu",19));
        list.add(new Person("bzhaoliu",18));
        list.add(new Person("tianqi",21));
        //使用Collections集合工具类中的方法sort,根据比较器产生的规则进行排序(年龄升序排序)
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                //年龄升序排序
                return o1.getAge()-o2.getAge();
            }
        });
        System.out.println(list);//[Person{name='zhansan', age=18}, Person{name='zhaoliu', age=18}, Person{name='wangwu', age=19}, Person{name='lisi', age=20}, Person{name='tianqi', age=21}]

        //按照两个人年龄升序排序,如果两个人年龄相同,按照姓名的首字母降序排序
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                //按照两个人年龄升序排序
                int a = o1.getAge()-o2.getAge();
                //判断两个人的年龄是否相等
                if(a==0){
                    //按照姓名的首字母降序排序
                    a = o2.getName().charAt(0)-o1.getName().charAt(0);
                }
                return a;
            }
        });
        System.out.println(list);
        //System.out.println("aaa".charAt(0)-"bbb".charAt(0));

        //int compareTo(String anotherString) 按字典(编码表)顺序比较两个字符串。
        //按照两个人年龄升序排序,如果两个人年龄相同,按照姓名进行排序
        Collections.sort(list, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                //按照两个人年龄升序排序
                int a = o1.getAge()-o2.getAge();
                //判断两个人的年龄是否相等
                if(a==0){
                    //按照姓名进行排序
                    a = o2.getName().compareTo(o1.getName());
                }
                return a;
            }
        });
        System.out.println(list);
    }
}
package com.itheima.demo02Collections;

public class Person {
    private String name;
    private int age;

    public Person() {
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "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;
    }
}

3.可变参数

package com.itheima.demo03VarArgs;

import java.util.ArrayList;

/*
    可变参数
        是JDK1.5之后出现的新特性
    作用:
        当我们定义一个方法的时候,方法的参数类型已经确定了,但是参数的个数不确定,就可以使用可变参数
    格式:
        修饰符 返回值类型 方法名(数据类型...变量名){
            方法体;
        }
     数据类型...变量名:叫可变参数,代表形式参数可以接收任意个数据
     调用参数是可变参数的方法,参数的个数可以传递任意个(不传递,1,2,3,4,5,6....n...)
     原理:
        可变参数底层就是一个数组,传递不同个数个参数,就会创建不同长度的数组,来接收这些参数
 */
public class Demo01VarArgs {
    public static void main(String[] args) {
        //getSum();
        //getSum(10);
        //getSum(10,20);
        int s = getSum(10, 20, 30, 40, 50, 60, 70, 80, 90, 100);
        System.out.println(s);//550

        int[] arr = {1,2,3};
        int s2 = getSum(arr);
        System.out.println(s2);

        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        //int s3 = getSum(list);
        //System.out.println(s3);

        method1(10,1.1,"aaa",1,2,3,4,4,5,65,6,7,7,8,8,8);
        method2(1,2,3,4,4,5,65,6,7,7,8,8,8);
        method2("a","v","c");
    }
    
    //可变参数的注意事项
    //1.一个方法的参数只能写一个可变参数
    //public static void method(int...a,String...s){}
    //2.方法的参数列表有多个参数,可变参数必须写在末尾
    //public static void method(int a,double b,int...d,String c){}//Vararg parameter must be the last in the list
    //public static void method(int a,double b,String c,int...d){}
    //可变参数终极写法
    public static void method1(Object...obj){}
    public static <T> T[] method2(T...t){
        return t;
    }

    /*
        定一个计算n个(不知道传递多少个整数,0,1,2,3,4,..)int类型整数和的方法
        已知:
            参数的数据类型:int类型
        未知:
            不知道计算多少个整数的和
        所以我们就可以使用可变参数,作为方法的参数使用,可以接收任意个同种数据类型的参数
        getSum();传递0个参数,那么可变参数就会创建一个长度为0的数组,用来接收参数 new int[]{ };
        getSum(10);传递1个参数,那么可变参数就会创建一个长度为1的数组,用来接收参数 new int[]{10};
        getSum(10,20);传递2个参数,那么可变参数就会创建一个长度为2的数组,用来接收参数 new int[]{10,20};
        ...
        getSum(10,20,30,40,50,60,70,80,90,100);传递10个参数,那么可变参数就会创建一个长度为10的数组,用来接收参数 new int[]{10,20,30,40,50,60,70,80,90,100};
     */
    public static int getSum(int...arr){
        //System.out.println(arr);//[I@4554617c 数组的地址值
        //System.out.println(arr.length);//0,1,2...数组的长度
        //对数组中的元素进行求和
        //定义一个变量,初始值为0,记录累加求和
        int sum = 0;
        //遍历数组(可变参数),获取数组中的每一个元素
        for (int i : arr) {
            //累加求和
            sum+=i;
        }
        //把和返回
        return sum;
    }

    /*
        定义计算四个int类型整数和的方法
     */
    /*public static int getSum(int a,int b,int c,int d){
        return a+b+c+d;
    }*/

    /*
        定义计算三个int类型整数和的方法
     */
    /*public static int getSum(int a,int b,int c){
        return a+b+c;
    }*/

    /*
        定义计算两个int类型整数和的方法
     */
    /*public static int getSum(int a,int b){
        return a+b;
    }*/
}

重点:记住可变参数可以接收任意个同种数据类型的元素

4.Collections集合工具类中的方法addAll

package com.itheima.demo03VarArgs;

import java.util.ArrayList;
import java.util.Collections;

/*
    java.util.Collections:操作集合的工具类,里边的方法都是静态的
    static <T> boolean  addAll(Collection<T> c, T... elements) 将所有指定元素添加到指定 collection 中。
    给集合添加多个元素
 */
public class Demo02Collections {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        //list.add(1);
        //list.add(2);
        //list.add(3);
        //list.add(4);
        //list.add(5);

        Collections.addAll(list,1,2,3,4,5);
        System.out.println(list);

        ArrayList<String> list02 = new ArrayList<>();
        Collections.addAll(list02,"a","b","c","d","e");
        System.out.println(list02);

        //可变参数底层就是一个数组,传递可变参数的地方都可以传递数组
        String[] arr = {"aaa","bbb","ccc","ddd"};
        Collections.addAll(list02,arr);
        System.out.println(list02);//[a, b, c, d, e, aaa, bbb, ccc, ddd]
    }
}

第三章 Set接口

1.Set接口的介绍(记住)

/*
	java.util.Set<E>接口 extends Collection<E>接口
	Set接口的特点:
		1.不允许存储重复的元素  add(1) add(1) ==>集合中只有一个1
		2.不包含带索引的方法,里边的方法和Collection接口是一样
*/

2.HashSet集合的介绍和基本使用(重点)

package com.itheima.demo04Set;

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

/*
    java.util.HashSet<E>集合 implements Set<E>接口
        此类实现 Set 接口,由哈希表(实际上是一个 HashMap 实例)支持。
        它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变。此类允许使用 null 元素。
     HashSet集合的特点:
        1.不允许存储重复的元素
        2.不包含带索引的方法(不能使用普通的for循环遍历Set集合)
        3.是一个无序的集合(存储的元素和取出的元素顺序有可能不一致)
        4.底层是一个哈希表
            JDK1.8之前:数组+单向链表
            JDK1.8之后:数组+单向链表|数组+红黑树(可以提高查询的效率)
 */
public class Demo01HashSet {
    public static void main(String[] args) {
        show02();
    }

    private static void show02() {
        //创建HashSet集合对象
        HashSet<String> set = new HashSet<>();
        boolean b1 = set.add("aaa");
        System.out.println("b1:"+b1);//b1:true
        set.add("bbb");
        set.add("ccc");
        boolean b2 = set.add("aaa");
        System.out.println("b2:"+b2);//b2:false
        set.add("ddd");
        //使用增强for循环遍历Set集合
        for (String s : set) {
            System.out.println(s);
        }
    }

    private static void show01() {
        //创建HashSet集合对象
        HashSet<Integer> set = new HashSet<>();
        set.add(1);
        set.add(3);
        set.add(2);
        set.add(4);
        set.add(1);
        //使用迭代器遍历Set集合
        Iterator<Integer> it = set.iterator();
        while (it.hasNext()){
            Integer s = it.next();
            System.out.println(s);
        }
    }
}

3.哈希值(了解)

package com.itheima.demo04Set;

/*
    哈希值:
        是一个十进制的整数,由操作系统随机给出,我们打印对象的地址值,使用的就是哈希值(逻辑地址)
        对象在内存中实际存储的地址,并不是哈希值的地址(物理地址)
    Object类有获取对象哈希值的方法:
        int hashCode() 返回该对象的哈希码值。
        hashCode方法的底层源码:
            public native int hashCode();
            native:调用的是操作系统底层的方法,不是由java语言编写的
 */
public class Demo02HashCode {
    public static void main(String[] args) {
        //Person类默认继承了Object类,所以可以使用Object类中的hashCode方法
        Person p1 = new Person();
        int h1 = p1.hashCode();
        System.out.println(h1);//1163157884==>1

        Person p2 = new Person();
        int h2 = p2.hashCode();
        System.out.println(h2);//1956725890==>1

        /*
            Object类的toString方法
                String toString() 返回该对象的字符串表示。
            底层源码:
                public String toString() {
                    return getClass().getName() + "@" + Integer.toHexString(hashCode());
                }
                getClass().getName():使用反射技术,获取包名+类名  com.itheima.demo04Set.Person
                "@":字符串原样输出
                Integer.toHexString(hashCode()):把hashCode方法返回的十进制的整数,转换为十六进制
         */
        System.out.println(p1.toString());//com.itheima.demo04Set.Person@4554617c==>1
        System.out.println(p2.toString());//com.itheima.demo04Set.Person@74a14482==>1
        System.out.println(p1==p2);//比较的是对象的地址值 false
    }
}
package com.itheima.demo04Set;

public class Person extends Object {
    @Override
    public int hashCode() {
        return 1;
    }
}

4.String类的哈希值(了解)

package com.itheima.demo04Set;

/*
    String类的哈希值(了解)
        String类重写了Object类的hashCode方法
        规则:
            相同的字符串返回的哈希值是一样的
            不同的字符串,计算出的哈希值也有可能是一样
 */
public class Demo03StringHashCode {
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("abc");
        System.out.println(s1.hashCode());//96354
        System.out.println(s2.hashCode());//96354
        System.out.println(s1==s2);//false

        System.out.println("重地".hashCode());//1179395
        System.out.println('重'+0);//37325
        System.out.println('地'+0);//22320

        System.out.println("通话".hashCode());//1179395
    }
}

请添加图片描述

5.HashSet集合存储数据的结构(哈希表)

请添加图片描述

6.使用HashSet集合存储String不重复的原理(了解)

package com.itheima.demo04Set;

/*
    String类的哈希值(了解)
        String类重写了Object类的hashCode方法
        规则:
            相同的字符串返回的哈希值是一样的
            不同的字符串,计算出的哈希值也有可能是一样
 */
public class Demo03StringHashCode {
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("abc");
        System.out.println(s1.hashCode());//96354
        System.out.println(s2.hashCode());//96354
        System.out.println(s1==s2);//false

        System.out.println("重地".hashCode());//1179395
        System.out.println('重'+0);//37325
        System.out.println('地'+0);//22320

        System.out.println("通话".hashCode());//1179395
    }
}

请添加图片描述

7.HashSet存储自定义类型元素(重点中的重点)

package com.itheima.demo05HashSet;

import java.util.HashSet;

/*
    HashSet存储自定义类型元素(重点中的重点)
    要求:
        同名同年龄的人,视为同一个人,只能存储一次
    保证:
        HashSet集合存储Person类必须重写hashCode和equals方法,来保证元素唯一
    重点:
        使用HashSet集合存储自定义类型的元素(Person,Student,Animal...),自定义元素必须重写hashCode和equals方法,来保证元素唯一
        快捷键: alt+insert  选择 equals and hashCode
    思考:
        使用ArrayList集合存储Person,Person需要重写hashCode和equals方法吗? 1需要 2不需要(正确)
        ArrayList集合元素是允许重复,add方法也不会调用元素hashCode和equals方法
 */
public class Demo02HashSetSavePerson {
    public static void main(String[] args) {
        //创建HashSet集合对象,泛型使用Person
        HashSet<Person> set = new HashSet<>();
        Person p1 = new Person("a",10);
        Person p2 = new Person("a",10);
        System.out.println(p1.hashCode());//1163157884
        System.out.println(p2.hashCode());//1956725890
        set.add(p1);
        set.add(p2);
        set.add(new Person("b",11));
        set.add(new Person("c",12));
        set.add(new Person("d",13));
        set.add(new Person("e",14));
        set.add(new Person("f",15));
        set.add(new Person("b",9));
        //遍历Set集合
        for (Person p : set) {
            System.out.println(p);
        }
    }
}
package com.itheima.demo05HashSet;

import java.util.Objects;

public class Person {
    private String name;
    private int age;

    public Person() {
    }

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

    /*
        重写Object类的hashCode方法:模拟String类
        name本身就是一个字符串,可以直接调用String类的hashCode方法,获取字符串的哈希值
        name.hashCode()+age;
        set.add(new Person("a",10));  哈希值:97+10=107
        set.add(new Person("a",10));  哈希值:97+10=107
        两个人的哈希值都是107,使用equals方法,比较两个人,equals返回true==>认定两个元素相同,只能存储一个
        ----------------------------------------------------
        name.hashCode()+age;
        set.add(new Person("a",10));  哈希值:97+10=107
        set.add(new Person("b",9));   哈希值:98+9=107
         两个人的哈希值都是107,使用equals方法,比较两个人,equals返回false==>认定两个元素不同,都会存储到集合中
         ----------------------------------------------------
         降低相同哈希值出现的几率:可以避免两个元素比较equals方法,可以提高程序的效率
         name.hashCode()*2+age;
         set.add(new Person("a",10));  哈希值:97*2+10=204
         set.add(new Person("b",9));   哈希值:98*2+9=205
          name.hashCode()*31+age;
     */
    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

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

        Person person = (Person) o;

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



    @Override
    public String toString() {
        return "Person{" +
                "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;
    }
}

2.LinkedHashSet集合(了解)

package com.itheima.demo06Set;

import java.util.HashSet;
import java.util.LinkedHashSet;

/*
    java.util.LinkedHashSet<E> extends HashSet<E>
        具有可预知迭代顺序的 Set 接口的哈希表和链接列表实现。
        此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重链接列表。
    LinkedHashSet特点:
        1.不允许存储重复元素
        2.没有带索引的方法
        3.底层是哈希表+单向链表
            JDK1.8之前:数组+单向链表+单向链表
            JDK1.8之后:数组+单向链表+单向链表|数组+红黑树+单向链表(可以提高查询的效率)
            结构就是一个双向链表,可以保证迭代的顺序,是一个有序的集合
 */
public class Demo01LinkedHashSet {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("aaa");
        set.add("bbb");
        set.add("ccc");
        set.add("ddd");
        set.add("aaa");
        System.out.println(set);//[aaa, ccc, bbb, ddd]  不允许存储重复元素,是一个无序集合

        LinkedHashSet<String> linked = new LinkedHashSet<>();
        linked.add("aaa");
        linked.add("bbb");
        linked.add("ccc");
        linked.add("ddd");
        linked.add("aaa");
        System.out.println(linked);//[aaa, bbb, ccc, ddd] 不允许存储重复元素,是一个有序集合
    }
}

3.TreeSet集合(使用)

package com.itheima.demo06Set;

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

/*
    java.util.TreeSet<E>集合 implements Set<E>接口
        基于Set接口的红黑树的实现
        使用元素的自然顺序对元素进行排序(内部会使用Comparator比较器对元素进行默认的升序排序)
        或者根据创建TreeSet集合时提供的 Comparator 进行排序,具体取决于使用的构造方法。
    构造方法:
        TreeSet() 构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。
        TreeSet(Comparator<? super E> comparator) 构造一个新的空 TreeSet,它根据指定比较器进行排序。
     TreeSet集合特点:
        1.不允许存储重复元素
        2.没有带索引的方法
        3.底层是一个红黑树结构(元素是有序的)
        4.可以根据比较器产生的规则对元素进行排序
 */
public class Demo02TreeSet {
    public static void main(String[] args) {
        //使用空参数构造方法创建TreeSet集合对象
        TreeSet<Integer> set1 = new TreeSet<>();
        set1.add(100);
        set1.add(1);
        set1.add(-100);
        set1.add(88);
        set1.add(66);
        set1.add(77);
        set1.add(11);
        System.out.println(set1);//[-100, 1, 11, 66, 77, 88, 100]

        //使用带比较器的构造方法创建TreeSet集合对象
        TreeSet<Integer> set2 = new TreeSet<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                //o1-o2:升序  o2-o1:降序
                return o2-o1;
            }
        });
        set2.add(100);
        set2.add(1);
        set2.add(-100);
        set2.add(88);
        set2.add(66);
        set2.add(77);
        set2.add(11);
        System.out.println(set2);//[100, 88, 77, 66, 11, 1, -100]
    }
}

相关文章:

  • const 关键字在 C++ 中的应用
  • Cannot deserialize instance of java.lang.String out of START_ARRAY token
  • PDN目标阻抗的局限与恶劣波评估
  • C++ 智能指针 unique_ptr shared_ptr weak_ptr小练习
  • 【Java基础-49】Java线程池及其基本应用详解
  • 强化学习的数学原理-六、随机近似与随机梯度下降
  • HTML之JavaScript DOM简介
  • Python中的闭包和装饰器
  • 静态时序分析:时钟组间的逻辑独立、物理独立和异步的区别
  • Perplexity AI:通过OpenAI与DeepSeek彻底革新搜索和商业策略
  • 过程监督(Process Supervision)融入到 GRPO (Group Relative Policy Optimization)
  • MT7628基于原厂的SDK包, 修改ra1网卡的MAC方法。
  • 【ORB-SLAM3】鲁棒核函数的阈值设置
  • docker-rss:容器更新的RSS订阅源
  • 卷积与动态特征选择:重塑YOLOv8的多尺度目标检测能力
  • 商汤绝影发布全新端到端自动驾驶技术路线R-UniAD
  • 【Python爬虫(49)】分布式爬虫:在新兴技术浪潮下的蜕变与展望
  • 从0开始:OpenCV入门教程【图像处理基础】
  • 【网络】高级IO
  • sklearn中的决策树
  • 人民日报读者点题·共同关注:今天我们为什么还需要图书馆?
  • 要更加冷静地看待“东升西降”的判断
  • 人民日报刊文:守护“技术进步须服务于人性温暖”的文明底线
  • 北京2025年住房发展计划:供应商品住房用地240-300公顷,建设筹集保租房5万套
  • 北京:下调个人住房公积金贷款利率
  • 李彦宏:技术迭代速度之快从业30年来未见过,要提升执行力战胜对手