根据Java 编程语言第 4 版。第 15.7.1 节“类型令牌”:
编译器对getClass进行特殊处理:如果在静态类型T的引用上调用getClass,则编译器将getClass的返回类型视为Class。所以这有效:
String str = "Hello";
Class<? extends String> c2 = str.getClass(); // compiler magic
类中方法的javadocs 提供了getClass
Object
更多详细信息:
实际结果类型 [of
getClass()
]是Class<? extends |X|>
调用|X|
getClass 的表达式的静态类型的擦除。例如,此代码片段中不需要强制转换:Number n = 0; Class<? extends Number> c = n.getClass();
那是 Java 和getClass()
class 的方法Object
。将注意力转移到 Scala,SLS 3.2.10 读取,
存在类型的占位符语法
句法:
WildcardType ::= ‘_’ TypeBounds
Scala 支持存在类型的占位符语法。通配符类型的形式为_ >: L <: U ...通配符类型是存在量化类型变量的简写,其中存在量化是隐含的。
...令T = pc[targs, T, targs']为参数化类型,其中targs , targs'可能为空,并且T是通配符类型_ >: L <: U。那么T等价于存在类型
pc[targs, t, targs] forSome { type t >: L <: U }
其中t是一些新的类型变量。
我在上面强调了“T 等同于存在类型......”,因为我观察到的行为似乎与该陈述不一致。
我做了什么
在 Scala repl 中,我尝试了 SLS 3.2.10 的通配符语法:
scala> val c: Class[_ >: scala.Nothing <: String] = "foo".getClass
c: Class[_ <: String] = class java.lang.String
这正如我所料。但是,如果我依赖 SLS 3.2.10 中声称的等效性“通配符类型是存在量化类型变量的简写”,我会遇到意外的失败。
scala> val c: Class[t forSome { type t >: scala.Nothing <: String }] = "foo".getClass
<console>:7: error: type mismatch;
found : java.lang.Class[?0] where type ?0 <: java.lang.String
required: Class[t forSome { type t <: String }]
Note: ?0 <: t forSome { type t <: String }, but Java-defined class Class is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: t forSome { type t <: String }`. (SLS 3.2.10)
val c: Class[t forSome { type t >: scala.Nothing <: String }] = "foo".getClass
^
错误消息似乎将我递归地引导回 SLS 3.2.10,建议我同时使用通配符语法和表达存在量化。我不明白那是什么意思。无论如何,我使用Object
上面引用的 javadocs 中的示例观察到相同的二分法:
scala> val n: Number = 0
n: java.lang.Number = 0
作品:
scala> val c: Class[_ >: scala.Nothing <: Number] = n.getClass
c: Class[_ <: java.lang.Number] = class java.lang.Integer
不工作:
scala> val c: Class[t forSome { type t >: scala.Nothing <: Number }] = n.getClass
<console>:8: error: type mismatch;
found : java.lang.Class[?0] where type ?0 <: java.lang.Number
required: Class[t forSome { type t <: java.lang.Number }]
Note: ?0 <: t forSome { type t <: java.lang.Number }, but Java-defined class Class is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: t forSome { type t <: java.lang.Number }`. (SLS 3.2.10)
val c: Class[t forSome { type t >: scala.Nothing <: Number }] = n.getClass
问题
主要是
如果特定的通配符类型与特定的存在类型“等效”,这是否意味着可以用一个替换另一个?这不就是等价的意思吗?假设我正确理解了 SLS 3.2.10 中使用的“等价”的含义,我尝试根据 SLS 3.2.10 中规定的规则进行等效替换是否有错误?repl 如何处理我上面引用的包含与 SLS 3.2.10 一致的存在类型的两个语句的失败,根据这些语句,失败的语句等同于使用成功的通配符类型的语句?
此外
相关错误消息的required行和found行中指定的类型有什么区别?即,这是怎么回事:
java.lang.Class[?0] where type ?0 <: java.lang.String
不同于
Class[t forSome { type t <: String }]
第一个问号是什么?显然?0
意味着什么,它似乎是一个类型变量,但使用这样的问号不是Scala,是吗?那是什么语言,在哪里指定,以便我可以理解该错误消息?