首页 > 编程语言 >Java拾贝第十四天——集合之Set

Java拾贝第十四天——集合之Set

时间:2023-11-02 16:00:21浏览次数:34  
标签:set Java name sale 第十四天 add Set Ball String

Set

Set是Collection的子接口,其定义如下:

public interface Set<E> extends Collection<E>

与List相同,此接口也使用了泛型,使用时必须指定具体的类型。

Set常见的实现子类:HashSet、TreeSet

HashSet

HashSet是Set的子类,其类定义如下:

public class HashSet<E>
    extends AbstractSet<E>
    implements Set<E>, Cloneable, java.io.Serializable

HashSe是无序的,其内部结构是散列表。

HashSet类的常用方法如下:

方法 类型 描述
boolean add(E e) 普通方法 添加元素
boolean remove(Object o) 普通方法 删除元素
boolean contains(Object o) 普通方法 是否包含某元素

boolean add(E e)

添加元素

栗子:

    public static void main(String[] args) {
        Set<String> set = new HashSet<>();

        set.add("张三");
        set.add(new String("张三"));
        String str = new String("张三");
        set.add(str);
        //测试存放相同的元素


        set.add("李四");
        set.add("王五");

        for (String s : set) {
            System.out.println(s);
        }
    }

程序运行结果:

李四
张三
王五

从结果可以看出HashSet中不能存放相同的元素,且HashSet内部的元素是无序的。

问:HashSet是如何判断重复的元素呢?
	答:散列码(哈希编码)。

众所周知Object是所有类的父类,在Object中有一个hashCode()方法来得到散列码。

每一个对象都有一个默认的散列码(哈希编码)。

对于自定义的类,想要达到去重的效果存放于HashSet集合中,需要重写其hashCode()方法。

boolean remove(Object o) 和 boolean contains(Object o)

删除元素 和 判断元素是否存在

栗子:

    public static void main(String[] args) {
        Set<String> set = new HashSet<>();
        set.add("张三");
        set.add("李四");
        set.add("王五");
        set.add("赵五");

        System.out.println("删除元素前");
        for (String s : set) {
            System.out.println(s);
        }

        System.out.println("删除元素后");
        set.remove("张三");
        System.out.println(set.contains("张三"));
        for (String s : set) {
            System.out.println(s);
        }
    }

程序运行结果:

删除元素前
李四
张三
王五
赵五
删除元素后
false
李四
王五
赵五

TreeSet

TreeSet是Set的子类,其类定义如下:

public class TreeSet<E> extends AbstractSet<E>
    implements NavigableSet<E>, Cloneable, java.io.Serializable

TreeSet是有序的。

TreeSet常用方法同HashSet类的常用方法

栗子:

    public static void main(String[] args) {
        Set<String> set = new TreeSet<>();
        set.add("王五");
        set.add("张三");
        set.add("赵六");
        set.add("李四");

        for (String s : set) {
            System.out.println(s);
        }
    }

程序运行结果:

张三
李四
王五
赵六

从栗子中可以清楚地看到,就算添加数据时没有顺序,其输出结果还是有序的。

问:TreeSet是如何判断重复的元素呢?
	答:对象的equals()方法返回值,或CompareTo()方法返回值。

问:TreeSet是如何实现的排序呢?
	答:TreeSet存储对象的时候, 可以排序, 但是需要指定排序的算法。
	对于上述栗子,我们存储的对象是String,String内部有默认排序。
	对于自定义的类,必须实现Comparable接口并重写其compareTo()方法。

自定义的类在TreeSet中使用

因为TreeSet中的元素都是有序排放的。

所以对于自定义的类想要在TreeSet中使用

  1. 实现Comparable接口
  2. 重写其compareTo()方法
  3. 在方法中指定排序规则

栗子:

public class Test14 {
    public static void main(String[] args) {
        Set<Ball> set = new TreeSet<>();
        set.add(new Ball("C",42.3));
        set.add(new Ball("B",32.3));
        set.add(new Ball("A",22.3));
        set.add(new Ball("A",22.3));
        set.add(new Ball("D",22.3));

        for (Ball ball : set) {
            System.out.println(ball);
        }
    }
}

class Ball implements Comparable {
    private String name;
    private double sale;

    public Ball(String name, double sale) {
        this.name = name;
        this.sale = sale;
    }

    @Override
    public int compareTo(Object o) {//compareTo方法也叫比较器
        Ball b = (Ball) o;//向下转型
        //this指向调用compareTo()方法的对象
        if (this.sale > b.sale) {//大返回-1
            return 1;
        } else if (this.sale < b.sale) {
            return -1;//小返回-1
        } else {
            return 0;//相等返回0
        }
    }

    @Override
    public String toString() {
        return "Ball{" +
                "name='" + name + '\'' +
                ", sale=" + sale +
                '}';
    }
}

程序运行结果:

Ball{name='A', sale=22.3}
Ball{name='B', sale=32.3}
Ball{name='C', sale=42.3}

对于上述栗子,添加元素时是无序的,但输出会自动调用compareTo()方法(比较器),然后按照规则排序。

但栗子中的比较器仅仅是根据sale属性进行排序,所以会导致存在D被过滤掉。

至此,修改栗子如下:

public class Test14 {
    public static void main(String[] args) {
        Set<Ball> set = new TreeSet<>();
        set.add(new Ball("C",42.3));
        set.add(new Ball("B",32.3));
        set.add(new Ball("A",22.3));
        set.add(new Ball("A",22.3));//重复的内容
        set.add(new Ball("D",22.3));

        for (Ball ball : set) {
            System.out.println(ball);
        }
    }
}

class Ball implements Comparable {
    private String name;
    private double sale;

    public Ball(String name, double sale) {
        this.name = name;
        this.sale = sale;
    }

    @Override
    public int compareTo(Object o) {
        Ball b = (Ball) o;//向下转型

        if (this.sale > b.sale) {//this指向调用compareTo()方法的对象
            return 1;
        } else if (this.sale < b.sale) {
            return -1;
        } else {//如果sale属性相等就比较name属性
            return this.name.compareTo(b.name);//使用String类内部默认的比较器进行字符串比较
        }
    }

    @Override
    public String toString() {
        return "Ball{" +
                "name='" + name + '\'' +
                ", sale=" + sale +
                '}';
    }
}

程序运行结果:

Ball{name='A', sale=22.3}
Ball{name='D', sale=22.3}
Ball{name='B', sale=32.3}
Ball{name='C', sale=42.3}

从结果可以发现,D正确的出现了,并且也成功去重。

但此时的去重只是依靠Comparable接口完成的。

如果将TreeSet集合换成HashSet集合也会出现重复的内容。

想要真正的实现去重,必须重写equals() 和 hashCode()

至此,修改栗子如下:

public class Test14 {
    public static void main(String[] args) {
        Set<Ball> set = new HashSet<>();
        set.add(new Ball("C", 42.3));
        set.add(new Ball("B", 32.3));
        set.add(new Ball("A", 22.3));
        set.add(new Ball("A", 22.3));
        set.add(new Ball("D", 22.3));

        for (Ball ball : set) {
            System.out.println(ball);
        }
    }
}

class Ball {//不用比较器的去重
    private String name;
    private double sale;

    public Ball(String name, double sale) {
        this.name = name;
        this.sale = sale;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;//地址值相同返回T
        if ( !(o instanceof Ball)) return false;//属于Ball或Ball子类的取反 返回F
        Ball ball = (Ball) o;//向下转型
        if (this.name.equals(ball.name) &&this.sale== ball.sale) return true; //全部属性相等 是一个对象
        else return false;//全部属性不相等 不是一个对象
    }

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

    @Override
    public String toString() {
        return "Ball{" +
                "name='" + name + '\'' +
                ", sale=" + sale +
                '}';
    }
}

程序运行结果:

Ball{name='D', sale=22.3}
Ball{name='B', sale=32.3}
Ball{name='A', sale=22.3}
Ball{name='C', sale=42.3}

标签:set,Java,name,sale,第十四天,add,Set,Ball,String
From: https://www.cnblogs.com/Ocraft/p/17805610.html

相关文章

  • 详解Java LinkedList
    LinkedList简介LinkedList是List接口的实现类,基于双向链表实现,继承自AbstractSequentialList类,同时也实现了Cloneable、Serializable接口。此外还实现了Queue和Deque接口,可以作为队列或双端队列使用。LinkedList的插入删除时间复杂度:在头部或尾部插入删除元素,只需要修改头节......
  • javaapi、spark、flink 创建Iceberg表,hive 和impala无法正常读取解决
    spark、flink创建Iceberg表中,元数据存储在hive的meta_store,发现hive或者impala无法正常读取报错。事实上解决方案是在spark、flink的SQL中执行语句:addiceberg相关引擎的runntime的jar;ALTERTABLEtSETTBLPROPERTIES('storage_handler'='org.apache.iceberg.mr.hive......
  • js/javaScript实现金额千分位
    作为前端开发,我们都知道,在实际的需求开发中,难免会遇到需要将接口返回的金额进行千分位格式化的场景。千分位后的金额便于阅读,提升用户体验。金额千分位可以由前端来处理,也可以后端处理后返回给前端展示。下边就来贴一下前端的两种实现方式:方法一:constcheckNaN=(value,cb)=......
  • java练习:二维码生成和输出
    <!--二维码生成--><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>2.2</version></dependency><dependency><groupId>com.google.zxing</groupId&......
  • Hive / ClickHouse 行转列函数 collect_set() / groupUniqArray() 入门
    Hive/ClickHouse行转列函数collect_set()/groupUniqArray()入门在数据处理和分析中,我们经常会遇到需要将一行数据转换为多列的情况。在Hive和ClickHouse中,可以使用collect_set()和groupUniqArray()函数来实现行转列操作。collect_set()1.功能说明collect_set()函......
  • Delphi使用TNetHTTPClient上传文件java接收测试
    Delphi使用TNetHTTPClient上传文件java接收测试上传客户端新建一个应用,拖入一个TButton按扭,一个TMemo多行文件显示框,一个TNetHttpClient,一个OpenDialog文件打开对话框。双击按扭添加代码  uses  System.Net.Mime;procedureTForm1.Button1Click(Sender:TObject);var......
  • java语言基础
    在计算机编程中,标识符是用来代表变量、函数、类、模块等命名实体的名称。标识符可以包含字母、数字和下划线,并且必须遵循一些特定的规则和约定。以下是一些通用的标识符规则:只能以字母(包括大写和小写)、下划线(_)或者某些特殊字符(在某些编程语言中)开头。其余部分可以是字母......
  • Java 匿名函数的概念和写法
    匿名函数的实现1.定义一个函数式接口。只有一个抽象方法的接口就是函数式接口//1.定义一个函数式接口。只有一个抽象方法的接口就是函数式接口interfaceILike{voidhit(longparam);}没有类名,必须借助接口或父类通过实例化函数式接口就可以完成匿名内部类实现此接口......
  • Java语言基础知识点梳理与总结
    Java语言基础知识点梳理与总结Java是一种广泛应用于软件开发的编程语言,具有丰富的特性和功能。在学习Java语言时,了解以下基础知识点对于建立坚实的编程基础非常重要。本博客将介绍Java语言中的标识符、运算符、流程控制、循环结构、分支结构、数组、方法、类与对象等主要知识点。......
  • Java踩坑之List的removeAll方法
    最近写个功能,需要用到差集,然后就想到了javaList中有一个removeAll方法,正好可以实现差集功能,可以直接调用。我们知道,apache的common-collections包下面得CollectionUtils.subtract()方法也可以对List作差集,为了比较两种方式差集的结果,见Java中CollectionUtils.subtract()......