Reputation: 926
I need to create a Custom Hashtable extends java.lang.Hashtable and i need to override the get method to achieve the following behavior :
Can anyone help me. I try to do this but I know it's wrong.
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();
}
}
}
please see the line :
if(key == null) return new Object();
and the lines :
if(v == null){
return new Object();
}
to know where the error occurred..
Upvotes: 1
Views: 6601
Reputation: 147164
The primary issue here is what you are trying to achieve is fundamentally wrongheaded. Checkout the methods of your class. The majority of them will now be inconsistent with get
. Worse, exactly how methods are implemented in terms of other public methods is not defined - such is the curse of inheritance.
Therefore, create a class that represents whatever abstraction you are trying to achieve. Have the contain not inherit from an appropriate map implementation.
The natural map in this case is probably not ye olde Hashtable
but java.util.concurrent.ConcurrentHashMap
. The important method here is [putIfAbsent
][2]. Unfortunately the API docs suck. Here is how it should be used:
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;
}
(You can use a Future
if you want to ensure that you never discard a value.)
To create I've assumed some kind of an abstract factory. In general methods don't have no-args public constructors that happen not to throw exceptions. Certainly avoid reflection like swine flu crossed with H5N1. Instead use an appropriate (abstraction-specific) abstract factory passed in at creation time.
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)
Upvotes: 3
Reputation: 29700
Do you need to create a new instance? or is it sufficient to return a default instance?
The latter could be implemented like:
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;
}
}
(but I still prefer Jon's factory solution: more flexible and also covers the default instance solution)
Upvotes: 2
Reputation: 7851
I understand what you asked, but could I ask the following please:
I'm just wondering if you had considered using a LazyMap from Apache Commons Collections?
Upvotes: 0
Reputation: 1502086
You'd have to store the class related to V and create a new instance. For example:
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);
}
}
}
(You may want to change the exception handling of course.)
An alternative is to make the caller effectively provide a factory to create a new instance of V
. You'd do this with an interface such as:
public interface Factory<T> {
T create();
}
You could then store the factory in the custom hashtable, and call create
any time you needed to.
Upvotes: 10