Создать настраиваемую хэш-таблицу - PullRequest
1 голос
/ 29 апреля 2009

Мне нужно создать пользовательский Hashtable, расширяет java.lang.Hashtable, и мне нужно переопределить метод get для достижения следующего поведения:

  1. если ключ == нуль, он вернет новый объект типа 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 ]

10 голосов
/ 29 апреля 2009

Вы должны сохранить класс, связанный с 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 в любое время.

3 голосов
/ 29 апреля 2009

Основная проблема здесь в том, что вы пытаетесь достичь, в корне неверно. Проверьте методы вашего класса. Большинство из них теперь будут несовместимы с get. Хуже того, как именно методы реализуются в терминах других открытых методов, не определено - таково проклятие наследования.

Поэтому создайте класс, представляющий любую абстракцию, которую вы пытаетесь достичь. содержит , не наследуя от соответствующей реализации карты.

Естественная карта в этом случае, вероятно, не старая Hashtable, а 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, если хотите быть уверенным, что никогда не сбросите значение.)

Для создания я предположил какую-то абстрактную фабрику. В общем случае методы не имеют открытых конструкторов без аргументов, которые бы не генерировали исключения. Конечно, избегайте отражения, как свиной грипп, скрещенный с 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)

2 голосов
/ 29 апреля 2009

Вам нужно создать новый экземпляр? или достаточно вернуть экземпляр по умолчанию ?
Последнее может быть реализовано так:

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;
    }
}

(но я все еще предпочитаю заводское решение Джона: более гибкое и также охватывает решение экземпляра по умолчанию)

0 голосов
/ 29 апреля 2009

Я понимаю, что вы спросили, но могу я спросить следующее, пожалуйста:

  • Вы всегда хотите новый объект, когда ключ является нулевым, или вы просто не хотите разрешить использование нулевого ключа?
  • Кроме того, вам определенно нужен новый экземпляр, когда вы не можете найти ключ, или же он будет действовать в каждом случае, когда вы не можете найти ключ?
  • Собираетесь ли вы помещать новые экземпляры в Hashtable?
  • Должен ли это быть Hashtable или HashMap?

Мне просто интересно, рассматривали ли вы вопрос об использовании LazyMap из коллекций Apache Commons?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...