Reputation: 2338
I am trying to make a singleton like the following, but I keep getting a warning. If possible, I don't want suppress warning. Is there a way to do it?
For now, I don't want to think about the thread-safety. I just want to pass this warning.
public interface Storage<K, V> {
public void put(K key, V value);
public V get(K key);
}
public static class DefaultStorage<K, V> implements Storage<K, V> {
private Map<Object, Object> map = new ConcurrentHashMap<Object, Object>();
private static DefaultStorage<K, V> defaultStorage;
private DefaultStorage() {
//
}
public static DefaultStorage<?, ?> getInstance() {
if (defaultStorage== null) {
defaultStorage= new DefaultStorage();
}
return defaultStorage;
}
}
Thanks.
Upvotes: 3
Views: 1448
Reputation: 533530
I would use an enum and specify the type.
public interface Storage<K, V> {
public void put(K key, V value);
public V get(K key);
}
public enum DefaultStorage implements Storage<String, Object> {
INSTANCE;
private final Map<Object, Object> map = new ConcurrentHashMap<>();
public Object get(String key) { return map.get(key); }
public void put(String key, Object value) { map.put(key, value); }
}
Upvotes: 1
Reputation: 61
How were you able to create a reference to your parameterized inner class like this?
private static DefaultStorage<K, V> defaultStorage;
As per the explanation given in Static method in a generic class?:
A class's type parameters is only available for its instance variables and not static fields and methods. Static fields and methods are shared among all instances of a class and even to instances of various type parameters."
So you cannot create a static reference to your class DefaultStorage and limit it to just K, V types. This should be fine.
private static DefaultStorage<?,?> defaultStorage;
But as you have mentioned I am not able to get rid of the warning without suppressing it. And creating the object like this
defaultStorage= new DefaultStorage();throws a compilation error obviously.
Upvotes: 0
Reputation: 7899
The variable defaultStorage
in DefaultStorage
only exists once in every instance of a DefaultStorage
combined. At runtime there's only one actual class, and one static variable. So, the variable will simultaneously be a DefaultStorage<K1, V1>
, a DefaultStorage<K2, V2>
, a DefaultStorage<K3, V3>
, and so on. So, one class will store Strings
in it, another will store BigDecimals
, and another X501Principals
. This subverts type-safety.
The warning is that you are storing an instance of a raw type, new DefaultStorage()
, in a variable declared as DefaultStorage<K, V>
.
From Angelika Langer's Generics FAQ,
Can generic types have static members?
Yes.
Generic types can have static members, including static fields, static methods and static nested types. Each of these static members exists once per enclosing type, that is, independently of the number of objects of the enclosing type and regardless of the number of instantiations of the generic type that may be used somewhere in the program. The name of the static member consists - as is usual for static members - of the scope (packages and enclosing type) and the member's name. If the enclosing type is generic, then the type in the scope qualification must be the raw type, not a parameterized type.
Upvotes: 2