java中set接口、哈希表、哈希值、HashSet、LinkedHashSet、方法的可变参数

set接口:

set接口和list接口一样,都是继承于Collection接口,它与Collection接口中的方法基本一致。特点:不允许存储重复元素,元素没有索引。它主要有两个实现类:HashSet(具有哈希表结构,实际是一个HashMap实例,它的没有顺序,但是查询速度非常快,底层也不是同步的 )和LinkedHashSet

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

// set接口:继承于Collection接口,不允许存储重复元素,且没有索引,因此不能使用带索引的方法,也不能使用普通的for遍历
// set接口主要有两个实现类:HashSet和
// 1.HashSet特点:1.不允许存储重复元素 2.没有索引,不能使用带索引的方法,也不能使用普通的for遍历 3.无序的集合,存取元素的顺序可能不同 4.底层是一个哈希表结构(查询速度非常快)
public class setInterfaceClass {
    
    
    public static void main(String[] args) {
    
    
        // 使用多态的方式创建一个HashSet集合:
        Set<Integer> st = new HashSet<Integer>();
        // 使用add方法向集合中添加元素:
        st.add(1);
        st.add(2);
        st.add(2);
        st.add(4);
        System.out.println(st); // [1, 2, 3, 4]
        // 遍历st集合:不能使用for遍历没有索引的集合:一般使用迭代器或增强for遍历没有索引的集合:
        // for (int i = 0; i < st.size();i++) {
    
    
        //    System.out.println(st[i]);
        //}
        Iterator<Integer> it = st.iterator();
        while (it.hasNext()) {
    
    
            int num = it.next();
            System.out.println(num); // 分别打印出了每个元素,但是2只打印了一次,因为存元素时不会存入重复的元素
        }
        for (int i : st) {
    
    
            System.out.println(i); // 分别打印出了每个元素,但是2只打印了一次,因为存元素时不会存入重复的元素
        };
    }
}

哈希表:

HashSet集合存储数据的结构就是使用哈希表,那么什么是哈希表?想要了解哈希表,那么就先了解哈希值。

哈希值 :一个十进制的整数,由系统随机给出(实际就是对象的地址值,但是并非物理地址,而是模拟出来的地址,在Object类中有一个hashCode方法可以获取对象的哈希值),

定义一个继承了Object的类:

// 定义一个TestClass类并继承Object
public class TestClass extends Object{
    
    
    // 点进Object查找hashCode方法可以看到源码:public native int hashCode(); 此方法没有方法体,而是有一个native,表示该方法调用了本地系统方法
}

使用TestClass类创建对象,并使用hashCode方法:

// 哈希值:一个由系统随机给出的对象整数地址值,hashCod方法可以返回这个哈希值:
public class hashCodeMethodsClass {
    
    
    public static void main(String[] args) {
    
    
        // 创建一个TestClass类的对象,又因为TestClass类继承了Object,因此可以调用hashCode方法:
        TestClass tc = new TestClass();
        int hashValue = tc.hashCode();
        System.out.println(hashValue); // 1967205423 ,每次执行都会得到不同的值

        TestClass tc2 = new TestClass();
        int hashValue2 = tc2.hashCode();
        System.out.println(hashValue2); // 42121758 ,每次执行都会得到不同的值
        System.out.println(tc == tc2); // false
 
        // 如何我们重写hashCode方法,那么返回值就一直是一个定值,虽然返回值的哈希值是相同的,但是这两个对象也是不相等的,因为物理地址不同

        // String类的哈希值:
        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("通话".hashCode()); // 1179395
    }
}

哈希表结构:

jdk1.8之前哈希表 = 数组+链表,jdk1.8之后哈希表= 数组+ 红黑树(提高查询速度)
在这里插入图片描述
set集合不能存储重复元素的原理 :

import java.util.HashSet;

// set集合不允许存储重复元素的原理:
public class setNoRepet {
    
    
    public static void main(String[] args) {
    
    
        HashSet<String> st = new HashSet<String>();
        String s1 = new String("abc");
        String s2 = new String("abc");

        st.add(s1);
        st.add(s2);
        st.add("重地");
        st.add("通话");
        st.add("abc");

        System.out.println(st); // [重地, 通话, abc] ,每次添加元素底层都会调用hashCode计算哈希值,并将这个哈希值水平存到数组中,如果有相同的哈希值元素被添加,那么会继续调用equals方法进一步比较两个元素是否相同,如果相同则不会存储,否则会在垂直方向将元素存到对应哈希值下面
    }
}

在这里插入图片描述
HashSet存储自定义类型元素:

给HashSet中存放自定义元素时,需要重写对象中hashCode和equals方法,建立自己的比较方法,才能保证HashSet集合中的对象唯一。

自定义类:

import java.util.Objects;

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

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Person() {
    
    
    }

    //  重写equals和hashCode方法代码可以alt+insert自定生成:
    @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);
    }

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

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

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public int getAge() {
    
    
        return age;
    }
}

使用HashSet存储自定义元素:

import java.util.HashSet;

// HashSet存储自定义元素:set集合存储元素唯一,以后如果要在HasHset中存储元素,一定要覆重写hashCode和equals方法:
public class customElementSaveHashSet {
    
    
    public static void main(String[] args) {
    
    
        Person p1 = new Person("小明",12);
        Person p2 = new Person("小明",12);
        Person p3 = new Person("小红",22);

        HashSet<Person> ps = new HashSet<>();
        ps.add(p1);
        ps.add(p2);
        ps.add(p3);
        System.out.println(p1.hashCode()); //1967205423
        System.out.println(p2.hashCode()); //42121758
        System.out.println(p3.hashCode()); //20671747
        System.out.println(ps); // [Person@13b6d03, Person@282ba1e, Person@75412c2f], 存进去了两个对象

        // 上面是没有重写hashCode方法和equals方法,会存三个值进去,下面是重写了Person类中的hashCode和equals方法的结果:
        System.out.println(p1.hashCode()); //23458766
        System.out.println(p2.hashCode()); //23458766
        System.out.println(p3.hashCode()); //23653828
        System.out.println(ps); // [Person@165f3ce, Person@168edc4]
    }
}

LinkedHashSet集合:

LinkedHashSet是一个具有可预知迭代顺序set接口的哈希表和链表的实现,继承于HashSet集合,与hashSet不同之处在于LinkedHashSet维护着一个运行于所有条目的双重链接列表,此链接列表定义了迭代顺序(按照将元素插入到set中的顺序,且插入的顺序不受set中重新插入元素影响)

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

// LinkedHashSet继承于HashSet集合,底层是一个哈希表(数组+链表/红黑树)和链表构成,可以看出是双链,其中一条是记录元素存储顺序的。
public class LinkedHashSetClass {
    
    
    public static void main(String[] args) {
    
    
        // 创建一个HashSet集合:
        HashSet<String> st = new HashSet<>();
        st.add("WWW");
        st.add("abc");
        st.add("abc");
        st.add("hello");
        System.out.println(st); // [abc, WWW, hello] ,可以看到遍历的顺序和存储的顺序是不一致且不允许重复存储的。

        // 创建一个LinkedHashSet集合:
        LinkedHashSet<String> ls = new LinkedHashSet<>();
        ls.add("WWW");
        ls.add("abc");
        ls.add("abc");
        ls.add("hello");
        System.out.println(ls); // [WWW, abc, hello] ,可以看到与HashSet集合不一致的是:元素存储迭代是有顺序的,且也是不重复
    }
}

可变参数:

在jdk1.5之后,如果定义的方法需要接收多个参数,且参数数据类型一致,那么我们可以对其传入参数简化书写:(参数类型…形参名),当方法的参数类型确定而参数个数不确定时可以使用可变参数,可变参数实际是一个数组(传递几个参数就会创建一个存几个元素的数组 )将每个参数存起来了,如:

public class VarParamClass {
    
    
    public static void main(String[] args) {
    
    
        getSum(); // 0
        getSum(2,4); // 2
    }
    // 一个方法的可变参数列表只能有一个参数,也就是说可变的参数只能有一个:
    public static void getSum(int...num) {
    
    
        System.out.println(num.length);
    };

    // 如果有多个参数,其中有一个可变参数,那么这个可变参数放到最后面试可行的:
    public static void getResult(String s,int n, Boolean b, int...num) {
    
    
        System.out.println(num.length);
    };

    // 当有多个参数时,可变参数不能放到其他位置,只能放到末尾:
    // public static void getReut(int...num,String s,int n, Boolean b) {
    
    
    //    System.out.println(num.length);
    //};
}

提示:本文图片等素材来源于网络,若有侵权,请发邮件至邮箱:[email protected]联系笔者删除。
笔者:苦海

猜你喜欢

转载自blog.csdn.net/weixin_46758988/article/details/128154484