可序列化的 `.class` 怎么会无法从 `Class.class` 进行赋值?

huangapple go评论83阅读模式
英文:

How can Serializable.class not be assignable from Class.class?

问题

org.springframework.core.SerializableTypeWrapper(版本5.2.3)中,第112行有以下代码:

if (GraalDetector.inImageCode() || !Serializable.class.isAssignableFrom(Class.class)) {
    // 如果在当前运行时环境中类型通常不可序列化(甚至是java.lang.Class本身,例如在Graal上),则跳过任何尝试包装的操作
    return providedType;
}

关于第二个检查(!Serializable.class.isAssignableFrom(Class.class))我很好奇:它有可能被评估为 true 吗(也就是说,Serializable.class 无法赋值给 Class.class)?

这是 Class#isAssignableFrom() 的Javadoc说明:

> 确定由此 Class 对象表示的类或接口是否与由指定的 Class 参数表示的类或接口相同,或者是其超类或超接口。

Class 的代码中看到以下内容:

public final class Class<T> implements java.io.Serializable

因此,SerializableClass 的超接口,应该始终可以从 Class 进行赋值。但是,Spring 代码中的检查表明有时可能不行。

为什么会这样?在什么情况下会发生这种情况,为什么它们不违反Java语言规范?

英文:

In org.springframework.core.SerializableTypeWrapper (version 5.2.3), there is the following code at line 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;
	}

I'm curious about the second check (!Serializable.class.isAssignableFrom(Class.class)): is it possible for it to evaluate to true (that is, for Serialazable.class to be not assignable from Class.class)?

Here is what Class#isAssignableFrom() javadoc says:

>Determines if the class or interface represented by this Class object is either the same as, or is a superclass or superinterface of, the class or interface represented by the specified Class parameter.

Looking at the code of Class, I see the following:

public final class Class<T> implements java.io.Serializable

So Serializable is a superinterface of Class and should always be assignable from Class. But the check in the Spring code suggests that sometimes it's not.

How come? In what situations can this happen and why don't they violate the Java Language Specification?

答案1

得分: 2

一个自定义的类加载器是表达式返回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]

英文:

A custom class loader is a possible (if unlikely) mechanism for the expression to return false. Custom class loaders can do some crazy things, including loading their own versions of standard Java classes. Some things to know about class loaders:

  • Custom class loaders can be configured to load any class, even including Java standard library classes (it's discouraged of course, but still possible)
  • Custom class loaders will typically be configured to delegate to the system class loader for classes that they don't know how to load.
  • When class A has a reference to class B, the reference will be resolved using whichever class loader was used to load class A
  • More than one class loader can be configured to handle the same class, which can lead to multiple versions of a class getting loaded into the JVM, with the actual implementation you get depending on which class loader you ask

Suppose there is a custom class loader that, for whatever reason, is configured to load java.io.Serializable by itself, but delegates to the system class loader for loading other classes, including java.lang.Class.

Now suppose this custom class loader is used to load SerializableTypeWrapper. This means it will also be used to resolve the reference to java.io.Serializable in SerializableTypeWrapper. With the reference to java.lang.Class, the custom class loader will delegate this to the system class loader. The system class loader will be used to load java.lang.Class, but it will also be used to load the reference to java.io.Serializable from within java.lang.Class.

So now we can ask the question - is java.io.Serializable [custom] assignable from java.lang.Class [standard]? And the answer is no - java.lang.Class does implement java.io.Serializable [standard], but it does not implement java.io.Serializable [custom].

huangapple
  • 本文由 发表于 2020年7月24日 14:13:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/63067863.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定