Java教程

Java集合框架03:Collection集合之Set

本文主要是介绍Java集合框架03:Collection集合之Set,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Set子接口

无序、无下标、元素不可重复

所有方法都继承自Collection父接口,没有自己的方法

HashSet实现类

集合中的元素都是引用类型,都有自己的HashCode,基于HashCode比较可以实现元素不重复

存储结构:哈希表(数组+链表或数组+红黑树)

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

public class Hello{
    public static void main(String[] args) {
        //Set<String> set = new HashSet<>();也可以
        HashSet<String> set = new HashSet<>();
        set.add("小米");
        set.add("苹果");
        set.add("华为");
        set.add("华为");
        
        //添加了重复元素无效,并且顺序和添加的不一样
        System.out.println(set);
        
        //增强for循环遍历
        for (String i : set){
            System.out.println(i);
        }
        
        //iterator()迭代器方法遍历
        Iterator<String> i = set.iterator();
        while (i.hasNext()){
            System.out.println(i.next());
        }
    }
}

拓展:哈希表存储方式

  • 先根据HashCode计算保存的位置,如果该位置为空则直接保存,否则进行下一步比较
  • 再执行equals()方法,如果二者相等则认为重复,否则在该位置形成链表保存
  • 两个对象的HashCode相同,并不一定表示两个对象就相同,即equals()不一定为true,只能说明这两个对象在一个散列存储结构中
import java.util.HashSet;

public class Hello{
    public static void main(String[] args) {
        HashSet<Test> set = new HashSet<>();
        Test a = new Test("ty", 25);
        Test b = new Test("tao", 26);
        set.add(a);
        set.add(b);
        
        //默认情况下,对象地址不同,就算内容相同,也不算重复。同时重写hashCode()和equals()方法才能保证元素的唯一性
        set.add(new Test("ty", 25));
        
        //直接打印是对象地址,如果想打印内容,需要重写toString()方法
        System.out.println(set);
    }
}

class Test {
    String name;
    int age;

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

    @Override
    public String toString() {
        return name + " : " + age;
    }

    @Override
    public int hashCode() {
        //重新定义hashCode,使得内容相同的对象hashCode就相等
        int n1 = name.hashCode();
        int n2 = age;
        return n1 + n2;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (obj instanceof Test) {
            Test ob = (Test) obj;
            //注意比较字符串的内容是否相等,用equals()方法而不是==
            if (this.name.equals(ob.name) && this.age == ob.age){
                return true;
            }
        }
        return false;
        }
}

拓展:哈希表计算hashCode时为什么用31?

  • 31是一个质数,计算时可以减少散列冲突,尽可能生成不同的hashCode
  • 31 * i = (i<<5) - i,31用来计算可以转换为位运算,提高执行效率

TreeSet实现类

基于排列顺序实现元素不重复,实现了SortedSet接口,对集合元素自动排序,默认升序

存储结构:红黑树

注意:自定义类无法自动排序,必须自定义排序的顺序,有两种方法,分别为对象类实现Comparab接口和TreeSet类在构造方法的参数中实现Comparator接口(比较器)

  • 对象类实现Comparable接口

元素对象的类实现Comparable接口,并重写CompareTo方法指定排列顺序,如果返回值为0则为重复元素

import java.util.TreeSet;

public class Hello{
    public static void main(String[] args) {
        TreeSet<Test> tree = new TreeSet<>();
        Test a = new Test("ty", 25);
        Test b = new Test("tao", 26);
        Test c = new Test("tao", 27);
        tree.add(a);
        tree.add(b);
        tree.add(c);

        //此处可以删除原有的元素,因为Test类重写了compareTo()方法,只比较对象的属性,不用再重写equals()方法
        tree.remove(new Test("ty", 25));
        System.out.println(tree);
    }
}

//第一种方法,对象类实现Comparable接口,泛型类型为Test,且重写其compareTo()方法
class Test implements Comparable<Test>{
    String name;
    int age;

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

    @Override
    public String toString() {
        return name + " : " + age;
    }

    //必须重写compareTo()方法
    @Override
    public int compareTo(Test o) {
        int n1 = this.name.compareTo(o.name);
        int n2 = this.age - o.age;
        
        //如果n1 == 0,说明姓名相同,只用比较年龄
        return n1 == 0 ? n2 : n1;
    }
}
  • TreeSet类在构造方法的参数中实现Comparator接口(比较器)

在创建集合时就定义规则,TreeSet类选择有参构造,在参数中实现一个匿名的Comparator接口类,并重写compare()方法指定排列顺序,如果返回值为0则为重复元素

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

public class Hello{
    public static void main(String[] args) {
        //第二种方法,在有参构造的参数中实现一个匿名的Comparator接口类,并重写compare()方法
        TreeSet<Test> tree = new TreeSet<>(new Comparator<Test>() {

            //重写compare()方法
            @Override
            public int compare(Test o1, Test o2) {
                int n1 = o1.name.compareTo(o2.name);
                int n2 = o1.age - o2.age;
                return n1 == 0 ? n2 : n1;
            }
        });
        Test a = new Test("ty", 25);
        Test b = new Test("tao", 26);
        Test c = new Test("tao", 27);
        tree.add(a);
        tree.add(b);
        tree.add(c);

        //此处可以删除原有的元素,因为重写了compare()方法,只比较对象的属性,不用再重写equals()方法
        tree.remove(new Test("ty", 25));
        System.out.println(tree);
    }
}

class Test {
    String name;
    int age;

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

    @Override
    public String toString() {
        return name + " : " + age;
    }
}

练习:将字符串按照长度排序

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

public class Hello{
    public static void main(String[] args) {
        TreeSet tree = new TreeSet<>(new Comparator<String>() {
            
            //重写compare()方法,将长度差作为返回值
            @Override
            public int compare(String o1, String o2) {
                int n1 = o1.length()-o2.length();
                int n2 = o1.compareTo(o2);
                return n1 == 0 ? n2 : n1;
            }
        });

        tree.add("beijing");
        tree.add("tianjin");
        tree.add("xian");
        tree.add("jinan");
        System.out.println(tree);
    }
}
这篇关于Java集合框架03:Collection集合之Set的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!