在Java中,有没有办法检查一个对象是否可序列化?

12

当我为一个问题浪费了很多时间后,我发现在Java中Object类不可序列化。
那么有没有人知道其他不可序列化的类或者任何一种检查类是否可序列化的方法?


1
这可能会对你有所帮助:https://dev59.com/wXRA5IYBdhLWcg3w9izq - 8f7ca04d817b1696
我尝试编写了一个尽力而为的单元测试,以检查接口或类是否完全可远程/可序列化,链接在这里:https://dev59.com/jW865IYBdhLWcg3wZNnT#51732244 - wu-lee
7个回答

15
if(someObj instanceof Serializable) // recommended because it uses 
                                    // the byte code instruction INSTANCEOF
或者
if(Serializable.class.isInstance(someObj))

如果需要在运行时替换Class,那么使用Class.isInstance(someObj)是有意义的。

例如:

Class<?> someClass == ....; // assign a class object reference dynamically
if(someClass.isInstance(someObj))

2
检查某个对象是否可序列化,不仅仅是检查它是否实现了“Serializable”接口。一些可序列化的类并不是“Serializable”(例如枚举、日期等)。而有些实现了“Serializable”接口的类却不一定可序列化(例如那些具有非可序列化成员的类)。 - wu-lee
@wu-lee 首先,枚举类型是可序列化的,并且实现了Serializable,请查看官方文档:https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html。如果你指的是`java.util.Date`,同样适用。其次,这个责任在类的程序员身上。如果你将一个类标记为`Serializable`,你必须确保所有非短暂实例字段也是可序列化的。或者你可以编写自己的序列化方法(writeObject、readObject)。请参阅http://www.oracle.com/technetwork/articles/java/javaserial-1536170.html。 - René Link
关于日期等方面的问题,我认为你说得对。然而,我认为第二点仍然成立,这也是为什么检查对象是否可序列化比你的答案(目前被接受的答案)所建议的要困难得多。它还需要更多的测试来确保序列化工作正常——例如,我发现类型不是“Serializable”的字段如果为“null”将会被序列化,这可能会导致一种错误的安全感和在运行时出现意外异常,如果你没有注意到这一点。 - wu-lee
@wu-lee 我理解你的观点。在我看来,开发人员也必须关注 javadoc,如果我阅读 Serializable 的 javadoc,我就知道该怎么做了。但你也是对的,事情可能会更加复杂。例如,想象一个具有 java.util.List 类型字段的类。java.util.List 不扩展 Serializable。现在,它取决于设置的具体列表类型是否可序列化。将字段设置为 ArrayList 将起作用。其他列表实现可能无法正常工作。比如由持久性框架设置的延迟加载列表。 - René Link

12

仅使用instanceof是不完全可靠的,就像以下代码所示。最好的方法是检查您尝试进行编组的类的源代码,如果您有它们,或者如果没有,您可以希望供应商正确处理了这件事。

class A {
    final int field;



/*
// uncomment this ctor to make class "more" serializable
    A()  {
        this.field = -1;
    }
*/


    A(int field) {
        this.field = field;
    }
}

class B extends A implements Serializable {

    B(int field) {
        super(field);
    }

    public String toString() {
        return "B{field=" + field + "}";
    }
}

class Test {
    public static void main(String[] args) {
        System.out.println(Serializable.class.isAssignableFrom(B.class));

        B b = new B(11);

        try {
            ByteArrayOutputStream bf = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bf);
            oos.writeObject(b);
            oos.close();

            ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bf.toByteArray()));
            Object o = ois.readObject();
            System.out.println(o.toString());
        } catch (Exception e) {
            System.out.println("Not exactly Serializable");
            e.printStackTrace();
        }

    }
}

你正在展示 implements Serializable 并不足以实际序列化对象。你完全正确,但我认为这不是被问到的问题(或者原帖作者需要更具体地表达)。 - m0skit0
在我看来,你说得非常到位。 - Dagmar

7
如果一个对象可序列化,你应该可以将它转换成一个字节数组。所以你可以使用这个测试方法来确保在序列化时不会抛出异常。
@Test
public void testIfYourClassIsSerilaizable()  {

    boolean exceptionThrown = false;
    try {
        YourClass obj = new YourClass();
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        oos.flush();
        byte [] data = bos.toByteArray();

    } catch(IOException ex) {
        exceptionThrown = true;
    }
    Assert.assertFalse(exceptionThrown);
}

因此,基于这一点,如果YourClass或其属性没有实现Serializable接口,上述测试将抛出异常,使该类不可序列化。


2
我认为这是测试一个类是否可序列化的唯一方法,instanceOf并不是完全可靠的方法。 - Shubham Gupta

5
是的
if (yourObjectInstance instanceof Serializable) {
    // It is
} else {
    // It is not
}

请注意,如果yourObjectInstancenull,那么会进入else部分,因为无论引用是关于什么类的,null都不是Serializable。此外,正如Victor Sorokin指出的那样,一个类实现Serializable并不意味着它实际上可以被序列化。

2

有些人建议使用instanceof运算符,但它做的是另一件事情:如果引用为空,则返回false,即使该类实现了Serializable接口! 而且这也适用于Class.isInstance(Object obj)


2
但是 Serializable.class.isInstance(null) 也将返回 false。变量声明的类型是什么并不重要,如果引用为 null,那么 instanceofClass.isInstance() 都会返回 false。 - René Link
1
null不是一个对象实例,因此它没有实现Serializable接口,所以这个行为是完全正确的。 - m0skit0
我并没有说它不正确。我只是澄清了它的行为。当你有一个 isSerializable(Object obj) { } 方法时,你不能保证调用者会将 null 放入其中。 - gyorgyabraham

0

你可以检查

someObject instanceof Serializable

如果someObject实现了Serializable接口,这将评估为true


-1

您可以检查类是否可序列化:

if(someObj instanceof Serializable)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接