Java中Set解析

关系

在JAVA集合的这里会设计到比较多的东西,所以我们先看一下继承关系,连接一下在Set这里到底的先后顺序是什么,有一个宏观的了解:

Set:用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。

不重复性:

Set中判断是否相等通过两个方法:通过计算hashCode值和equals方法来比较。

如果想要让两个不同的Person对象视为相等的,就必须覆盖Object继下来的hashCode方法和equals方法,因为Object  hashCode方法返回的是该对象的内存地址,所以必须重写hashCode方法,才能保证两个不同的对象具有相同的hashCode,同时也需要两个不同对象比较equals方法会返回true。

如下图是Object类源码中的hashCode()方法,和String继承后重写的hashCode()函数,所以说,每一个对象都有一个hashCode值,如果hashCode值不一样,那么还要比较equals函数计算是否相同,如果相同就判断是相同元素,就不加入,如果不同就会加入。

在这里顺便提一句,equals和==的区别。equals方法,用于比较两个对象是否相同,它其实就是使用两个对象的内存地址在比较。Object类中的equals方法内部使用的就是==比较运算符。在开发中要比较两个对象是否相同,经常会根据对象中的属性值进行比较,也就是在开发经常需要子类重写equals方法根据对象的属性值进行比较。

String类重写的equals()函数,源码如下:

我们自己也可以重写equals()方法,如下:

class Person extends Object{
    int age ;
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        }
        if(!(obj instanceof Person)){
            return false;
        }
        Person p = (Person)obj;
        return this.age == p.age;
    }
}

此时重写后的equals()方法便和==是有区别的了。

对equals()重新需要注意五点:

  1 、 对任意引用值X,x.equals(x)的返回值一定为true;
  2  、 对于任何引用值x,y,当且仅当y.equals(x)返回值为true时,x.equals(y)的返回值一定为true;
  3  、 如果x.equals(y)=true, y.equals(z)=true,则x.equals(z)=true ;
  4  、如果参与比较的对象没任何改变,则对象比较的结果也不应该有任何改变;
  5  、任何非空的引用值X,x.equals(null)的返回值一定为false 。

言归正传,继续看hashCode,Object的hashCode封装在了本地,String继承自Object,它就从写了hashCode函数,可以看到它自己定义了计算方法来计算出不同的hashCode,源码如下:

Object类:

String类:

hashSet():

HashSet类,也叫哈希表,存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(set的通性),是按照哈希值来存的所以取数据也是按照哈希值取得。该容器中只能存储不重复的对象。看一下HashSet的继承关系,因为它继承了Set函数,所以它也具有set的集合,对于判断重复元素,采用的也是hashCodeequals函数。

对于hashCode相同,equals不同是怎么存储的呢?这里就要看下hashSet的哈希桶结构。

图中的1、2、3、4是hashCode不同,那么存在了不同的位置,而1、5、6则属于hashCode相同,equals不同的三个元素,通过像挂灯笼一样,一个挂一个的存储起来。

一个小例子如下:

public class Student {
	private String name;
	private int age;
	public Student(String name, int age) {
		super();
		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 String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if(!(obj instanceof Student)){
			System.out.println("类型错误");
			return false;
		}
		Student other = (Student) obj;
		return this.age ==  other.age && this.name.equals(other.name);
	}
}

public class HashSetDemo {
	public static void main(String[] args) {
		//创建HashSet对象
		HashSet hs = new HashSet();
		//给集合中添加自定义对象
		hs.add(new Student("zhangsan",21));
		hs.add(new Student("lisi",22));
		hs.add(new Student("wangwu",23));
		hs.add(new Student("zhangsan",21));
		//取出集合中的每个元素
		Iterator it = hs.iterator();
		while(it.hasNext()){
			Student s = (Student)it.next();
			System.out.println(s);
		}
	}
}

TreeSet:

现在有序的容器不能去重和排序,去重的容器不能排序,那么有没有可以排序且去重的集合呢?当然有,这就是我们要说的TreeSet。

public class test {
    public static void main(String[] args) {
        HashSet<Integer> hs = new HashSet<>();
        hs.add(14);
        hs.add(14);
        hs.add(12);
        hs.add(11);
        hs.add(15);
        hs.add(13);
        for (Integer h : hs) {
            System.out.println(h);
        }
    }
}

TreeSet既然能有排序的输出数据,那么它一定有自己的排序算法。上面的例子传入的是一个具体的数字,那么如果我传入一个Object类型对象呢?答案是它会报java.lang.ClassCastException异常,那么没有办法传入了吗?肯定是有的,这时候就需要我们重写hs里面的排序函数了。

看例子:

import java.util.TreeSet;

public class TreeSetDemo {
    public static void main(String[] args) {
        TreeSet<People> ts = new TreeSet<>();
        ts.add(new People("aa",19));
        ts.add(new People("aa",10));
        ts.add(new People("ee",14));
        ts.add(new People("cc",13));
        ts.add(new People("cc",15));
        for (People t : ts) {
            System.out.println(t);
        }
    }
}

class People implements Comparable {
    private String name;
    private int age;
    public People(String name,int age){
        this.name = name;
        this.age = age;
    }
    public String toString(){
        return this.name+"..."+this.age;
    }
    public int compareTo(Object o) {
        People p = (People) o;
        int num = this.name.compareTo(p.name);
        return num == 0 ? this.age - p.age : num;
    }
}

在这里,我用People类要实现Comparable接口,如果我们要实现接口,首要的就是要重写接口里面的方法了。在JAVA的api中是这么写Comparable接口的。

意思就是说commpareTo函数的返回值很重要,如果是一个负整数,那么说明此对象小于指定对象;返回0,说明相等;返回正整数,则说明是大于指定对象的。根据此我们就可以重写符合我们规则的commpareTo函数了,具体也如上面的例子所示。

LinkedHashSet:

在HashSet下面有一个子类LinkedHashSet,它是哈希表和双向链表组合的一个数据存储结构,可以保证元素的插入顺序,示例如下。

public class LinkedHashSetDemo {
	public static void main(String[] args) {
   		Set<String> set = new LinkedHashSet<String>();
		set.add("bbb");
		set.add("aaa");
		set.add("abc");
		set.add("bbc");
   		Iterator it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
}

 

 

全部评论

相关推荐

emmm别问我为啥上一条帖子隔了两个月我才开始投简历和拿offer,因为我懒😰简单流程如下:周一凌晨改好的简历,然后到处乱投简历;周二接到了三维家的一面通知,临时抱佛脚的背了一些八股;周三上午一面下午通知第二天hr面;周四上午hr面下午拿offer,遂收手支线:在BOSS上顺手投了几个大厂,投字节的时候不小心投城客户端了,结果过了一天HR突然把我简历要走了,还问我能不能整客户端,我直接一口答应(脏面评警告😢)结果在周三下午的时候给我打电话,说前端有空缺实习岗,问我有没有兴趣,然后就跟我约了周四下午一面😰我都没咋准备啊,咩都不会啊😭结果周四下午面完,晚上打电话通知过一面了,赶紧把二面约在下周一下午,留点缓冲时间。逆大天了,我一半的问题都不会,他居然给我过了?运气未免有点好了😥现在正在恶补计网、网安、性能优化的东西(这三大板块我是几乎一点不会,一面几乎一点答不出来,加上我又没怎么背八股,这块被干烂了😵)心得体会与经验:1.&nbsp;我giao怎么这么快就结束了,我还以为要找好久😨2.&nbsp;大厂的面试问题真的和中厂小厂很大不同,比如在三维家我能自己吹水到vue的数据劫持、Proxy代理响应式之类的他们就觉得很不错了,但是在字节你但凡敢提到一下就会追问你细节了,一追问马脚就全漏出来了3.&nbsp;有信心真的很重要,我感觉我能拿中厂offer最重要的就是吹水吹出自信来了,以至于三维家面试反问面试官有哪里还需要改进的时候,他就说很不错了解的很多😦4.&nbsp;理解很重要,我从头到尾真没背过很多八股,不过有一些知识确实是敲过代码验证过,所以面试的时候能吹水吹得出来😇想了解面经啥的可以直接评论区问我,但我可能也说不全,因为我没有记录,而且今天摆了一天感觉记忆快清空了😵下面是故事时间:我暑假刚开始的时候才开始准备八股,印象很深那个时候连什么原型、事件循环、闭包这些名词都没听过,资料也不知道怎么找,就一直零零散散的准备,感觉也只有js稍微背了一下八股,其他很多时候都是靠完全理解和手写熟悉一些机制的,但这样做效率很低,反正准备了一个多星期半个月就开摆了😭结果一摆就摆到了开学,笔记是乱七八糟的,八股是忘光光的,简历是一直没改的,实习也是一直没投过的。直到上周日晚上偶然和师兄聊天,他突然问我“你怎么还不找实习”,那天晚上才幡然醒悟,是时候做点事情了😡然后就按照上面描述的来走了。其实我感觉我从头到尾都没背特别多八股,也没怎么找刷题资料啥的,早期就是翻尚硅谷或者黑马的入门视频从头学起,中期用面试鸭看了一点点题,主要是在学js机制和敲js代码,后期才发现了w3c的面经网站,然后在那里看着学(那个时候已经懒得敲了,因为有些问题与代码感觉不像是给找实习的看的,忒细了点😂)接下来继续准备字节二面吧,虽然几乎没啥可能可以通过,但是万一有奇迹呢?😍😍😍也祝大家能够早日拿到心仪的offer
我的offer呢😡:我已经预见10天后你会发,节孝子启动了
投递三维家等公司10个岗位
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务