Set集合&泛型

本文详细介绍了Java中的Set集合,包括Set集合的特点、HashSet和LinkedHashSet的存储原理与区别。同时,讲解了Set集合的排序机制,以TreeSet为例展示了自然排序和比较器排序。此外,还探讨了泛型的概念,包括泛型类、泛型方法和泛型接口,以及泛型通配符的使用。最后,介绍了Java中的可变参数特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.Set集合

1.1Set集合概述和特点

  • Set集合的特点
    1.元素存取无序
    2.没有索引,只能通过迭代器或增强for循环遍历
    3.不能存储重复元素(有条件)

  • Set集合的基本使用

public class SetDemo {
    public static void main(String[] args) {
        //创建集合对象
        Set<String> set = new HashSet<String>();
        //添加元素
        set.add("hello");
        set.add("world");
        set.add("java");
        //不包含重复元素的集合
        set.add("world");
        //遍历
        for(String s : set) {
            System.out.println(s);
        }
    }
}

1.2哈希值

  • 哈希值简介
    是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值

  • 如何获取
    Object类中的public int hashCode();返回对象的哈希码

  • 哈希值的特点:
    1.同一个对象多次调用hashCode()方法返回的哈希值是相同的
    2.默认情况下,不同对象的哈希值是不同的 而重写hashCode()方法,可以实现让不同对象的哈希值相同

1.3HashSet存储元素的原理
当往HashSet集合中存储元素的时候,会先计算元素的hashCode值(每一个对象的hashCode值默认不一样)

 - 如果hashCode值和已元素的hashCode值不同,则会直接存储到集合;
 - 如果hashCode值相同,还会使用equals方法判断元素的内容是否相同
    如果hashCode相同,equals比较内容相同,则认为元素重复,不存储。
    如果hashCode相同,equals比较内容不同,则认为元素不重复,存储到集合

在这里插入图片描述
1.4HashSet

  • 特点:
    1.底层数据结构是哈希表
    2.对集合的迭代顺序不作任何保证,也就是说不保证存储和取出元素顺序一致
    3.没有带索引的方法,所以不能使用普通for循环遍历
    4.由于是Set集合,所以不包含重复元素

1.5LinkedHashSet集合概述和特点

  • LinkedHashSet集合特点
    1.哈希表和链表实现Set接口,具有可预测的迭代次序
    2.由链表保证元素有序,即存储和取出顺序是一致的
    3.由hash表保证元素唯一,也就是没有重复元素

2.Set集合排序

2.1TreeSet集合概述和特点

  • 概述:
    1.元素有序,可以按照一定规则进行排序,具体排序方式取决于构造方法
    TreeSet():根据其元素的自然排序进行排序
    TreeSet(Comparator comparator):根据指定比较器进行排序
    2.没有带索引方法,不能用普通for遍历
    3.不包含重复元素
  • 基本使用
//创建集合对象
TreeSet<Integer> ts = new TreeSet<Integer>();

//添加元素
ts.add(10);
ts.add(40);
ts.add(30);
ts.add(50);
ts.add(20);

ts.add(30);

//遍历集合
for(Integer f : ts) {
    System.out.println(f);
}

2.2自然排序Comparable的使用
TreeSet可以对集合中的元素进行排序,在添加元素的时候会自动去调用Comparable接口的compareTo方法

比如String和Integer本身就具备排序规则
 1.String类本身就实现了Comparable接口,也复写compareTo方法,所以它具备字典顺序的排序规则。
 2.Integer类本身就实现Comparable接口,也复写compareTo方法,按照整数大小排序

想让自己写的类也具有排序规则,就可以让自己的类实现Comparable接口复写comparaTo方法

ublic class Student implements Comparable<Student> {
   private String name;
   private  int age;

    public Student() {
    }

    public Student(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 int compareTo(Student stu) {
        //按照年龄的升序排列
        int num=this.age-stu.age;
        //如果num==0,表示年龄一样,继续按照姓名的升序排练
        if(num==0){
            //继续按照姓名的升序排练
            num= this.name.compareTo(stu.name);
        }
        return num;
    }
}
TreeSet<Student> ts=new TreeSet<>();
Student s1=new Student("白龙马",100);
Student s2=new Student("唐僧",80);
Student s3=new Student("b沙和尚",260);
Student s4=new Student("a红孩儿",260);
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
for (Student t : ts) {
  System.out.println(t);
}

2.3使用Comparator接口排序(比较器排序)
也可以使用比较器对TreeSet中的元素进行排序

TreeSet<Student>ts=new TreeSet(new Comparator<Student>(){
@Override
public int compare(Student s1,Student s2)
{
//按照年龄升序排列
int num=s1.getAge()-s2.getAge();
if(num==0){
//如果年龄相同,按照姓名的升序排列

num=s1.getName().compareTo(s2.getName());
}
return num;
}
});
Student s1=new Student("唐僧",80);
Student s2=new Student("孙悟空",500);
Student s3=new Student("猪八戒",300);
Student s4=new Student("b沙和尚",260);
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);

for (Student t : ts) {
  System.out.println(t);
} 
}

3. 泛型

在写一个类、接口、方法时有些数据类型不确定,可以使用<字母>表示一个不确定的数据类型

泛型的好处:
 1.把运行时期的错误提前到了编译时期
 2.避免了强制类型转化的麻烦 

在这里插入图片描述

3.1自定义泛型

  • 泛型类
//<E> 表示在GenericClass类中有一个不确定数据类型
public class GenericClass<E> {
    private E e;
    public E getE() {
        return e;
    }
    public void setE(E e) {
        this.e = e;
    }
}
//创建对象的时候,再确定GenericClass中<E>的具体类型
public class Demo1 {
    public static void main(String[] args) {
        GenericClass<Integer> gc=new GenericClass<>();
        //设置一个整数
        gc.setE(100);
        //获取一个整数
        Integer v = gc.getE();
        System.out.println(v);
GenericClass<String> gc1=new GenericClass<>();
        gc1.setE("hello");
        String v1 = gc1.getE();
        System.out.println(v1);
    }
}
  • 泛型方法
//<T> 表示在方法中不确定的数据类型

//调用方法时,根据实际传递的参数来确定<T>的数据类型
public static void main(String[] args){
  show("hello");
  show(123);
  show(3.14);
}
  • 泛型接口
//<E> 表示在GenericInter接口中有一个不确定数据类型
public interface GenericInter<E> {
    public void method(E e);
}
//那个类实现接口,就由那个类来确定接口种<E>的数据类型
public class GenericImpl implements GenericInter<String>{
  @Override
  public void method(String e){
    ...
  }
}

3.2泛型通配符
泛型通配符,一般是用在方法形式参数的位置 用来限制传递实际参数的范围

//<?> 表示集合中的元素可以是任意类型
public static void method1(List<?> list){
  for (Object o : list) {
    System.out.println(o);
  }
}
//<? extends Number>> 表示集合中的元素可以是Number或者Number的子类
public static void method2(Set<? extends Number> list){
  for (Object o : list) {
    System.out.println(o);
  }
}
//<? super Number> 表示集合中的元素可以是Number或者Number的父类
public static void method3(Set<? super Number> list){
  for (Object o : list) {
    System.out.println(o);
  }
}

4.可变参数

在定义方法时,如果不确定参数有多少个,就可以使用可变参数

public static void method(参数类型...变量名){
  //可变参数的本质就是一个数组,在方法种就把可变参数当做数组使用就可以了。
}
public class Demo5 {
    public static void main(String[] args) {
        int[] arr={1,2,3,4};
        sum(arr);
        sum(1,2);
    }
    public static void sum(int...arr){
        int sum=0;
        for (int i = 0; i < arr.length; i++) {
            sum+=arr[i];
        }
        System.out.println(sum);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值