2016-08-26 3 views
1

Ich musste meinen eigenen JDK dynamischen Proxy schreiben, um die Fähigkeit der dynamischen Schnittstellenimplementierung zur Verfügung zu stellen. Da ich mit akka arbeite, muss es in Scala geschrieben werden. Aber ich mit ein paar ziemlich seltsame Verhalten konfrontiert unterscheidet sich von Java:Scala vs Java Methode Aufruf

object Main extends App { 
    println(classOf[Message].getDeclaredMethod("msg") 
          .invoke(Message("Test"), null)) 
          //throws IllegalArgumentException 
} 

case class Message(message: String){ 
    def msg() = message 
} 

Stacktrace:

Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at Main$.delayedEndpoint$Main$1(Main.scala:2) 
    at Main$delayedInit$body.apply(Main.scala:1) 
    at scala.Function0$class.apply$mcV$sp(Function0.scala:34) 
    at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12) 
    at scala.App$$anonfun$main$1.apply(App.scala:76) 
    at scala.App$$anonfun$main$1.apply(App.scala:76) 
    at scala.collection.immutable.List.foreach(List.scala:381) 
    at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35) 
    at scala.App$class.main(App.scala:76) 
    at Main$.main(Main.scala:1) 
    at Main.main(Main.scala) 

DEMO

Aber ich in Java, es funktioniert:

public static void main (String[] args) throws java.lang.Exception 
{ 
    System.out.println(Message.class.getDeclaredMethod("msg") 
       .invoke(new Message(), null)); //prints Message 
} 

public static class Message{ 
    public String msg(){ 
     return "Message"; 
    } 
} 

DEMO

Warum wirft Scala eine Ausnahme? Und wie man es repariert?

+4

Ich wette, dass Scala das 'null' Argument anders in seine eigenen Argumente einpackt, anstatt _no arguments_ zu meinen. Einfach aus dem Aufruf entfernen. –

+1

@SotiriosDelimanolis hat Recht, ohne das Null ergibt, was Sie erwarten –

+0

@SotiriosDelimanolis Sehr interessant, aber wissen Sie nicht die genaue Scala Magie über Null? – user3663882

Antwort

3

Hoffentlich kann ich zeigen, was los ist:

class TheClass { 
    def theMethod:Unit = { println("It's me the method"); } 
} 

scala> classOf[TheClass].getDeclaredMethod("theMethod").invoke(new TheClass, null) 
java.lang.IllegalArgumentException: wrong number of arguments 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 

scala> classOf[TheClass].getDeclaredMethod("theMethod").invoke(new TheClass) 
It's me the method 
res1: Object = null 

Wie erwartet, haben aber nun einen Blick auf diese:

scala> classOf[TheClass] 
     .getDeclaredMethod("theMethod").invoke(new TheClass, Array.empty) 
java.lang.IllegalArgumentException: wrong number of arguments 

Versus dies:

scala> classOf[TheClass] 
     .getDeclaredMethod("theMethod").invoke(new TheClass, Array.empty : _*) 
It's me the method 
res4: Object = null 

Mitteilung über die Unterschied zwischen den Aufrufe: .invoke(new TheClass, Array.empty) vs .invoke(new TheClass, Array.empty : _*). Was geschieht, ist, dass invoke zweite Argument ist ein varargs, die in eine Anordnung unter der Motorhaube gedreht werden sollte, wenn es eine einfache Array.empty oder null scalac sie ersetzt und mit Array(Array.empty)Array(null) gegeben wird. Wenn das Argument nicht zur Verfügung gestellt wird, ist es tatsächlich Array.empty und wenn wir verwenden, teilt es dem Compiler nur mit, dass das Argument, das wir beweisen, ist die Varargs selbst.

+0

Sehr interessant, vielen Dank. – user3663882