6.7 特质(Trait)

Scala语言中,采用特质trait(特征)来代替接口的概念,也就是说,多个类具有相同的特质(特征)时,就可以将这个特质(特征)独立出来,采用关键字trait声明。

Scala中的trait中即可以有抽象属性和方法,也可以有具体的属性和方法一个类可以混入(mixin)多个特质。这种感觉类似于Java中的抽象类。

Scala引入trait特征,第一可以替代Java的接口,第二个也是对单继承机制的一种补充。

6.7.1 特质声明

1)基本语法

trait 特质名 {

trait主体

}

2)案例实操

trait Age13 {

// 允许出现抽象的属性和方法

val age :Int

def sayHi():Unit

// 允许出现非抽象的属性

val age1:Int = 10

def sayHi1()={

println("hi ")

}

}

通过查看字节码,可以看到特质=抽象类+接口

6.7.2 特质基本语法

一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素,所以在使用时,也采用了extends关键字,如果有多个特质或存在父类,那么需要采用with关键字连接。

1)基本语法:

没有父类:class  类名 extends  特质1   with    特质2   with   特质3 …

有父类:class  类名  extends  父类   with  特质1   with   特质2  with 特质3…

2)说明

(1)类和特质的关系:使用继承的关系。

(2)当一个类去继承特质时,第一个连接词是extends,后面是with。

(3)如果一个类在同时继承特质和父类时,应当把父类写在extends后。

3)案例实操

(1)特质可以同时拥有抽象方法和具体方法

(2)一个类可以混入(mixin)多个特质

(3)所有的Java接口都可以当做Scala特质使用

(4)动态混入:可灵活的扩展类的功能

(4.1)动态混入:创建对象时混入trait,而无需使类混入该trait

(4.2)如果混入的trait中有未实现的方法,则需要实现

object Test14_TraitMixin {

def main(args: Array[String]): Unit = {

val student1 = new Student14

println(student1.name1)

println(student1.age1)

println(student1.name)

println(student1.age)

//(4)动态混入:可灵活的扩展类的功能

//(4.1)动态混入:创建对象时混入trait,而无需使类混入该trait

//(4.2)如果混入的trait中有未实现的方法,则需要实现

// 只有当前创建的一个对象具有混入的特质  类是没有的

val teacher1: Teacher14 with Age14 = new Teacher14 with Age14 {

override val name = "teacher"

override var age = 18

}

}

}

trait Age14{

val name:String

var age:Int

val name1:String = "age"

var age1:Int = 10

}

abstract class Person14{

val name:String = "person"

var age:Int = 18

val name1:String = "person1"

//  var age1:Int = 11

}

// 继承的时候 父类和特质不能有相同的具体属性  会发生冲突报错

// 报错的如果是val 常量 可以通过重写解决  如果是var 变量  只能去修改父类或者特质

// 如果继承的属性 一个是抽象的一个是非抽象的  不会发生冲突  需要注意var的属性不能重写

class Student14 extends Person14 with Age14{

override val name: String = "student"

age = 19

// 通过重写解决

override val name1: String = "student"

age1 = 18

}

//(3)所有的Java接口都可以当做Scala特质使用

class Teacher14 extends java.io.Serializable{

}

6.7.3 特质叠加

由于一个类可以混入(mixin)多个trait,且trait中可以有具体的属性和方法,若混入的特质中具有相同的方法(方法名,参数列表,返回值均相同),必然会出现继承冲突问题。冲突分为以下两种:

第一种,一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait之间没有任何关系,解决这类冲突问题,直接在类(Sub)中重写冲突方法。

第二种,一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait继承自相同的trait(TraitC),及所谓的“钻石问题”,解决这类冲突问题,Scala采用了特质叠加的策略。

所谓的特质叠加,就是将混入的多个trait中的冲突方法叠加起来,案例如下,

trait Ball {

def describe(): String = {

"ball"

}

}

trait Color extends Ball {

override def describe(): String = {

"blue-" + super.describe()

}

}

trait Category extends Ball {

override def describe(): String = {

"foot-" + super.describe()

}

}

class MyBall extends Category with Color {

override def describe(): String = {

"my ball is a " + super.describe()

}

}

object TestTrait {

def main(args: Array[String]): Unit = {

println(new MyBall().describe())

}

}

结果如下:

6.7.4 特质叠加执行顺序

思考:上述案例中的super.describe()调用的是父trait中的方法吗?

当一个类混入多个特质的时候,scala会对所有的特质及其父特质按照一定的顺序进行排序,而此案例中的super.describe()调用的实际上是排好序后的下一个特质中的describe()方法,排序规则如下:

结论:

(1)案例中的super,不是表示其父特质对象,而是表示上述叠加顺序中的下一个特质,即,MyClass中的super指代Color,Color中的super指代Category,Category中的super指代Ball。

(2)如果想要调用某个指定的混入特质中的方法,可以增加约束:super[],例如super[Category].describe()。

6.7.5 特质自身类型

1)说明

自身类型可实现依赖注入的功能。

2)案例实操

object Test16_TypeSelf {

def main(args: Array[String]): Unit = {

//    val young1: Young16 = new Young16 {

//      override val age: Int = 16

//    }

}

}

trait Age16 {

val age: Int

}

//trait Young16  extends Age16

trait Young16 {

// 特质自身类型

_: Age16 =>

}

// 特质自身类型 要求必须同时实现两个依赖的特质

class Person16 extends Young16 with Age16{

override val age: Int = 17

}

6.7.6特质和抽象类的区别

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

2.如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行(有无参构造)。

6.8 扩展

6.8.1 类型检查和转换

1)说明

(1)obj.isInstanceOf[T]:判断obj是不是T类型。

(2)obj.asInstanceOf[T]:将obj强转成T类型。

(3)classOf获取类模板。

2)案例实操

class Person{

}

object Person {

def main(args: Array[String]): Unit = {

val person = new Person

//(1)判断对象是否为某个类型的实例

val bool: Boolean = person.isInstanceOf[Person]

if ( bool ) {

//(2)将对象转换为某个类型的实例

val p1: Person = person.asInstanceOf[Person]

println(p1)

}

//(3)获取类的模板

val pClass: Class[Person] = classOf[Person]

println(pClass)

}

}

6.8.2 枚举类和应用类

1)说明

枚举类:需要继承Enumeration

应用类:需要继承App

2)案例实操

object Test {
    def main(args: Array[String]): Unit = {

println(Color.RED)
    }
}

// 枚举类
object Color extends Enumeration {
    val RED = Value(1, "red")
    val YELLOW = Value(2, "yellow")
    val BLUE = Value(3, "blue")
}

// 应用类
object Test20 extends App {
    println("xxxxxxxxxxx");
}

6.8.3 Type定义新类型

1)说明

使用type关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名

2)案例实操

object Test {

def main(args: Array[String]): Unit = {
        
        type S=String
        var v:S="abc"
        def test():S="xyz"
    }
}

scala特质 对比java的接口 使用方法相关推荐

  1. Java 9 接口私有方法

    Java 9 接口私有方法 Java 9已经发布,并且已经发生了很多变化.今天我们将研究接口中Java 9私有方法的变化. 目录[ 隐藏 ] 1接口中的Java 9私有方法 1.1 Java 7接口 ...

  2. java定义接口的方法_java定义接口的方法

    java定义接口的方法 发布时间:2020-06-28 13:50:49 来源:亿速云 阅读:103 作者:Leah 本篇文章为大家展示了java定义接口的方法,代码简明扼要并且容易理解,绝对能使你眼 ...

  3. java函数接口和方法引用

    目录 四大核心函数式接口 自定义函数式接口 方法引用 对象::实例方法 类::静态方法名字 类::实例方法名字 构造器引用 class::new 数组引用 数组::new 四大核心函数式接口 概念:有 ...

  4. [Java] Comparator接口/compare方法的介绍与使用

    上一篇文章讲了Comparable接口的使用,建议搭配食用. 背景 在实现Comparable接口的前提下,对象间已经有一套可适用的大小比较规则/排序规则了.然而某些情况下,由compareTo定义的 ...

  5. 调用接口的方法 java_java调用接口的方法

    java调用接口的方法 发布时间:2020-06-24 10:42:58 来源:亿速云 阅读:85 作者:Leah 这期内容当中的小编将会给大家带来有关java调用接口的方法,以专业的角度为大家分析和 ...

  6. java deque,Java Deque接口

    本文概述 Java Deque接口是一个线性集合, 支持两端的元素插入和删除. Deque是"双头队列"的首字母缩写. 和接口声明 public interface Deque e ...

  7. 大数据入门:Java和Scala编程对比

    在学习大数据之初,很多人都会对编程语言的学习有疑问,比如说大数据编程主要用什么语言,在实际运用当中,大数据主流编程是Java,但是涉及到Spark.Kafka框架,还需要懂Scala.今天的大数据入门 ...

  8. java list接口为何要重新声明collection接口的方法_JAVA Collection接口中List Map 和Set的区别(转)...

    Java中的集合包括三大类,它们是Set(集).List(列表)和Map(映射),它们都处于java.util包中,Set.List和Map都是接口,它们有各自的实现类.Set的实现类主要有HashS ...

  9. java private 接口_java接口中 定义 private 私有方法

    在传统的Java编程中,被广为人知的一个知识点是:java Interface接口中不能定义private私有方法.只允许我们定义public访问权限的方法.抽象方法或静态方法.但是从Java 9 开 ...

最新文章

  1. HTML-加速、再加速
  2. 当我们拿到数据进行建模时,如何选择更合适的算法?
  3. php linux fork进程 多个进程/线程共享一个 socket连接 出现多个进程响应串联
  4. if __name__ == __main___终于搞懂了Python脚本里的if __name__ == #39;__main__#39;
  5. 大牛深入讲解!最经典的HashMap图文详解
  6. 理解Android Binder机制原理
  7. Linux rsyslog 转存至日志服务器
  8. 苹果无人车四个最新专利:手势控制变道、车辆导流、路况感知及车辆控制
  9. bitcoin: 何为燃烧地址
  10. HDU 2389(HK 最大二分匹配)
  11. mac 修改hosts的2种方案
  12. rails kaminari bootstrap-kaminari-views certified
  13. SwiftUI - 常用控件:Slider、Stepper、Picker、Toggle、Form、LoadingView、Gradient、AnyView
  14. 如何使虚拟机VMware workstation连接局域网
  15. Linux入坑手册(鸟哥的私房菜)
  16. WeChat微信商户号JSAPI支付 支付授权目录无法添加:添加完成后不刷新再添加一遍
  17. mysql 锁(三)
  18. Microsoft Office 历史版本
  19. HDU5015 233 Matrix
  20. Lucene 7.5.0 索引文件之liv

热门文章

  1. ACwing166数独与183靶形数独
  2. mybatis表不存在的解决办法
  3. 戴尔游匣G15 系统蓝屏问题解决的方法
  4. unity3d的Animation 动画播放器的基本API
  5. 优秀,起诉网站,可尼玛太秀了
  6. java请输入第一个人,Java-每日编程练习题③
  7. iOS开发-XIB、Storyboard操作小技巧
  8. sybase datediff mysql_Sybase中的日期时间函数_龙的天空
  9. AI“网红”科大讯飞的闹心半年报,员工竟成吃掉利润的背锅侠?
  10. 投之家与妙优车达成战略合作,加强推进优质资产端建设