Java 特征和接口是二进制兼容的吗?
我只是有点惊讶于,Java 特征和接口是二进制兼容的吗?,java,scala,interface,traits,Java,Scala,Interface,Traits,我只是有点惊讶于,Scala跨越了不同的版本。现在,因为在Java8中,我们有默认的方法实现,这与trait提供给我们的在Java代码中使用trait安全吗?我试着自己使用它,因为: trait TestTrait { def method(v : Int) def concrete(v : Int) = println(v) } public class Test implements TestTrait{ // Compile-error. Implement concrete(I
Scala
跨越了不同的版本。现在,因为在Java8
中,我们有默认的方法实现,这与trait
提供给我们的在Java代码中使用trait安全吗?我试着自己使用它,因为:
trait TestTrait {
def method(v : Int)
def concrete(v : Int) = println(v)
}
public class Test implements TestTrait{ // Compile-error. Implement concrete(Int)
@Override
public void method(int v) {
System.out.println(v);
}
}
但它拒绝编译。编译器抱怨没有实现
concrete(Int)
。尽管在Scala 2.11编译器编译trait时,我在TestTrait
中指定了实现,但它不会使用默认方法生成接口,因为生成的代码必须与Java 6一起使用。在Scala2.12(需要Java8)中,它会,所以如果您使用2.12编译器编译Scala代码,我希望您能够以这种方式从Java使用它(至少对于这样一个简单的情况)
请注意,这样的更改正是使不同的Scala版本二进制不兼容的原因:如果您尝试使用Scala 2.12中使用Scala 2.11编译的特性,它将尝试调用接口的默认方法,而这些方法并不存在 Scala 2.11编译器编译trait时,不会生成带有默认方法的接口,因为生成的代码必须使用Java 6。在Scala2.12(需要Java8)中,它会,所以如果您使用2.12编译器编译Scala代码,我希望您能够以这种方式从Java使用它(至少对于这样一个简单的情况)
请注意,这样的更改正是使不同的Scala版本二进制不兼容的原因:如果您尝试使用Scala 2.12中使用Scala 2.11编译的特性,它将尝试调用接口的默认方法,而这些方法并不存在 您的期望值相互矛盾 您会“惊讶”地看到Scala在主要版本之间是二进制不兼容的,这表明您的预期正好相反:即使在主要版本之间,Scala也应该是二进制兼容的 但同时,你也希望Scala使用一种特征编码,这种特征依赖于Scala 2.11二进制格式设计时甚至不存在的特性。Scala 2.11的第一个候选版本,也就是说,在Java 8发布之前的两周,不允许再进行任何更改。要求每个Scala用户在Java8发布之前就安装它是荒谬的 因此,一方面,您期望完全的二进制兼容性,即完全没有更改。另一方面,您希望使用最新和最强大的功能,即尽快进行更改。你不能两者兼得。你必须选择 而且,正如Alexey在他的回答中指出的,正是这样的改进需要打破二进制兼容性 如果你有二进制兼容性,你不能改变你的二进制表示,如果你找到一个更好的。而且,当目标平台的新功能可用时,您无法使用它们。这是非常严格的,特别是对于Scala这样的语言,它突破了JVM上可以合理编码的界限。如果编译器设计者第一次就强迫他们“一切正常”,那将是非常苛刻的 以下是几年来发生了变化并破坏了向后兼容性的几件事情:
- 在Java7中添加lambda时,使用
s对lambda进行编码。他们不可能“第一次就做到了”,因为那时MethodHandle
s根本不存在MethodHandle
- (在接下来的2.12中)lambdas的编码,同样,它们与Java8的编码相同。他们不可能“第一次就做到了”,因为那时lambdas甚至不存在于Java中
- (在接下来的2.12节中)使用
s中的接口
方法对性状进行编码。他们不可能“第一次就做到这一点”,因为当时Java中甚至不存在默认
方法default
.class
文件或.jar
的元数据部分中提供,对于Scala.js,将在编译的源文件中的注释或二进制数组中提供,对于Scala,将在编译的.dll
,.exe
,.so
,.dylib
的元数据部分提供,等等
回到你关于特质的具体问题:
目前,单个特征编码为:
- 包含所有trait方法(抽象和具体)的抽象声明的
接口
- 一个静态类,包含所有traits的具体方法的静态方法,使用一个额外的参数
$this
- 在继承层次结构中混合trait的每一点上,trait中所有具体方法的合成转发器方法将转发到静态类的静态方法
trait A {
def foo(i: Int) = i + 1
def abstractBar(i: Int): Int
}
trait B {
def baz(i: Int) = i - 1
}
class C extends A with B {
override def abstractBar(i: Int) = i * i
}
将按如下方式编码:
接口A{
int foo(int i);
intAbstractBar(intI);
}
A.