打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
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

  }

  }
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Java 如何重写对象的 equals 方法和 hashCode 方法
浅析equals()与hashCode()方法的重写
Java Set集合的详解
Java中Set的深入研究 - javaGrowing - BlogJava
Set集合去除重复元素
对java中equals和hashCode函数的一些理解
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服