在org.springframework.core.SerializableTypeWrapper
(版本5.2.3(中,第112行有以下代码:
if (GraalDetector.inImageCode() || !Serializable.class.isAssignableFrom(Class.class)) {
// Let's skip any wrapping attempts if types are generally not serializable in
// the current runtime environment (even java.lang.Class itself, e.g. on Graal)
return providedType;
}
我对第二个检查(!Serializable.class.isAssignableFrom(Class.class)
(很好奇:它是否可能求值为true
(即Serialazable.class
不能从Class.class
赋值(?
以下是Class#isAssignableFrom()
javadoc所说的:
确定此class对象表示的类或接口是否与指定的class参数表示的类或者接口相同,或者是该类或者接口的超类或者超接口。
查看Class
的代码,我看到以下内容:
public final class Class<T> implements java.io.Serializable
因此Serializable
是Class
的超接口,并且应该总是可从Class
赋值。但Spring代码中的检查表明,有时情况并非如此。
为什么?在什么情况下会发生这种情况?为什么它们不违反Java语言规范?
自定义类加载器是表达式返回false
的可能机制(如果不太可能的话(。自定义类加载器可以做一些疯狂的事情,包括加载自己版本的标准Java类。关于类加载器需要了解的一些信息:
- 自定义类加载器可以配置为加载任何类,甚至包括Java标准库类(当然不鼓励这样做,但仍然可以(
- 自定义类加载器通常会被配置为将它们不知道如何加载的类委托给系统类加载器
- 当类A具有对类B的引用时,将使用用于加载类A的类加载器来解析该引用
- 可以配置多个类加载器来处理同一个类,这可能会导致一个类的多个版本被加载到JVM中,实际实现取决于您要求的类加载器
假设有一个自定义类加载器,无论出于何种原因,它被配置为自己加载java.io.Serializable
,但委托给系统类加载器来加载其他类,包括java.lang.Class
。
现在假设这个自定义类加载器用于加载SerializableTypeWrapper
。这意味着它还将用于解析SerializableTypeWrapper
中对java.io.Serializable
的引用。通过引用java.lang.Class
,自定义类加载器将把它委托给系统类加载器。系统类加载器将用于加载java.lang.Class
,但也将用于从java.lang.Class
中加载对java.io.Serializable
的引用。
所以现在我们可以问一个问题——java.io.Serializable [custom]
可以从java.lang.Class [standard]
分配吗?答案是否定的——java.lang.Class
确实实现了java.io.Serializable [standard]
,但它没有实现java.io.Serializable [custom]
。