您的位置:首页 > 大数据 > 人工智能

scala中的trait

2016-01-04 14:27 459 查看
特质
是一些字段和行为的集合,可以扩展或混入(mixin)你的类中。

trait Car {
val brand: String
}

trait Shiny {
val shineRefraction: Int
}


class BMW extends Car {
val brand = "BMW"
}


通过
with
关键字,一个类可以扩展多个特质:

class BMW extends Car with Shiny {
val brand = "BMW"
val shineRefraction = 12
}


什么时候应该使用特质而不是抽象类? 如果你想定义一个类似接口的类型,你可能会在特质和抽象类之间难以取舍。这两种形式都可以让你定义一个类型的一些行为,并要求继承者定义一些其他行为。一些经验法则:

优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。

如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行。例如,你不能说
trait t(i: Int) {}
,参数
i
是非法的。

你不是问这个问题的第一人。可以查看更全面的答案: stackoverflow: Scala特质 vs 抽象类 , 抽象类和特质的区别, and Scala编程: 用特质,还是不用特质?

在Scala中有一个trait类型,它可以被继承,而且支持多重继承,其实它更像我们熟悉的接口(interface),但它与接口又有不同之处是:

//声明一个 trait
trait TraitBase{
def add(x:Int,y:Int): Int ={
return x+y
}
}
//TraitTest 继承自 TraitBase
class TraitTest extends TraitBase{
//重写父类的方法
override def add(x:Int,y:Int): Int ={
return x+y*10
}
}

//如果需要调用父类的方法,使用super访问父类
class TraitTest extends TraitBase{
override def add(x:Int,y:Int): Int ={
return super.add(x,y)*10
}
}

//使用
val test = new TraitTest
println(test.add(4,5))


对于多重继承,我们使用 with 关键字

trait A{
def FA(): Unit ={
println("FA")
}
}
trait B{
def FB(): Unit ={
println("FB")
}
}
class C{
val content=null
}
//多重继承
class D extends C with A with B{
//这里不需要必须实现trait中的方法
}


看完了使用,我们看看编译器把trait编译成什么样的java对象了。编译后有两个文件(TraitBase$class.class和TraitBase.class)
先来看看TraitBase.class

/**很熟悉吧,interface,看来trait还是跟interface有共性*/
public abstract interface TraitBase
{
public abstract int add(int paramInt1, int paramInt2);
}


再看看TraitBase$class.class

/**抽象类
它内部都是static的静态方法,但是大家注意
每个方法都带有一个参数,TraitBase 对象,通过这个对象,可以访问实际对象中定义的变量和方法
*/
public abstract class TraitBase$class
{
public static int add(TraitBase $this, int x, int n)
{
return x + n;
}

public static void $init$(TraitBase $this)
{
}
}


对于继承自trait的TraitTest,反编译结果如下

/**中规中矩的接口继承*/
public class TraitTest  implements TraitBase
{
public int add(int x, int n)
{
//调用的是TraitBase$class类中的add方法,并传递了自己这个实例对象
return TraitBase.class.add(this, x, n);
}
//初始化
public TraitTest()
{
TraitBase.class.$init$(this);
}

}


属性的访问,假如有下面的Scala代码

trait TraitBase{
val content = "this is trait test"
}

class TraitTest extends TraitBase{
def Foo(): Unit ={
println(content)
}
}


反编译结果
TraitBase.class

public abstract interface TraitBase
{
/**编译器自动增加了两个接口,对content属性赋值和取值*/

//写接口,编译器自动命名,就是我们常用的stter
public abstract void scala$test$TraitBase$_setter_$content_$eq(String paramString);
//读接口,就是我们常用的getter
public abstract String content();
}


TraitBase$class.class

public abstract class TraitBase$class
{
//初始化,初始化变量
public static void $init$(TraitBase $this)
{
$this.scala$test$TraitBase$_setter_$content_$eq("this is trait test");
}
}


看来trait最终编译为interface和abstract class的两个文件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: