java set 包含_Java中Set的contains()方法

本文主要讨论 集合Set 中存储对象的 hashCode 与 equals 方法应遵循的约束关系.新手对Set中contains()方法的疑惑

[java]

普通类会继承Object类的一切方法,但是不会重写Object类的方法

import java.util.HashSet;

class Dog{

String color;

public Dog(String s){

color = s;

}

}

public class SetAndHashCode {

public static void main(String[] args) {

HashSet dogSet = new HashSet();

dogSet.add(new Dog('white'));

dogSet.add(new Dog('white'));

System.out.println('We have ' + dogSet.size() + ' white dogs!');

if(dogSet.contains(new Dog('white'))){

System.out.println('We have a white dog!');

}else{

System.out.println('No white dog!');

}

}

}

上述代码的输出为:

[plain]

We have 2 white dogs!

No white dog!

程序中添加了两只白色的小狗到集合dogSet中. 且 size()方法显示有2只白色的小狗.但为什么用 contains()方法来判断时却提示没有白色的小狗呢?

Set的contains(Object o) 方法详解

Java的API文档指出: 当且仅当 本set包含一个元素 e,并且满足(o==null ? e==null : o.equals(e))条件时,contains()方法才返回true. 因此 contains()方法 必定使用equals方法来检查是否相等.

需要注意的是: set 中是可以包含 null值的(常见的集合类都可以包含null值). 所以如果添加了null,然后判断是否包含null,将会返回true,代码如下所示:

[java]

HashSet a = new HashSet();

a.add(null);

if(a.contains(null)){

System.out.println('true');

}

Java的根类Object定义了 public boolean equals(Object obj) 方法.因此所有的对象,包括数组(array,[]),都实现了此方法。

在自定义类里,如果没有明确地重写(override)此方法,那么就会使用Object类的默认实现.即只有两个对象(引用)指向同一块内存地址(即同一个实际对象, x==y为true)时,才会返回true。

如果把Dog类修改为如下代码,能实现我们的目标吗?

[java

class Dog{

String color;

public Dog(String s){

color = s;

}

//重写equals方法, 最佳实践就是如下这种判断顺序:

public boolean equals(Object obj) {

if (!(obj instanceof Dog))

return false;

if (obj == this)

return true;

return this.color == ((Dog) obj).color;

}

}

英文答案是: no.

问题的关键在于 Java中hashCode与equals方法的紧密联系. hashCode() 是Object类定义的另一个基础方法.

equals()与hashCode()方法之间的设计实现原则为:

如果两个对象相等(使用equals()方法),那么必须拥有相同的哈希码(使用hashCode()方法).

即使两个对象有相同的哈希值(hash code),他们不一定相等.意思就是: 多个不同的对象,可以返回同一个hash值.

hashCode()的默认实现是为不同的对象返回不同的整数.有一个设计原则是,hashCode对于同一个对象,不管内部怎么改变,应该都返回相同的整数值.

在上面的例子中,因为未定义自己的hashCode()实现,因此默认实现对两个对象返回两个不同的整数,这种情况破坏了约定原则。

解决办法

[java]

class Dog{

String color;

public Dog(String s){

color = s;

}

//重写equals方法, 最佳实践就是如下这种判断顺序:

public boolean equals(Object obj) {

if (!(obj instanceof Dog))

return false;

if (obj == this)

return true;

return this.color == ((Dog) obj).color;

}

public int hashCode(){

return color.length();//简单原则

}

}

但是上面的hashCode实现,要求Dog的color是不变的.否则会出现如下的这种困惑:

[java]

import java.util.HashSet;

import java.util.Set;

public class TestContains {

public static final class Person{

private String name = '';

public Person(String n) {

setName(n);

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = (name==null)? '' : name;

}

@Override

public int hashCode() {

// 请考虑是否值得这么做,因为此时name是会变的.

return name.length();

// 推荐让name不可改变

}

@Override

public boolean equals(Object obj) {

if(!(obj instanceof Person)){

return false;

}

if(obj == this){

return true;

}

return this.name.equals(((Person)obj).name);

}

};

public static void main(String[] args) {

Set persons = new HashSet();

//

Person person = new Person('tiemao');

persons.add(person);

// 修改name, 则依赖hash的集合可能失去作用

person.setName('ren');

// 同一个对象,居然是false,原因是我们重写了hashCode,打破了hashCode不变的基本约定

boolean has = persons.contains(person);

int size = persons.size();

System.out.println('has='+has); // has=false.

System.out.println('size='+size);// size=1

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值