Java学习day_18之集合(泛型&Set)

一、泛型

泛型是JDK5引入的特性,可以在编译阶段约束操作的数据类型,并进行检查

  • 泛型的好处
    1. 把运行时期的问题提前到了编译期间
    2. 避免了强制类型转换
  • 泛型的定义格式
    • <类型>: 指定一种类型的格式.尖括号里面可以任意书写,一般只写一个字母.例如:
    • <类型1,类型2…>: 指定多种类型的格式,多种类型之间用逗号隔开.例如: <E,T> <K,V>

弊端:
  利用泛型方法有一个小弊端,此时它可以接受任意的数据类型

通配符

?  也表示不确定的类型, 它可以进行类型的限定
? extends E:  表示可以传递E或者E所有的子类类型
? super E:   表示可以传递E或者E所有的父类类型 E要自己具体定义

应用场景:
1.如果在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口。
2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以用泛型的通配符

public class GenericsDemo6 {
    public static void main(String[] args) {
        //泛型不具备继承性,但是数据具备继承性

        //创建集合的对象
        ArrayList<Ye> list1 = new ArrayList<>();
        ArrayList<Fu> list2 = new ArrayList<>();
        ArrayList<Zi> list3 = new ArrayList<>();

        method(list1);
//      method(list2);

        list1.add(new Ye());
        list1.add(new Fu());
        list1.add(new Zi());

    }
    //此时,泛型里面写的是什么类型,那么只能传递什么类型的数据
    public static void method(ArrayList<Ye> list) {

    }
}

二、Set

1.HashSet

特点:

  • 底层数据结构是哈希表
  • 存取无序
  • 不可以存储重复元素
  • 没有索引,不能使用普通for循环遍历

HashSet添加元素的过程
 计算哈希值:调用元素的hashCode()方法,计算出一个int类型的哈希值
 计算索引位置:通过哈希值计算在数组中的索引位置 (n - 1) & hash
 检查该位置是否有元素
  如果该位置为null,直接存入
  如果该位置已有元素,调用equals()比较
   如果equals返回true,认为是重复元素,不存入
   如果equals返回false,以链表或红黑树形式存储(哈希冲突)

由此可以得到输出顺序不一定等于添加顺序

哈希值:对象的整数表现形式
1.如果没有重写hashCode方法,不同对象计算出的哈希值是不同的

		//1.创建对象
        Student s1 = new Student("zhangsan",23);
        Student s2 = new Student("zhangsan",23);

        //2.如果没有重新hashCode方法,不同对象计算出的哈希值是不同的
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());

在这里插入图片描述

2.如果已经重写hashCode方法,不同的对象只有属性值相同,计算出的哈希值就是一样的

//在JavaBean类覆盖以下方法,重新运行
  @Override
    public boolean equals(Object o) {
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

在这里插入图片描述

3.但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)

  System.out.println("abc".hashCode());
  System.out.println("acD".hashCode());

在这里插入图片描述

总结

  • HashSet集合存储自定义类型元素,要想实现元素的唯一,要求必须重写hashCode方法和equals方法

2.LinkedHashSet

该集合的特点及原理

  • 有序、不重复、无索引
  • 底层基于哈希表,使用双链表记录添加顺序
public class LinkHashSetDemo {
    public static void main(String[] args) {
        //1.创建三个学生对象
        Student s1 = new Student("zhangsan", 23);
        Student s2 = new Student("lisi", 24);
        Student s3 = new Student("wangwu", 25);
        Student s4 = new Student("wangwu", 25);

        //保证数据的存取有序
        LinkedHashSet<Student> lhs = new LinkedHashSet<>();

        System.out.println(lhs.add(s3));
        System.out.println(lhs.add(s2));
        System.out.println(lhs.add(s1));
        System.out.println(lhs.add(s4));

        System.out.println(lhs);
    }
}

在这里插入图片描述
可以看到有序且不重复

3.TreeSet

特点

  • 不可以存储重复元素
  • 没有索引
  • 可以将元素按照规则进行排序

排序方式一:
  默认的排序规则/自然排序
  JavaBean类实现Comparable接口,重新里面的抽象方法,再指定比较规则

@Override
    public int compareTo(Student o) {
        //指定排序的规则
        //按照年龄的升序进行排列
        return this.getAge() - o.getAge();
    }
//1.创建三个学生对象
Student s1 = new Student("zhangsan",23);
Student s2 = new Student("wangwu",25);
Student s3 = new Student("lisi",24);

//2.创建集合对象
TreeSet<Student> ts = new TreeSet<>();

//3.添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);

System.out.println(ts);

在这里插入图片描述
排序方式二:比较器排序
 在集合中重写新的比较器

 TreeSet<String> ts = new TreeSet<>((o1, o2) -> {
            //按照长度排序
            int i = o1.length() - o2.length();
            //如果一样长度则按照首字母排序
            i = i == 0?o1.compareTo(o2) : i;
            return i;
        });

        //2.添加元素
        ts.add("c");
        ts.add("ab");
        ts.add("df");
        ts.add("qwer");
        //默认从首字母开始排序

        System.out.println(ts);

在这里插入图片描述
总结

  • 两种比较方式小结
    • 自然排序: 自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序
    • 比较器排序: 创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序
    • 在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,必须使用比较器排序
  • 两种方式中关于返回值的规则
    • 如果返回值为负数,表示当前存入的元素是较小值,存左边
    • 如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
    • 如果返回值为正数,表示当前存入的元素是较大值,存右边
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值