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的两个文件
相关文章推荐
- Setting your email in Git
- 发送邮件(E-mail)方法整理合集
- 集群单节点任务Failover
- [dubbo] dubbo No provider available for the service
- Filestream/Windows Share导致Alwayson Failover失败
- LeetCode 219:Contains Duplicate II
- 简单使用 SSKeychain 存储密码
- NSLayoutConstraint 简单理解
- hadoop jps出现process information unavailable提示解决办法
- Fzuoj 2216 The Longest Straight 【二分 || 模拟】
- Saiku去掉登录模块
- Facebook人工智能负责人Yann LeCun谈深度学习的局限性
- QDU65 again and again(字典序暴力or字典树)
- 151219DuoTaiDemo
- 趣说游戏AI开发:对状态机的褒扬和批判
- [Android Pro] 网络流量安全测试工具Nogotofail
- VT-x is not available (VERR_VMX_NO_VMX) 的解决方案
- OC对象的retainCount(引用计数器)
- VMfailVaild 错误号
- 【science封面文章】Human-level concept learning through probabilistic program induction