java8之前规定java接口只能有方法定义,不能有方法实现,java8之后增加了函数式接口,函数式接口可以有一个带实现的抽象方法,scala的特质跟java的接口有点类似,但是没有java代码那样的方法实现数量限制
?
1.接口不会有构造器,特质可以有构造器,并且在实现类继承特质的时候,先要调用特质的构造器。
2.接口中不能有未初始化的属性,且属性的修饰都是public static final,特质中可以有未初始化的属性变量,即抽象字段
3.类实现implements多个接口,且用逗号“,”隔开,类继承extends多个trait且用with隔开。
4.Java中接口不能继承普通类,但是scala中特质可以extends class,并且该类成为所有继承trait的类的父类
实际的我们看例子:
public interface JavaInterface { default void test(String agg) { System.out.println("Interface test"); } } public class JavaInterfaceImpl implements JavaInterface { public void test2(String args) { test("Java interface test: " + args); System.out.println("Java interface impl test" + args ); } public static void main(String args[]) { JavaInterfaceImpl javaInterface = new JavaInterfaceImpl(); javaInterface.test("11111"); javaInterface.test2("11111"); } } 运行结果: Interface test Interface test Java interface impl test11111
?
?
trait ScalaTraitTest { val name:String//抽象字段 println("name: "+name)//特质中构造器执行的语句 def test(arg:String) ={ println(s"Scala Trait test $arg") } def test2(arg:String, arg2:String) ={ println(s"Scala Trait test2 $arg, $arg2") } } class ScalaTraitClass() extends { val name = "jack" } with ScalaTraitTest { def test3(arg3:String) ={ test(arg3) test2(arg3, "2222") println(s"Scala Trait class test 3 $arg3") } } object ScalaTraitClass { def main(args: Array[String]): Unit = { val classTest = new ScalaTraitClass classTest.test3("33333") } } 运行结果: name: jack Scala Trait test 33333 Scala Trait test2 33333, 2222 Scala Trait class test 3 33333
?执行结果首先打印name: jack
?
通过上面的例子,我们反推一下具体的原因,还从class文件入手,通过反编译class文件查看其实际运行
java的函数式接口反编译后是一个abstract interface,其接口的本质没有改变
?
import java.io.PrintStream; public abstract interface JavaInterface { public void test(String agg) { System.out.println("Interface test"); } }?但是scala的特质反编译后有两个class文件,ScalaTraiteTest.class和ScalaTraiteTest$class.class,ScalaTraiteTest$class.class是abstrac class,这里有$init$函数,就是一个构造器,ScalaTraiteTest.class是一个abstract interface
?
?
import scala.reflect.ScalaSignature; public abstract interface ScalaTraitTest { public abstract String name(); public abstract void test(String paramString); public abstract void test2(String paramString1, String paramString2); }?
?
?
import scala.Predef.; import scala.StringContext; import scala.collection.mutable.StringBuilder; public abstract class ScalaTraitTest$class { public static void $init$(ScalaTraitTest $this) { Predef..MODULE$.println(new StringBuilder().append("name: ").append($this.name()).toString()); } public static void test(ScalaTraitTest $this, String arg) { Predef..MODULE$.println(new StringContext(Predef..MODULE$.wrapRefArray((Object[])new String[] { "Scala Trait test ", "" })).s(Predef..MODULE$.genericWrapArray(new Object[] { arg }))); } public static void test2(ScalaTraitTest $this, String arg, String arg2) { Predef..MODULE$.println(new StringContext(Predef..MODULE$.wrapRefArray((Object[])new String[] { "Scala Trait test2 ", ", ", "" })).s(Predef..MODULE$.genericWrapArray(new Object[] { arg, arg2 }))); } }?
?
?我们再看其实现类ScalaTraitClass,ScalaTraitClass类确实实现了ScalaTraitTest接口,但是做了很多的事情,首先他的构造里调用了monospace;">ScalaTraitTest$class的构造器,这跟java类的构造流程一样;其次,ScalaTraitClass里面实现了接口定义的方法test和test2,但是内部实现是分别调用ScalaTraitTest$class的test和test2方法
?
import scala.Predef.; import scala.StringContext; import scala.reflect.ScalaSignature; public class ScalaTraitClass implements ScalaTraitTest { private final String name; public void test(String arg) { ScalaTraitTest.class.test(this, arg); } public void test2(String arg, String arg2) { ScalaTraitTest.class.test2(this, arg, arg2); } public String name() { return this.name; } public ScalaTraitClass() { ScalaTraitTest.class.$init$(this); } public void test3(String arg3) { test(arg3); test2(arg3, "2222"); Predef..MODULE$.println(new StringContext(Predef..MODULE$.wrapRefArray((Object[])new String[] { "Scala Trait class test 3 ", "" })).s(Predef..MODULE$.genericWrapArray(new Object[] { arg3 }))); } }
?
这样来看就清晰了很多,Scala的特质是把java的抽象类和接口特性揉在了一起,这样给编程带来了很大的灵活性也方便了很多。