scala类型系统:2) classOf与getClass方法的差异

前一篇在提到获取Class时的两个方法:classOf 和 getClass

scala> class  A
scala> val a = new A

scala> a.getClass
res2: Class[_ <: A] = class A

scala> classOf[A]
res3: Class[A] = class A

上面显示了两者的不同,getClass 方法得到的是 Class[A]的某个子类,而 classOf[A] 得到是正确的 Class[A],但是去比较的话,这两个类型是equals为true的

scala> a.getClass  == classOf[A]
res13: Boolean = true

这种细微的差别,体现在类型赋值时,因为java里的 Class[T]是不支持协变的,所以无法把一个 Class[_ < : A] 赋值给一个 Class[A]

scala> val c:Class[A] = a.getClass
<console>:9: error: type mismatch;

scala类型系统:2) classOf与getClass方法的差异》上有28个想法

  1. 协变 逆协变 不协变这些概念有点晕晕的…
    原来写过一段笔记不知道对不对…

    C[T] A B 其中A <: B
    若 C[A]:C[B] C 是 cotravariant
    如果 C[A]和C[B]没有父子关系 那么C是nonvariant

    Scala中是允许你自己定义是否是variant的
    class C[+A]{…} C是covariant
    class C[-A]{…} C是contrvariant
    class C[A] {…} C是nonvariant(默认)

    • 有一段被过滤掉了….
      若 C[A]<:C[B] C 是 covariant
      若 C[A]>:C[B] C 是 cotravariant

    • 你确定?你的小版本号是什么?我机器上是2.11.0-RC4 刚测试了一下还是true.

          • 前面版本写错了
            [hadoop@slave1 ~]$ scala
            Welcome to Scala version 2.11.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_45).

            但是在下面版本下
            C:\Documents and Settings\Administrator>scala
            Welcome to Scala version 2.11.0-M4 (Java HotSpot(TM) Client VM, Java 1.8.0_20).

            scala> a.getClass == classOf[A]
            res2: Boolean = true

  2. 你能把完整的scala版本jdk版本信息 以及执行过程 贴出来吗?我特意下载了一个 2.11.0 的,在 jdk7下运行,也是true

    % export JAVA_HOME=”/System/Library/Frameworks/JavaVM.framework/Versions/jdk1.7/Home” && ./scala
    Welcome to Scala version 2.11.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_67).
    Type in expressions to have them evaluated.
    Type :help for more information.

    scala> class A
    defined class A

    scala> val a = new A
    a: A = A@c3cec2e

    scala> a.getClass == classOf[A]
    res0: Boolean = true

        • 这个问题很蹊跷,不太可能这种低级bug在编译器反复出现,能否在repl下把重现的步骤给出来。

        • Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102)
          scala> class A
          defined class A

          scala> val a = new A
          a: A = A@6f7923a5

          scala> a.getClass == classOf[A]
          res3: Boolean = true

  3. Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102).
    Type in expressions for evaluation. Or try :help.
    win7 64位
    a.getClass == classOf[A]
    该版本是false

  4. 所有所 a.getClass == classOf[A] 为 false 的能否把完整的代码片段贴出来,我怀疑是你们自己的错误,所有反馈说false的没有一个人给出完整的验证过程。
    就像我下面在最新的2.12.1版本里完整的验证过程:

    /data/tools/scala-binary/scala-2.12.1/bin [14:41:16]
    ➜ ./scala
    Welcome to Scala 2.12.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_51).
    Type in expressions for evaluation. Or try :help.

    scala> class A
    defined class A

    scala> val a = new A
    a: A = A@1a3e5f23

    scala> a.getClass == classOf[A]
    res0: Boolean = true

    如果你用的版本得到的是 false ,请贴出完整的过程,避免是你自己的失误。

  5. Welcome to Scala version 2.11.6 (OpenJDK 64-Bit Server VM, Java 1.8.0_121).

    一个版本下结果不一致 : 这个是“true”
    Welcome to Scala version 2.11.6 (OpenJDK 64-Bit Server VM, Java 1.8.0_121).
    Type in expressions to have them evaluated.
    Type :help for more information.

    scala> class A
    defined class A

    scala> val a = new A
    a: A = A@244038d0
    scala> a.getClass == classOf[A]
    res0: Boolean = true

    scala> a.getClass
    res1: Class[_ classOf[A]
    res2: Class[A] = class A

    scala>

    ———————————————————————————————————————————-
    这个是“false“

    scala> val a2 = new A
    a2: A = A@7197b07f

    scala> val b1 = new a1.B
    b1: a1.B = A$B@18709cb2

    scala> val b2 = new a2.B
    b2: a2.B = A$B@b768a65

    scala> b1.getClass
    res13: Class[_ b2.getClass
    res14: Class[_ typeOf[a1.B]
    res15: reflect.runtime.universe.Type = a1.B

    scala> typeOf[a2.B]
    res16: reflect.runtime.universe.Type = a2.B

    scala> typeOf[a1.B]<: typeOf[a1.B]<: classOf[List[Int]] == classOf[List[String]]
    res19: Boolean = true

    scala> a.getClass == classOf[A]
    res20: Boolean = false

    scala> a
    res21: A = A@29eda4f8

    scala> a.getClass
    res22: Class[_ classOf[A]
    res23: Class[A] = class A

    • 第二段,你把 A 这个class怎么定义的,以及 a 这个值怎么创建的过程也贴出来。

  6. Linux dell 4.4.0-59-generic #80-Ubuntu SMP Fri Jan 6 17:47:47 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
    系统

  7. 还有一点要补充下:
    比较不同的代码是
    安装你的文章从类型系统第一篇开始模拟的。

    比较相同的代码是:
    新开了一天终端,直接输入这几个语句。

  8. 不同时的反编译:javap A

    :javap A
    Size 518 bytes
    MD5 checksum 00665e3dcb5ab63ad1b690934dcf755b
    Compiled from “”
    public class A
    minor version: 0
    major version: 50
    flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
    #1 = Utf8 A
    #2 = Class #1 // A
    #3 = Utf8 java/lang/Object
    #4 = Class #3 // java/lang/Object
    #5 = Utf8
    #6 = Utf8
    #7 = Utf8 ()V
    #8 = NameAndType #6:#7 // “”:()V
    #9 = Methodref #4.#8 // java/lang/Object.””:()V
    #10 = Utf8 this
    #11 = Utf8 LA;
    #12 = Utf8
    #13 = Class #12 //
    #14 = Utf8 $line30/$read
    #15 = Class #14 // $line30/$read
    #16 = Utf8
    #17 = Utf8
    #18 = Class #17 //
    #19 = Utf8
    #20 = Class #19 //
    #21 = Utf8
    #22 = Class #21 //
    #23 = Utf8 A
    #24 = Utf8 Code
    #25 = Utf8 LocalVariableTable
    #26 = Utf8 LineNumberTable
    #27 = Utf8 SourceFile
    #28 = Utf8 InnerClasses
    #29 = Utf8 Scala
    {
    public A();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
    stack=1, locals=1, args_size=1
    0: aload_0
    1: invokespecial #9 // Method java/lang/Object.””:()V
    4: return
    LocalVariableTable:
    Start Length Slot Name Signature
    0 5 0 this LA;
    LineNumberTable:
    line 14: 0
    }
    SourceFile: “”
    InnerClasses:
    public static #16= #13 of #15; //=class of class $line30/$read
    public static #16= #18 of #13; //=class of class
    public static #16= #20 of #18; //=class of class
    public static #16= #22 of #20; //=class of class
    public static #23= #2 of #22; //A=class A of class
    Error: unknown attribute
    Scala: length = 0x0

  9. 相同时:

    scala> :javap A
    Size 413 bytes
    MD5 checksum 280934bc1bdc79baba079ad87dfd3620
    Compiled from “”
    public class A
    minor version: 0
    major version: 50
    flags: ACC_PUBLIC, ACC_SUPER
    Constant pool:
    #1 = Utf8 A
    #2 = Class #1 // A
    #3 = Utf8 java/lang/Object
    #4 = Class #3 // java/lang/Object
    #5 = Utf8
    #6 = Utf8
    #7 = Utf8 ()V
    #8 = NameAndType #6:#7 // “”:()V
    #9 = Methodref #4.#8 // java/lang/Object.””:()V
    #10 = Utf8 this
    #11 = Utf8 LA;
    #12 = Utf8
    #13 = Class #12 //
    #14 = Utf8 $line3/$read
    #15 = Class #14 // $line3/$read
    #16 = Utf8
    #17 = Utf8
    #18 = Class #17 //
    #19 = Utf8 A
    #20 = Utf8 Code
    #21 = Utf8 LocalVariableTable
    #22 = Utf8 LineNumberTable
    #23 = Utf8 SourceFile
    #24 = Utf8 InnerClasses
    #25 = Utf8 Scala
    {
    public A();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
    stack=1, locals=1, args_size=1
    0: aload_0
    1: invokespecial #9 // Method java/lang/Object.””:()V
    4: return
    LocalVariableTable:
    Start Length Slot Name Signature
    0 5 0 this LA;
    LineNumberTable:
    line 11: 0
    }
    SourceFile: “”
    InnerClasses:
    public static #16= #13 of #15; //=class of class $line3/$read
    public static #16= #18 of #13; //=class of class
    public static #19= #2 of #18; //A=class A of class
    Error: unknown attribute
    Scala: length = 0x0

    • 不需要贴出这些反编译的内容,你只需要把 a.getClass == classOf[A] 返回 false 的那个过程,完整的给贴出来我就知道怎么回事了,你现在贴出来的信息是从中间开始的,我不知道你之前的 A 怎么定义,a怎么创建的。

  10. 这个问题可以重现:
    进入scala ,从上一篇文章例子输入,不要关闭,到这一篇文章例子中。比较时就会产生不同。

    新打开一个终端,安装本篇文章的示例,比较会相同。

    • 我知道了,你开始显示定义了一个 A 且包含内部 B 的class,并创建了一个a的实例

      scala> class A { class B }
      defined class A

      scala> val a = new A
      a: A = A@73a28541

      你后来又重新定义了一个 A
      scala> class A
      defined class A

      注意,这个时候在REPL下 A 已经覆盖了之前定义的那个 A

      所以 比较时返回false
      scala> a.getClass == classOf[A]
      res3: Boolean = false

      是因为这里的 a.getClass 这个值是之前的 class A { class B } 那个被覆盖掉的 A,而 classOf[A] 是新定义的 A

      是在 REPL 下同名污染所致

  11. scala> % greister@dell tmp % scala
    Welcome to Scala version 2.11.6 (OpenJDK 64-Bit Server VM, Java 1.8.0_121).
    Type in expressions to have them evaluated.
    Type :help for more information.

    scala> import scala.reflect.runtime.universe._
    import scala.reflect.runtime.universe._

    scala> class A
    defined class A

    scala> typeOf[A]
    res0: reflect.runtime.universe.Type = A

    scala> classOf[A]
    res1: Class[A] = class A

    scala> val a = new A
    a: A = A@5b970f7

    scala> a.getClass
    res2: Class[_ a.getClass = classOf[A]
    :12: error: reassignment to val
    a.getClass = classOf[A]
    ^

    scala> a.getClass == classOf[A]
    res3: Boolean = true

    scala> class A { class B }
    defined class A

    scala> val a1 = new A
    a1: A = A@1fd386c3

    scala> val a2 = new A
    a2: A = A@aed0151

    scala> val b1 = new a1.B
    b1: a1.B = A$B@71178a52

    scala> val b2 = new a2.B
    b2: a2.B = A$B@543e593

    scala> b1.getClass
    res4: Class[_ a.getClass == classOf[A]
    res5: Boolean = false

  12. 你先定义的 Class A 被后来的 Class A { class B} 同名类覆盖掉了。

    每次练习前,请先退出一下 REPL ,避免之前同名的类或变量混淆

发表评论

电子邮件地址不会被公开。 必填项已用*标注