我在假设您有..class
文件Person
但没有.class
. Address
(也许Person
是来自不同项目的依赖?)
您无法序列化Person
(即使该Address
字段是瞬态的)的原因是序列化 API 使用 Java 反射 API。尽管 JVM 将加载一个类而不加载其所有依赖项,但反射 API 并不那么宽容。
第一次使用反射 API 检索特定类的字段信息时,它会检索并缓存该类中所有字段的信息。为此,它必须解析类中每个字段的类型,因此将尝试为每个字段加载类文件。(您可以在 Java 源代码中看到这一点:ObjectOutputStream
使用ObjectStreamClass
、调用Class.getDeclaredField
、调用私有方法privateGetDeclaredFields
,该方法解析并缓存类的所有字段定义。)
作为一种解决方法,如果您的代码实际上从未使用任何类型的对象Address
,您可以简单地在正确的包中创建一个空Address
类,编译它,并将其添加到您的类路径中:
public class Address { }
对于那些认为Person
没有类定义就无法在运行时使用的人Address
,以下三个类演示了 OP 的含义:
人.java
import java.io.Serializable;
public class Person implements Serializable {
private String name;
private transient Address address;
public Person(String name) { this.name = name; }
public Address getAddress() { return address; }
public String getName() { return name; }
}
地址.java
public class Address {
private String address;
public String getAddress() { return address; }
}
测试.java
import java.io.FileOutputStream;
import java.io.ObjectOuputStream;
public class Test {
public static void main(String...args) throws Exception {
Person person = new Person("John Doe");
System.out.println("Person successfully instantiated with name " + person.getName());
// now attempt to serialize
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("person.out"));
out.writeObject(person); // NoClassDefFoundError thrown here if Address.class doesn't exist
out.close();
}
}
现在编译Test.java
、删除Address.class
和运行Test
:
$ javac Test.java
$ rm Address.class
$ java Test
Person successfully instantiated with name John Doe
Exception in thread "main" java.lang.NoClassDefFoundError: LAddress;
at java.lang.Class.getDeclaredFields0(Native Method)
at java.lang.Class.privateGetDeclaredFields(Class.java:2308)
at java.lang.Class.getDeclaredField(Class.java:1897)
at java.io.ObjectStreamClass.getDeclaredSUID(ObjectStreamClass.java:1624)
at java.io.ObjectStreamClass.access$700(ObjectStreamClass.java:69)
at java.io.ObjectStreamClass$2.run(ObjectStreamClass.java:442)
at java.security.AccessController.doPrivileged(Native Method)
at java.io.ObjectStreamClass.<init>(ObjectStreamClass.java:430)
at java.io.ObjectStreamClass.lookup(ObjectStreamClass.java:327)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1130)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at Test.main(Test.java:10)
Caused by: java.lang.ClassNotFoundException: Address
at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:294)
at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
... 12 more