Java 为其他对象实现与String.intern()等效的

Java 为其他对象实现与String.intern()等效的,java,memory,serialization,intern,Java,Memory,Serialization,Intern,我正在尝试实现一个与String.intern()等效的对象,但其他对象除外。 我的目标如下: 我有一个对象A,我将序列化然后反序列化。 如果某个地方有另一个引用,我希望反序列化的结果是相同的引用 下面是我所期望的一个例子 MyObject A = new MyObject(); A.data1 = 1; A.data2 = 2; byte[] serialized = serialize(A); A.data1 = 3; MyObject B = deserialize(serialized)

我正在尝试实现一个与String.intern()等效的对象,但其他对象除外。 我的目标如下: 我有一个对象A,我将序列化然后反序列化。 如果某个地方有另一个引用,我希望反序列化的结果是相同的引用

下面是我所期望的一个例子

MyObject A = new MyObject();
A.data1 = 1;
A.data2 = 2;
byte[] serialized = serialize(A);
A.data1 = 3;
MyObject B = deserialize(serialized); // B!=A and B.data1=1, B.data2=2
MyObject C = B.intern(); // Here we should have C == A. Consequently C.data1=3 AND C.data2=2
这是我的atm机。(MyObject类扩展了InternableObject)

失败的原因是,在反序列化时,调用InternableObject的构造函数,因此objectId将为2(即使序列化数据包含“1”)

有没有关于如何解决这个特殊问题或处理高级问题的其他方法的想法


谢谢大家不要使用构造函数来创建实例。首先使用工厂方法检查实例是否已经存在,如果还没有匹配的实例,则仅创建实例

要使序列化协同工作,类需要使用readResolve()/writeReplace()

您实现构造函数的方式是,在构造过程中泄漏引用,这可能会导致非常难以确定的问题。另外,您的实例映射不受任何锁的保护,因此它不是线程保存。

通常
intern()
形成一个方面,可能不应该实现为基类,也可能限制了它在更复杂的星座中的使用

有两个方面:

1。共享“相同”对象。

当几个对象可以“内部化”到同一个对象时,内部化一个对象只会带来利润。所以我认为,内在的客体。用一个新的序列号是不够的。更重要的是,该类定义了fitting equals和hashCode

然后,您可以进行标识
映射

由于类型擦除,需要
Class
参数。这里忽略了并发


在Java8之前,只需使用可内化为_marker:interface的空接口,并使用静态InternMap。

字符串是不可变的
,因此将其内化是有意义的。为什么您甚至希望将此功能用于任意对象?我建议您查看
Currency
的源代码以获得灵感。
public abstract class InternableObject {

private static final AtomicLong maxObjectId = new AtomicLong();
private static final Map<Long, InternableObject> dataMap = new ConcurrentHashMap<>();
private final long objectId;

public InternableObject() {
    this.objectId = maxObjectId.incrementAndGet();

    dataMap.put(this.objectId, this);
}

@Override
protected void finalize() throws Throwable {
    super.finalize();
    dataMap.remove(this.objectId);
}

public final InternableObject intern() {
    return intern(this);
}

public static InternableObject intern(InternableObject o) {
    InternableObject r = dataMap.get(o.objectId);

    if (r == null) {
        throw new IllegalStateException();
    } else {
        return r;
    }
}
}
    private static class MyData extends InternableObject implements Serializable {

    public int data;

    public MyData(int data) {
        this.data = data;
    }
}

@Test
public void testIntern() throws Exception {
    MyData data1 = new MyData(7);

    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(data1);
    oos.flush();
    baos.flush();
    oos.close();
    baos.close();
    ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    ObjectInputStream ois = new ObjectInputStream(bais);
    MyData data2 = (MyData) ois.readObject();

    Assert.assertTrue(data1 == data2.intern()); // Fails here
}
public class InternMap {
    private final Map<Object, Object> identityMap = new HashMap<>();
    public static <I extends Internalizable<?>> Object intern(I x) {
        Object first = identityMap.get(x);
        if (first == null) {
           first = x;
           identityMap.put(x, x);
        }
        return first;
    }
}
interface Internalizable<T> {
    public static final InternMap interns = new InternMap();
    public default T intern(Class<T> klazz) {
        return klazz.cast(internMap.intern(this));
    }

class C implements Internalizable<C> { ... }

C x = new C();
x = x.intern(C.class);