1

我需要创建一个自定义哈希表扩展 java.lang.Hashtable 并且我需要重写 get 方法以实现以下行为:

  1. 如果 key == null,它将返回一个类型为 V 的新对象
  2. 如果 super.get(key) == null,它也会返回一个类型为 V 的新对象。

谁能帮我。我尝试这样做,但我知道这是错误的。

import java.util.Hashtable;

public class CustomHashtable<K, V> extends Hashtable {
    @Override
    public synchronized V get(Object key) {
        if(key == null) return new Object();
        Object v = super.get(key);
        if(v == null){
            return new Object();
        }
    }

}

请看这条线:

if(key == null) return new Object();

和行:

if(v == null){
    return new Object();
}

知道错误发生在哪里..

4

4 回答 4

10

您必须存储与 V 相关的类并创建一个新实例。例如:

public class CustomHashtable<K, V> extends Hashtable {
    Class<V> clazz;

    public CustomHashtable(Class<V> clazz) {
        this.clazz = clazz;
    }

    @Override
    public synchronized V get(Object key) {
        if(key == null) return newValue();
        Object v = super.get(key);
        if(v == null){
            return newValue();
        }
    }

    private V newValue() {
        try {
            return clazz.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException (e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException (e);
        }
    }
}

(当然,您可能想要更改异常处理。)

另一种方法是让调用者有效地提供一个工厂来创建V. 您可以使用如下界面执行此操作:

public interface Factory<T> {
    T create();
}

然后,您可以将工厂存储在自定义哈希表中,并create在需要时随时调用。

于 2009-04-29T09:05:49.927 回答
3

这里的主要问题是您试图实现的目标从根本上是错误的。检查你班级的方法。他们中的大多数现在将与get. 更糟糕的是,没有定义如何根据其他公共方法来实现方法——这就是继承的诅咒。

因此,创建一个代表您尝试实现的任何抽象的类。让包含不继承自适当的地图实现。

在这种情况下,自然地图可能不是 ye oldeHashtable而是java.util.concurrent.ConcurrentHashMap。这里的重要方法是[ putIfAbsent][2]。不幸的是,API 文档很烂。以下是它应该如何使用:

public V getOrCreate(K key) {
    final V value = map.get(key);
    if (value != null) {
        return value;
    }
    V newValue = factory.create(key); // May discard.
    V oldValue = map.putIfAbsent(key, value);
    return oldValue==null ? newValue : oldValue;
}

Future(如果你想确保你永远不会丢弃一个值,你可以使用 a 。)

为了创建,我假设了某种抽象工厂。一般来说,方法没有碰巧不会抛出异常的无参数公共构造函数。当然要避免像猪流感与 H5N1 交叉的反射。而是使用在创建时传入的适当的(特定于抽象的)抽象工厂。

public interface MySortOfFactory<
    T /*extends SomeEntity*/,
    A /*extends SomeInfo*/
> {
    T create(A arg);
}

[2]: http: //java.sun.com/javase/6/docs/api/java/util/concurrent/ConcurrentMap.html#putIfAbsent (K , V)

于 2009-04-29T11:21:12.503 回答
2

您需要创建一个新实例吗?还是返回默认实例就足够了?
后者可以像这样实现:

public class CustomHashtable<K, V> extends Hashtable<K, V> {

    /** Default instance. */
    private final V defaultValue;

    public CustomHashtable(V defaultValue) {
        this.defaultValue= defaultValue;
    }

    @Override
    public synchronized V get(Object key) {
        if(key != null) {
            V val = super.get(key);
            if(val != null) {
                return val;
            }
        }
        return defaultValue;
    }
}

(但我还是更喜欢 Jon 的工厂解决方案:更灵活,也涵盖了默认实例解决方案)

于 2009-04-29T09:47:15.617 回答
0

我明白你的问题,但我可以问以下问题:

  • 当键为空时,您总是想要一个新对象,还是只想允许一个空键?
  • 另外,当您找不到密钥时,您是否肯定需要一个新实例,或者在您找不到密钥的每种情况下都需要同一个实例?
  • 您是否要将新实例放入哈希表中?
  • 它必须是 Hashtable,还是 HashMap 可以?

我只是想知道您是否考虑过使用Apache Commons Collections中的LazyMap ?

于 2009-04-29T09:39:11.907 回答