【问题标题】:Hash Set add method is not working fine哈希集添加方法无法正常工作
【发布时间】:2015-08-12 09:50:05
【问题描述】:

我写了一个虚拟程序,在哈希集中添加对象。我创建了一个可容纳 5 人的类 Car。

现在的问题是我从不同的主程序得到不同的输出。

请在下面找到 2-Main 程序。

第一个主程序是

  public class Main_1 {
    static int counter = 0;

    public static void main(String args[]) {

        Car car = new Car();
        for (int i = 0; i < 20; i++) {
            car.add(new Person());
        }
        car.done();

    }

     }

Main_1 的输出是:线程“main”java.lang.IllegalStateException 中的异常:我已满 在 Car.add(Car.java:10) 在 Main_1.main(Main_1.java:8)

第二个主程序是

   public class Main_2 {
    static int counter = 0;
    static Car car = new Car();

    public static void main(String args[]) {
        car.add(new RecursivePerson());
        car.done();
    }

    static class RecursivePerson extends Person {
        public int hashCode() {
            if (++counter < 20) {
                car.add(new RecursivePerson());
            }
            return super.hashCode();
        }
    }
}

Main_2 的输出是我是一辆有 20 人的汽车!

下面是我的程序的业务逻辑。

      import java.util.HashSet;
      import java.util.Set;

        public class Car {
        private static final int CAPACITY = 5;
        private Set<Person> people = new HashSet<Person>();

        public synchronized void add(Person p) {
            if (people.size() >= CAPACITY) {
                throw new IllegalStateException("I'm full");
            } else {
                people.add(p);
            }
        }

        public synchronized void done() {
            if (people.size() == 20) {
                // The goal is to reach this line
                System.out.println("I'm a car with 20 people!");
            }
        }
      }

        class Person {
         }

有人能告诉我为什么 java 会这样吗?

【问题讨论】:

  • 有什么问题?该程序只做你告诉它做的事情。你做了一些非常精确的更改并使用了精确的数字,我只能假设你没有写这个,因为我会很惊讶你可以编写代码来做到这一点,但不知道它在做什么。
  • 你在哪里设置人的大小值?
  • 是的,我正在读java,这个例子是,我不明白,所以我与你们分享,以检查为什么在我递归添加它的工作正常时会发生这种情况,但在通过for循环添加时却没有.
  • @PiyushMittal- 问题不是我为什么要设置值问题为什么我在递归添加时得到输出并在我通过 for 循环添加时得到异常。

标签: java hashset


【解决方案1】:

不同之处在于 HashSet 的工作方式:如果您向其中添加新元素,它首先检查对象是否已经在集合中,如果不是,则将其添加到放。为了检查对象是否在集合中,它在对象上调用hashCode()

您的第二个程序专门设计用于绕过汽车的容量检查。您在添加到哈希集中的对象中覆盖 hashCode()。此方法由HashSet.add 方法调用,但在对象实际添加到集合之前。在覆盖的hashCode() 方法中,您将附加元素添加到集合中。即如果调用Car.add(),则哈希集的大小始终为0,容量检查始终通过。

【讨论】:

    【解决方案2】:

    HashSet 是使用 HashMap 实现的。让我们看一下源HashSet的源代码,根据GrepCode添加:

    public boolean add(E e) 
    {
        return map.put(e, PRESENT)==null;
    }
    

    让我们按照GrepCode来看看HashMap中的put实现:

    public V More ...put(K key, V value) 
    {
         if (key == null)
             return putForNullKey(value);
         int hash = hash(key.hashCode());
         int i = indexFor(hash, table.length);
         for (Entry<K,V> e = table[i]; e != null; e = e.next) 
         {
             Object k;
             if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
             {
                 V oldValue = e.value;
                 e.value = value;
                 e.recordAccess(this);
                 return oldValue;
             }
        }
    
         modCount++;
         addEntry(hash, key, value, i);
        } 
    

    您的对象使用 addEntry 添加到最后一行。但是,在添加条目之前的第 3 行调用了 hashCode;最后,这个原因被再次调用。因为你的 hashCode 方法添加直到你有 20 个元素,所以集合的大小最终是 20。

    【讨论】:

      【解决方案3】:

      这是因为在Main_2 中,您正在递归调用 add。对.add() 方法的初始调用不会返回实际增加人员列表的大小。所以,people.size() 所以它总是返回 0,尽管你在那里添加了很多元素。

      如果你做一点调试,你会在Main_2 中看到几次迭代后的调用堆栈如下所示:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-12
        • 1970-01-01
        • 1970-01-01
        • 2019-10-17
        • 2019-07-03
        • 2016-05-04
        • 1970-01-01
        • 2019-06-02
        相关资源
        最近更新 更多