Так хочется себе это:
import java.io.*;
public class A {
private Object mFoo;
public A(Object foo) {
mFoo = foo;
}
public Serializable getData() {
String niceString = "Nice String";
return new B(niceString);
}
public class B implements Serializable {
private Object mBlob;
public B (Object blob) {
mBlob = blob;
}
public String toString() {
return String.format("%s-%s-%s", getClass(), mBlob, mFoo);
}
}
public static void main(String[] args)throws Exception {
A a = new A("Have a nice Day");
Serializable s = a.getData();
System.out.println("Before:" + s);
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
ObjectOutputStream ostream = new ObjectOutputStream(bytesOut);
ostream.writeObject(s);
ostream.flush();
ostream.close();
ByteArrayInputStream bytesIn = new ByteArrayInputStream(bytesOut.toByteArray());
ObjectInputStream istream = new ObjectInputStream(bytesIn);
System.out.println("After:" + istream.readObject());
}
}
где виртуальные конструкции, которые имеют являются вещи, как mFoo
в этом случае. Ссылка на них в toString()
здесь возможна, потому что этот jvm имеет ссылку на экземпляр A
с строкой «Have a nice Day». Теперь, если это статично, это другое дело. Но без статичности это не может быть сериализовано.
Before:class A$B-Nice String-Have a nice Day
Exception in thread "main" java.io.NotSerializableException: A
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1165)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1535)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1496)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1413)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1159)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:329)
at A.main(A.java:35)
Теперь давайте изменим B
чуть-чуть что-то вроде:
public static class B implements Serializable {
private Serializable mData2;
private Object mBlob;
public B (Object blob) {
mBlob = blob;
mData2 = new Serializable() {
String data = "Foo";
public String toString() {
return data;
}
};
}
public String toString() {
return String.format("%s-%s-%s", getClass(), mBlob, mData2);
}
}
Теперь нет никаких ссылок на A
, B
имеет анонимный класс, который указывает обратно B, так как это технически внутренний класс. Это была бы та же проблема, кроме того, что B также является Serializable. Какой результат. Я бегу по горячей точке.
Before:class A$B-Nice String-Foo
After:class A$B-Nice String-Foo
Таким образом, все детали могут быть написаны отлично! ... но все еще есть проблема.
ПРИМЕЧАНИЕ Это работает только потому, что мы контролируем несколько вещей.
Скажем, вместо сериализации в буфер и повторного чтения его внутри того же приложения мы делаем что-то более полезное. Предположим, мы сохранили экземпляр B
в файл. Это, по сути, сериализация анонимного внутреннего класса за пределами данной среды выполнения.
Если вы описывали класс B
кому-то еще, что бы вы назвали этим анонимным внутренним классом? Это анонимно. Вероятно, вы бы назвали это тем, что имело для вас смысл, и так последовательно ссылаться на него. Это то, что делают sdk/runtime. Он назвал это чем-то, что не столкнулось бы с каким-либо другим классом в classpath. В Hotspot я думаю, что он будет называться A.B$1
, так как он является первым анонимным внутренним классом B
(почему это не индексируется 0 всегда меня беспокоило). Это, однако, реализация деталей Hotspot, которые я считаю. Поэтому, если вы должны взять один и тот же источник и скомпилировать его с помощью другого набора инструментов sdk, а затем запустите код и попросите его десериализовать этот файл, если он не назвал этот анонимный внутренний класс тем же именем, вероятно, будет ClassNotFoundException
бросили, и вы были бы как HUH? КАК? ГДЕ? и было бы болью преследовать, поскольку кто знает, когда был написан этот файл.
Существует спецификация формата Serialization, с которой происходит этот тип.Обычно есть какое-то магическое число, чтобы указать начало данных, а затем имя класса сериализованного blob, которому предшествует L
, поэтому я думаю, что в этом случае файл будет содержать что-то вроде LA.B$1
, если он скомпилирован и запущен на Hotspot. Таким образом, вся среда выполнения может действительно выполняться, когда она считывает этот поток, который ищет A.B.$1
, так как он не знает, на каком именно этапе исполнения, или на экземпляре времени выполнения, из которого был получен этот файл. (Отключение памяти здесь, поэтому есть много деталей, которые я пропускаю).
Получите mac используя OpenJDK и Linux-машину с помощью JRockit (или какой-либо другой JVM), затем создайте внутренний класс Serializable и используйте RMI для передачи его между этими машинами ... –
Если это работает, попробуйте IBM JDK .. , –