Java基础知识之Set

特性

Set中不允许出现重复元素,是根据什么原理呢?答案是:根据equals()方法来区分的。那么如想自定义类对象实例在Set中不重复出现,则需要覆写equals方法了:

这里我们假定自定义类为Person:

package Public;

public class Person{

    private int age;
    private String name;
    public Person() {
        super();
    }
    public Person(int age, String name) {
        super();
        this.age = age;
        this.name = name;
    }
    //同一对象返回true,反之返回false
    @Override
    public boolean equals(Object obj) {
        //若地址相同,肯定是同一个对象
        if(this == obj){
            return true;
        }
        //若要比较的对象不是自定义类对象(这里为Person),肯定不是同一对象
        //想一想为什么不写为 this.equals(obj)呢???
        if(!(obj instanceof Person)){
            return false;
        }
        //运用多态进行转型
        Person p = (Person)obj;
        //比较各个成员变量的值是否相等
        if(p.age == this.age && p.name.equals(this.name)){
            return true;
        }else{
            return false;
        }
    }
    @Override
    public String toString() {
        return "Person [age=" + age + ", name=" + name + "]";
    }
}

到这里可不要忙着去测试,Set是一个接口,它是这样的:public interface Set extends Collection,为其实例化要使用实现它的类,通常用的有TreeSet(有排序功能)、HashSet(根据hash值存储)。

使用TreeSet实例化:

上面说TreeSet有排序功能,这是根据什么实现的呢?答案是:compareTo()方法,就是说我们自定义的类要实现Comparable接口,覆写compareTo()方法:

让我们该造下Person类:

package Public;
//重点在这里
public class Person implements Comparable<Person>{
    private int age;
    private String name;
    public Person() {
        super();
    }
    public Person(int age, String name) {
        super();
        this.age = age;
        this.name = name;
    }
    //重点在这里
    @Override
    public int compareTo(Person o) {
        if(this.age > o.age){
            return 1;
        }else if(this.age < o.age){
            return -1;
        }else{
            return this.name.compareTo(o.name);
        }
    }
    @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        }
        if(!(obj instanceof Person)){
            return false;
        }
        Person p = (Person)obj;
        if(p.age == this.age && p.name.equals(this.name)){
            return true;
        }else{
            return false;
        }
    }
    @Override
    public String toString() {
        return "Person [age=" + age + ", name=" + name + "]";
    }
}

测试下:

package Set;

import java.util.Set;
import java.util.TreeSet;
import Public.Person;

public class TreeSetDemo {
    public static void main(String[] args) {
        Set<Person> s = new TreeSet<Person>();
        s.add(new Person(3,"x"));//添加元素
        s.add(new Person(1,"x"));//添加元素
        s.add(new Person(1,"x"));//添加重复元素
        s.add(new Person(1,"y"));//添加元素
        s.add(new Person(2,"x"));//添加元素
        System.out.println(s);
    }
}
/*结果:
[Person [age=1, name=x], Person [age=1, name=y], Person [age=2, name=x], Person [age=3, name=x]]*/

从结果看出,添加的元素没有重复,且输出有序;

使用HashSet实例化

HashSet并不具有排序,所以可以不实现Comparable接口,但是要覆写hashCode()方法,毕竟人家要有自己的东西去标示下嘛;

简单的修改下Person类:

package Public;

public class Person{

    private int age;
    private String name;
    public Person() {
        super();
    }
    public Person(int age, String name) {
        super();
        this.age = age;
        this.name = name;
    }
    @Override
    public int hashCode() {
        return this.name.hashCode() * this.age;
    }
    @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        }
        if(!(obj instanceof Person)){
            return false;
        }
        Person p = (Person)obj;
        if(p.age == this.age && p.name.equals(this.name)){
            return true;
        }else{
            return false;
        }
    }
    @Override
    public String toString() {
        return "Person [age=" + age + ", name=" + name + "]";
    }
}

测试一下:

package Set;

import java.util.HashSet;
import java.util.Set;
import Public.Person;
public class HashSetDemo {
    public static void main(String[] args) {
        Set<Person> s = new HashSet<Person>();
        s.add(new Person(1,"x"));
        s.add(new Person(1,"x"));
        s.add(new Person(1,"z"));
        System.out.println(s);
    }
}
/*结果:
[Person [age=1, name=z], Person [age=1, name=x]]*/

好了,就讲到这里吧!

时间: 2024-11-10 05:13:45

Java基础知识之Set的相关文章

java基础知识回顾之java Thread类学习(八)--java多线程通信等待唤醒机制经典应用(生产者消费者)

 *java多线程--等待唤醒机制:经典的体现"生产者和消费者模型 *对于此模型,应该明确以下几点: *1.生产者仅仅在仓库未满的时候生产,仓库满了则停止生产. *2.消费者仅仅在有产品的时候才能消费,仓空则等待. *3.当消费者发现仓储没有产品可消费的时候,会唤醒等待生产者生产. *4.生产者在生产出可以消费的产品的时候,应该通知等待的消费者去消费. 下面先介绍个简单的生产者消费者例子:本例只适用于两个线程,一个线程生产,一个线程负责消费. 生产一个资源,就得消费一个资源. 代码如下: pub

java基础知识回顾之java Thread类学习(七)--java多线程通信等待唤醒机制(wait和notify,notifyAll)

1.wait和notify,notifyAll: wait和notify,notifyAll是Object类方法,因为等待和唤醒必须是同一个锁,不可以对不同锁中的线程进行唤醒,而锁可以是任意对象,所以可以被任意对象调用的方法,定义在Object基类中. wait()方法:对此对象调用wait方法导致本线程放弃对象锁,让线程处于冻结状态,进入等待线程的线程池当中.wait是指已经进入同步锁的线程,让自己暂时让出同步锁,以便使其他正在等待此锁的线程可以进入同步锁并运行,只有其它线程调用notify方

java基础知识回顾之java Thread类学习(六)--java多线程同步函数用的锁

1.验证同步函数使用的锁----普通方法使用的锁 思路:创建两个线程,同时操作同一个资源,还是用卖票的例子来验证.创建好两个线程t1,t2,t1线程走同步代码块操作tickets,t2,线程走同步函数封装的代码操作tickets,同步代码块中的锁我们可以指定.假设我们事先不知道同步函数用的是什么锁:如果在同步代码块中指定的某个锁(测试)和同步函数用的锁相同,就不会出现线程安全问题,如果锁不相同,就会发生线程安全问题. 看下面的代码:t1线程用的同步锁是obj,t2线程在操作同步函数的资源,假设不

第1天:了解Java基础知识

Java的优势 1. 简单 不像C或者C++语言,Java中省去了对指针的操作.但是,Java中并没有省去指针,代替指针的是一种新的变量--引用,引用也是保存一个对象的内存地址. 2.方便 Java虚拟机自带垃圾回收器,能够自动回收内存资源.而C和C++语言,需要开发人员手动进行内存资源回收. 3.安全 不支持指针操作 4.平台无关性 Java语言是跨平台的,一次编译,到处运行. 而且,不同平台,C语言中数据类型所占的位数是不同的,而Java语言中,数据类型所占的位数是固定的. 5.面向对象 J

JAVA基础知识-java文化基础和运行环境

JAVA基础知识 1,java是95年sun公司推出的开发语言,发展很快,09年被oracle公司收购.至今分为SE.ME.EE三个发展方向和软件版本. 2,运行java的环境主要是通过JVM(java virtual machine)实现的.首先编写.java结尾的源文件,通过编译器编译成.class结尾的字节码文件,然后通过解释器实现在不同平台上一致运行的效果. 3,jvm,jre和jdk的区别:jvm,java虚拟机:jre,java运行环境,jdk:java开发工具包. 4,jdk的下载

java基础知识回顾之javaIO类--管道流PipedOutputStream和PipedIutputStream

管道流(线程通信流):管道流的主要作用是可以进行两个线程间的通讯,分为管道输出流(PipedOutputStream).管道输入流(PipedInputStream),如果想要进行管道输出,则必须要把输出流连在输入流之上.如图所示: 1.管道输入流应该连接到管道输出流 ,输入流和输出流可以直接连接       2.使用多线程操作,结合线程进行操作.通常由某个线程从管道输入流中(PipedInputStream)对象读取.          并由其他线程将其写入到相应的端到输出流中.不能使用单线程

Java基础知识——类装载器与反射机制

类装载器ClassLoader 类装载器就是寻找类的字节码文件,并构造出类在JVM内部表示的对象组件. 类装载器把一个类装入JVM中,要经过三步: 1.装载:查找和导入Class文件: 2.链接:执行校验.准备和解析(解析是可以选择的): 3.初始化:对类的静态变量.静态代码块执行初始化工作: 类装载工作由ClassLoader及其子类负责.JVM在运行时会产生三个ClassLoader:根装载器.ExtClassLoader(扩展类装载器)和AppClassLoader(系统类装载器). 根装

JAVA基础知识整理

一.首先先明白get与post的基本定义和区别: 这是两种在客户端和服务器端进行请求-响应的方法. 1get:从指定的资源请求数据. 2post:向指定的资源提交要处理的数据. get基本上用于从服务器取回数据,注意:get方法可能返回缓存数据. post可以从服务器上获取数据,不过,post方法不会缓存数据,并且常用语连同请求一起发送数据. 二. Jquery $.get()方法. $.get()方法通过Http Get发起请求,从服务器上请求数据. 语法:&.get(URL,callback

java基础知识回顾之java Thread类学习(五)--java多线程安全问题(锁)同步的前提

这里举个例子讲解,同步synchronized在什么地方加,以及同步的前提: * 1.必须要有两个以上的线程,才需要同步. * 2.必须是多个线程使用同一个锁. * 3.必须保证同步中只能有一个线程在运行,锁加在哪一块代码 那么我们要思考的地方有:1.知道我们写的哪些是多线程代码 2.明确共享数据 3.明确多线程运行的代码中哪些语句是操作共享数据的.. 4.要确保使用同一个锁. 下面的代码:需求:两个存户分别往银行存钱,每次村100块,分三次存完. class bank{ private int

java基础知识回顾之---java String final类普通方法

辞职了,最近一段时间在找工作,把在大二的时候学习java基础知识回顾下,拿出来跟大家分享,如果有问题,欢迎大家的指正. /*     * 按照面向对象的思想对字符串进行功能分类.     *      *      * 1,获取:     * 1.1 获取字符串中字符的个数(长度).     *         int length();     * 1.2 取字符串中的某一个字符,其中的参数index指的是字符串中序数.字符串的序数从0开始到length()-1 .     *