2012-05-11 8 views
6

Ich bemerkte, dass AbstractMethodError beim Ausführen der folgenden Codes aufgetreten ist.AbstractMethodError ist aufgetreten, wenn Paket private Methode überschreiben

package javapkg; 

public abstract class JavaClass{ 
    abstract String foo(int b); 

    public String bar(int b){ 
    return foo(b); 
    } 
} 
package scalapkg 

import javapkg._ 

class ScalaClass extends JavaClass{ 
    def foo(a:Int) = a.toString 
} 

object Main extends App{ 
    println(new ScalaClass().bar(10)) 
} 
[error] (run-main) java.lang.AbstractMethodError: javapkg.JavaClass.foo(I)Ljava/lang/String; 
java.lang.AbstractMethodError: javapkg.JavaClass.foo(I)Ljava/lang/String; 
at javapkg.JavaClass.bar(JavaClass.java:7) 
at scalapkg.Main$delayedInit$body.apply(ScalaClass.scala:10) 
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:60) 
at scala.App$$anonfun$main$1.apply(App.scala:60) 
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59) 
at scala.collection.immutable.List.foreach(List.scala:76) 
at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:30) 
at scala.App$class.main(App.scala:60) 
at scalapkg.Main$.main(ScalaClass.scala:9) 
at scalapkg.Main.main(ScalaClass.scala) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
at java.lang.reflect.Method.invoke(Method.java:597) 
java.lang.RuntimeException: Nonzero exit code: 1 
at scala.sys.package$.error(package.scala:27) 

Ist das ein Bug oder Spezifikation?

P.S. Scala Version 2.9.2, 2.10.0-M3 und 2.10.0-SNAPSHOT (2.10.0-20120507-163905-843ac9520c) gleicher Fehler aufgetreten

+0

Und ich möchte wissen, dass dieses Problem auf https://issues.scala-lang.org/ registriert wurde, wenn dies ein Fehler ist. –

Antwort

6

Es ist ein bisschen kompliziert. Es ist ein Fehler - der Scala-Compiler sollte einen Fehler ausgeben - aber es ist ein subtiler Fehler.

Das Problem ist, dass, da Sie public von der abstrakten Methode verlassen haben, seine Sichtbarkeit Paket-privat ist. Wenn Sie dies in Java schreiben:

package javapkgimpl; 

public class JavaClassImpl extends javapkg.JavaClass { 
    String foo(int b) { return (new java.lang.Integer(b)).toString(); } 
    public static void main(String[] args) { 
    System.out.println(new JavaClassImpl().bar(10)); 
    } 
} 

dann werden die Java-Compiler beschweren:

JavaClassImpl.java:3: javapkgimpl.JavaClassImpl is not abstract and does not 
    override abstract method foo(int) in javapkg.JavaClass 
public class JavaClassImpl extends javapkg.JavaClass { 
    ^
1 error 

Es deutlich ist versucht, außer Kraft zu setzen, aber es funktioniert nicht wirklich funktionieren, da es nicht in den richtigen ist Paket und kann daher nicht auf das Original foo zugreifen (oder überschreiben). Wenn wir das Paket zu javapkg ändern, dann funktioniert alles. Wenn wir dieses Scala stattdessen versuchen:

package javapkg 

class ScalaClass extends JavaClass{ 
    def foo(a:Int) = a.toString 
} 

object ScalaClass extends App{ 
    println(new ScalaClass().bar(10)) 
} 

dann funktioniert Scala auch gut.

Es ist die Schuld des Scala-Compilers, dass er diesen Fehler nicht bemerkt - er sollte den gleichen Fehler wie der Java-Compiler (oder einen hilfreicheren, der Ihnen tatsächlich sagt, dass der Zugriff verdreht ist!) Ausgeben Bytecode ausgeben, der nicht funktionieren kann.

Aber es ist einfach zu beheben: Ändern Sie einfach das Paket auf dem Scala-Code (oder den Zugriffsmodifizierer im Java-Code).

+0

Schöne Antwort! (füllen) – Luciano