I noticed that AbstractMethodError occurred when execute the following codes.
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)
Is this a bug or specification ?
P.S. Scala version 2.9.2 , 2.10.0-M3 and 2.10.0-SNAPSHOT (2.10.0-20120507-163905-843ac9520c) same error occurred
It's a bit complicated. It's a bug--the Scala compiler should emit an error--but it's a somewhat subtle one.
The problem is that since you have left public off of the abstract method, its visibility is package-private. If you write this in Java:
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));
}
}
then the Java compiler will complain:
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
It clearly is trying to override, but it doesn't actually work since it's not in the right package and therefore can't actually access (or override) the original foo. If we change the package to javapkg, then everything works. If we try this Scala instead:
package javapkg
class ScalaClass extends JavaClass{
def foo(a:Int) = a.toString
}
object ScalaClass extends App{
println(new ScalaClass().bar(10))
}
then Scala works fine also.
It is the fault of Scala's compiler that it doesn't notice this mistake--it should emit the same error as the Java compiler (or a more helpful one that actually tells you that the access is screwy!) rather than emitting bytecode that cannot work.
But it's easy to fix: just change the package on the Scala code (or the access modifier in the Java code).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With