The output is:
import java.util.Map;
import java.util.WeakHashMap;
/**
* A simple cache using WeakHashMap of zero length arrays of a given class.
*
* @author schitale
*
*/
public class ZeroLength {
private static Mapmap = new WeakHashMap ();
@SuppressWarnings("unchecked")
public staticT[] array(Class c) {
T[] array = (T[]) map.get(c);
if (array == null) {
array = (T[]) java.lang.reflect.Array.newInstance(c, 0);
map.put(c, array);
}
return array;
}
public static void main(String[] args) {
System.out.println(array(String.class).getClass().getCanonicalName()
+ " of length " + array(String.class).length);
System.out.println(array(String[].class).getClass().getCanonicalName()
+ " of length " + array(String.class).length);
}
}
java.lang.String[] of length 0If you want to rely on the identity of the zero length array instance (e.g. == based comparison) then replace the WeakHashMap with HashMap. However, in that case you have to watch out for memory leaks through static fields of array component classes. You may want to add a method to remove the reference to the array from the HashMap.
java.lang.String[][] of length 0
Is there a better way to do this?
IMHO the java.lang.Class class should provide such factory method. This is along the lines of factory method:
public static final T List T java.util.Collections.emptyList();
The implementation in java.lang.Class may look like:
private static T[] zeroLengthArray;
public static synchronized T[] emptyArray() {
if (zeroLengthArray == null) {
zeroLengthArray = (T[]) java.lang.reflect.Array.newInstance(this, 0);
}
return zeroLengthArray;
}
7 comments:
While the code is interesting, I'm not sure when I would use this code. Could you give a more concrete example of when this would be used?
I applaud your use of generics for the interface to your map, but a WeakHashMap is not a cache.
I've implemented caches using maps of SoftReferences and a ReferenceQueue.
You might want to read this:
http://www.codeinstructions.com/2008/09/weakhashmap-is-not-cache-understanding.html
@aberrant - you are right. WeakHashMap should not be thought of as a cache. Instead one could use HashMap and manage the it with references counted release of the cached instance.
It should be thread safe. E.g. using a HashMap from concurrent threads may leed to an endless loop in the internals of "put". So use a cache implementation based on ConcurrentHashMap or so..
@wombat42
Concreate example is to avoid code like this:
List<String> strings = ....
:
String[] stringArray = strings.toArray(new String[0]);
// Could be replaced by:
String[] stringArray = strings.toArray(ZeroLength.array(String.class);
In fact the java.lang.Class<T> could provide such factory method which will avoid issues with memory leaks. This is allong the lines of factory methods in
java.util.Collections.emptyList()
@jodelight
You are right the code needs to be thread safe.
Post a Comment