Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala:为什么扩展trait会破坏'Class.getConstructor()`?_Scala_Traits - Fatal编程技术网

Scala:为什么扩展trait会破坏'Class.getConstructor()`?

Scala:为什么扩展trait会破坏'Class.getConstructor()`?,scala,traits,Scala,Traits,当一个类扩展一个trait时,如果调用getConstructor(),否则会成功,然后抛出一个NoSuchMethodException。为什么会发生这种情况?我们可以做些什么 在下面的代码中,getConstructor()的第一次调用返回时没有错误。第二个提出了例外 trait MyTrait class MyClass(root: String) object Main extends App { val one = new MyClass("foo") one.getCl

当一个类扩展一个trait时,如果调用
getConstructor()
,否则会成功,然后抛出一个
NoSuchMethodException
。为什么会发生这种情况?我们可以做些什么

在下面的代码中,
getConstructor()
的第一次调用返回时没有错误。第二个提出了例外

trait MyTrait

class MyClass(root: String)

object Main extends App {

  val one = new MyClass("foo")
  one.getClass.getConstructor(classOf[String])
  println("so far so good")

  val two = new MyClass("foo") with MyTrait
  two.getClass.getConstructor(classOf[String]) // NoSuchMethodException

}
使用零参数构造函数创建一个新的匿名类(该构造函数在内部执行
super(“foo”)
),然后创建该新类的实例

classOf[MyClass] eq one.getClass
classOf[MyClass] ne two.getClass
因为在新的匿名类中没有基于
字符串的构造函数,所以代码失败

使用零参数构造函数创建一个新的匿名类(该构造函数在内部执行
super(“foo”)
),然后创建该新类的实例

classOf[MyClass] eq one.getClass
classOf[MyClass] ne two.getClass

因为在新的匿名类中没有基于字符串的构造函数,所以代码会失败。

让我们仔细看看会发生什么

我稍微修改了您的定义,以简化生成的输出。我的
Main
对象如下所示:

object App {
  def main(args: Array[String]): Unit = {
    val one = new MyClass("foo")
    one.getClass.getConstructor(classOf[String])
    println("so far so good")

    val two = new MyClass("foo") with MyTrait
    two.getClass.getConstructor(classOf[String]) // NoSuchMethodException
  }
}
val foo = "foo"
val two = new MyClass(foo) with MyTrait
编译后,我们得到以下类:
App$$anon$1.class
App$.class
App.class
MyClass.class
MyTrait.class

MyClass.class
MyTrait.class
都是琐碎的,我不会讨论它们

让我们看看有趣的课程:

  • App.class
  • 以下是
    javap-c
    输出:

    public final class test.App {
      public static void main(java.lang.String[]);
        Code:
           0: getstatic     #16                 // Field test/App$.MODULE$:Ltest/App$;
           3: aload_0
           4: invokevirtual #18                 // Method test/App$.main:([Ljava/lang/String;)V
           7: return
    }
    
    如我们所见,它只调用
    App$.main
    方法

  • App$.class
  • 这是里面的东西:

    public final class test.App$ {
      public static test.App$ MODULE$;
    
      public static {};
        Code:
           0: new           #2                  // class test/App$
           3: invokespecial #14                 // Method "<init>":()V
           6: return
    
      public void main(java.lang.String[]);
        Code:
           0: new           #19                 // class test/MyClass
           3: dup
           4: ldc           #21                 // String foo
           6: invokespecial #24                 // Method test/MyClass."<init>":(Ljava/lang/String;)V
           9: astore_2
          10: aload_2
          11: invokevirtual #28                 // Method test/MyClass.getClass:()Ljava/lang/Class;
          14: iconst_1
          15: anewarray     #30                 // class java/lang/Class
          18: dup
          19: iconst_0
          20: ldc           #32                 // class java/lang/String
          22: aastore
          23: invokevirtual #36                 // Method java/lang/Class.getConstructor:([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
          26: pop
          27: getstatic     #41                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
          30: ldc           #43                 // String so far so good
          32: invokevirtual #47                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
          35: new           #7                  // class test/App$$anon$1
          38: dup
          39: invokespecial #48                 // Method test/App$$anon$1."<init>":()V
          42: astore_3
          43: aload_3
          44: invokevirtual #28                 // Method test/MyClass.getClass:()Ljava/lang/Class;
          47: iconst_1
          48: anewarray     #30                 // class java/lang/Class
          51: dup
          52: iconst_0
          53: ldc           #32                 // class java/lang/String
          55: aastore
          56: invokevirtual #36                 // Method java/lang/Class.getConstructor:([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
          59: pop
          60: return
    
      private test.App$();
        Code:
           0: aload_0
           1: invokespecial #54                 // Method java/lang/Object."<init>":()V
           4: aload_0
           5: putstatic     #56                 // Field MODULE$:Ltest/App$;
           8: return
    }
    
    public final class test.App$$anon$1 extends test.MyClass implements test.MyTrait {
      public test.App$$anon$1();
        Code:
           0: aload_0
           1: ldc           #16                 // String foo
           3: invokespecial #19                 // Method test/MyClass."<init>":(Ljava/lang/String;)V
           6: return
    }
    
    在这里,我们终于看到了我们的
    “foo”
    (在第1行)<代码>ldc
    表示“负载常数”;“#16”是对表中该常数的引用;注释说它的类型是
    String
    ,值是
    foo

    第3行是对
    MyClass.“:(Ljava/lang/String;)V
    的调用

    TLDR优化器在自动生成的类的构造函数中隐藏常量。所以构造函数本身没有任何参数

    PS:如果我们像这样更改代码:

    object App {
      def main(args: Array[String]): Unit = {
        val one = new MyClass("foo")
        one.getClass.getConstructor(classOf[String])
        println("so far so good")
    
        val two = new MyClass("foo") with MyTrait
        two.getClass.getConstructor(classOf[String]) // NoSuchMethodException
      }
    }
    
    val foo = "foo"
    val two = new MyClass(foo) with MyTrait
    
    然后我们得到一个自动生成的类,该类具有接受
    字符串
    参数的构造函数:

    public final class test.App$$anon$1 extends test.MyClass implements test.MyTrait {
      public test.App$$anon$1(java.lang.String);
        Code:
           0: aload_0
           1: aload_1
           2: invokespecial #17                 // Method test/MyClass."<init>":(Ljava/lang/String;)V
           5: return
    }
    
    public final class test.App$$anon$1扩展test.MyClass实现test.MyTrait{
    public test.App$$anon$1(java.lang.String);
    代码:
    0:aload_0
    1:aload_1
    2:invokespecial#17//methodtest/MyClass.“:(Ljava/lang/String;)V
    5:返回
    }
    
    让我们仔细看看发生了什么

    我稍微修改了您的定义,以简化生成的输出。我的
    Main
    对象如下所示:

    object App {
      def main(args: Array[String]): Unit = {
        val one = new MyClass("foo")
        one.getClass.getConstructor(classOf[String])
        println("so far so good")
    
        val two = new MyClass("foo") with MyTrait
        two.getClass.getConstructor(classOf[String]) // NoSuchMethodException
      }
    }
    
    val foo = "foo"
    val two = new MyClass(foo) with MyTrait
    
    编译后,我们得到以下类:
    App$$anon$1.class
    App$.class
    App.class
    MyClass.class
    MyTrait.class

    MyClass.class
    MyTrait.class
    都是琐碎的,我不会讨论它们

    让我们看看有趣的课程:

  • App.class
  • 以下是
    javap-c
    输出:

    public final class test.App {
      public static void main(java.lang.String[]);
        Code:
           0: getstatic     #16                 // Field test/App$.MODULE$:Ltest/App$;
           3: aload_0
           4: invokevirtual #18                 // Method test/App$.main:([Ljava/lang/String;)V
           7: return
    }
    
    如我们所见,它只调用
    App$.main
    方法

  • App$.class
  • 这是里面的东西:

    public final class test.App$ {
      public static test.App$ MODULE$;
    
      public static {};
        Code:
           0: new           #2                  // class test/App$
           3: invokespecial #14                 // Method "<init>":()V
           6: return
    
      public void main(java.lang.String[]);
        Code:
           0: new           #19                 // class test/MyClass
           3: dup
           4: ldc           #21                 // String foo
           6: invokespecial #24                 // Method test/MyClass."<init>":(Ljava/lang/String;)V
           9: astore_2
          10: aload_2
          11: invokevirtual #28                 // Method test/MyClass.getClass:()Ljava/lang/Class;
          14: iconst_1
          15: anewarray     #30                 // class java/lang/Class
          18: dup
          19: iconst_0
          20: ldc           #32                 // class java/lang/String
          22: aastore
          23: invokevirtual #36                 // Method java/lang/Class.getConstructor:([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
          26: pop
          27: getstatic     #41                 // Field scala/Predef$.MODULE$:Lscala/Predef$;
          30: ldc           #43                 // String so far so good
          32: invokevirtual #47                 // Method scala/Predef$.println:(Ljava/lang/Object;)V
          35: new           #7                  // class test/App$$anon$1
          38: dup
          39: invokespecial #48                 // Method test/App$$anon$1."<init>":()V
          42: astore_3
          43: aload_3
          44: invokevirtual #28                 // Method test/MyClass.getClass:()Ljava/lang/Class;
          47: iconst_1
          48: anewarray     #30                 // class java/lang/Class
          51: dup
          52: iconst_0
          53: ldc           #32                 // class java/lang/String
          55: aastore
          56: invokevirtual #36                 // Method java/lang/Class.getConstructor:([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
          59: pop
          60: return
    
      private test.App$();
        Code:
           0: aload_0
           1: invokespecial #54                 // Method java/lang/Object."<init>":()V
           4: aload_0
           5: putstatic     #56                 // Field MODULE$:Ltest/App$;
           8: return
    }
    
    public final class test.App$$anon$1 extends test.MyClass implements test.MyTrait {
      public test.App$$anon$1();
        Code:
           0: aload_0
           1: ldc           #16                 // String foo
           3: invokespecial #19                 // Method test/MyClass."<init>":(Ljava/lang/String;)V
           6: return
    }
    
    在这里,我们终于看到了我们的
    “foo”
    (在第1行)<代码>ldc
    表示“负载常数”;“#16”是对表中该常数的引用;注释说它的类型是
    String
    ,值是
    foo

    第3行是对
    MyClass.“:(Ljava/lang/String;)V
    的调用

    TLDR优化器在自动生成的类的构造函数中隐藏常量。所以构造函数本身没有任何参数

    PS:如果我们像这样更改代码:

    object App {
      def main(args: Array[String]): Unit = {
        val one = new MyClass("foo")
        one.getClass.getConstructor(classOf[String])
        println("so far so good")
    
        val two = new MyClass("foo") with MyTrait
        two.getClass.getConstructor(classOf[String]) // NoSuchMethodException
      }
    }
    
    val foo = "foo"
    val two = new MyClass(foo) with MyTrait
    
    然后我们得到一个自动生成的类,该类具有接受
    字符串
    参数的构造函数:

    public final class test.App$$anon$1 extends test.MyClass implements test.MyTrait {
      public test.App$$anon$1(java.lang.String);
        Code:
           0: aload_0
           1: aload_1
           2: invokespecial #17                 // Method test/MyClass."<init>":(Ljava/lang/String;)V
           5: return
    }
    
    public final class test.App$$anon$1扩展test.MyClass实现test.MyTrait{
    public test.App$$anon$1(java.lang.String);
    代码:
    0:aload_0
    1:aload_1
    2:invokespecial#17//methodtest/MyClass.“:(Ljava/lang/String;)V
    5:返回
    }
    
    有趣的是,如果您使用变量而不是常量,那么scala将生成带有
    字符串
    参数的构造函数。@Oleg Pyzhcov:毫无疑问,这个答案是正确的,但这是否有文档记录?你是通过阅读源代码了解到这一点的吗?@talex:你确定吗?我将
    val-two
    更改为
    var-two
    ,但仍然引发异常。@AdamMackler我的意思是,如果您将
    “foo”
    替换为
    foo
    并声明
    var-foo=“foo”
    @talex,您确定这是真的吗?我在
    two
    的定义之上定义了
    var foo=“foo”
    ,然后将
    val two=new MyClass(“foo”)
    更改为
    val two=new MyClass(foo)
    但仍然引发了异常。有趣的是,如果您使用变量而不是常量,scala将生成带有
    字符串
    参数的构造函数。@Oleg Pyzhcov:毫无疑问,这个答案是正确的,但这是否有文档记录?你是通过阅读源代码了解到这一点的吗?@talex:你确定吗?我将
    val-two
    更改为
    var-two
    ,但仍然引发异常。@AdamMackler我的意思是,如果您将
    “foo”
    替换为
    foo
    并声明
    var-foo=“foo”
    @talex,您确定这是真的吗?我在
    two
    的定义之上定义了
    var foo=“foo”
    ,然后将
    val two=new MyClass(“foo”)
    更改为
    val two=new MyClass(foo)
    ,并且仍然引发了异常。我想知道如果您生成
    final val foo=“foo”
    ,它是否会返回到内联?您的
    final val foo
    是什么意思
    val
    已经意味着您不能更改它,而且
    final val foo
    甚至连co都不能更改