package Sequenic.T2.Seq; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.io.ObjectStreamException; import java.util.Arrays; import java.util.concurrent.ConcurrentHashMap; /** * Reduces the storage requirements for an array of Strings. * Intended to store collections of strings that are frequently used together. * E.g. the class names used in a TraceStep. * * @author Jeiel Schalkwijk * */ public final class StringList implements Externalizable { private String[] arr; private int hashCode; public StringList() {} public String[] getStrings() { return arr; } /** Create a StringList containing the given strings. * * @param strings * @return */ public static StringList create(String... strings) { StringList res = new StringList(); res.initialize(strings); return res; } private void initialize(String[] a) { arr = a; hashCode = Arrays.hashCode(arr); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object obj) { if(obj instanceof StringList) { return Arrays.equals(arr, ((StringList) obj).arr); } return false; } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { initialize((String[])in.readObject()); } @Override public void writeExternal(ObjectOutput out) throws IOException { //First intern each String, to avoid serializing duplicate String instances. for (int i = 0; i < arr.length; i++) arr[i] = arr[i].intern(); //Then write the array of strings. out.writeObject(arr); } private static final ConcurrentHashMap cache = new ConcurrentHashMap(); /* By using a cache each unique StringList is serialized exactly once. * References to duplicate (i.e. equivalent) StringList instances are replaced * with a reference to the first instance that was serialized. */ private Object writeReplace() throws ObjectStreamException{ final StringList list = cache.putIfAbsent(this, this); return list==null? this : list; } }