一、包
1.1 Scala包
1.1.1 基本语法
package 包名.类名
1.1.2 Scala包的作用(和Java一样)
- 区分相同名字的类
- 当类很多时候,可以很好的管理类
- 控制访问范围
1.2 包的命名
- 命名规则
- 只能包含数字、字母、下划线、小圆点.,但不能用数字开头,也不要使用关键字
- 例如
demo.class.exec1 //错误,因为 class 关键字
demo.12a //错误,数字开头
- 命名规范:一般都是小写字母+"."
- 例如
tiger.scala.test.model
1.3 包说明
1.3.1 Scala包的管理风格
- 和Java的包管理风格相同,每个源文件一个包(包名和源文件所在路径不要求必须一致),包名用“.”进行分隔以表示包的层级关系
- 例如
tiger.scala.test.model
- 通过嵌套的风格表示层级关系
- 特点
- 一个源文件中可以声明多个package
- 子包中的类可以直接访问父包中的内容,而无需导包
- 特点
- 例如
package aaa{
package ccc{
package ddd {
object Test003 {
def main(args: Array[String]): Unit = {
}
}
}
}
}
- 特点示例
package com {
import com.atguigu.Inner //父包访问子包需要导包
object Outer {
val out: String = "out"
def main(args: Array[String]): Unit = {
println(Inner.in)
}
}
package atguigu {
object Inner {
val in: String = "in"
def main(args: Array[String]): Unit = {
println(Outer.out) //子包访问父包无需导包
}
}
}
}
package other {
}
1.4 包对象
1.4.1 定义
- 在Scala中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有class和object的共享变量,可以被直接访问。
- 例如
package aaa{
package ccc{
package bbb {
object Test03 {
def main(args: Array[String]): Unit = {
}
}
}
}
}
package aaa{
package ccc{
package ddd {
object Test003 {
def main(args: Array[String]): Unit = {
}
}
}
}
}
package object aaa {
var ss:String = "hahha"
def nmm(): Unit ={
println("hhhhh")
}
}
1.4.2 说明
- 若使用Java的包管理风格,则包对象一般定义在其对应包下的package.scala文件中,包对象名与包名保持一致。
- 如果采用嵌套方式管理包,则包对象可与包定义在同一文件中,但是要保证包对象与包声明在同一作用域中。
1.5 导包说明
- 和Java一样,可以在顶部使用import导入,在这个文件中的所有类都可以使用。
- 局部导入:什么时候使用什么时候导入,在其作用范围内都可以使用
- 通配符导入:_
import java.util._
- 给类起名:
import java.util.{ArrayList=>JL}
- 屏蔽类:
import java.util.{ArrayList =>_,_}
- 导入相同包的多个类:
import java.util.{HashSet, ArrayList}
- 导入包的绝对路径:
new _root_.java.util.HashMap
- 说明:
import com.atguigu.Fruit | 引入com.atguigu包下Fruit(class和object) |
import com.atguigu._ | 引入com.atguigu下的所有成员 |
import com.atguigu.Fruit._ | 引入Fruit(object)的所有成员 |
import com.atguigu.{Fruit,Vegetable} | 引入com.atguigu下的Fruit和Vegetable |
import com.atguigu.{Fruit=>Shuiguo} | 引入com.atguigu包下的Fruit并更名为Shuiguo |
import com.atguigu.{Fruit=>Shuiguo,_} | 引入com.atguigu包下的所有成员,并将Fruit更名为Shuiguo |
import com.atguigu.{Fruit=>_,_} | 引入com.atguigu包下屏蔽Fruit类 |
new _root_.java.util.HashMap | 引入的Java的绝对路径 |
- 注意:Scala中的三个默认导入分别是
import java.lang._
import scala._
import scala.Predef._
1.6 访问权限
1.6.1 说明
- Scala 中属性和方法的默认访问权限为public,但Scala中无public关键字。
- private为私有权限,只在类的内部和伴生对象中可用。
- protected为受保护权限,Scala中受保护权限比Java中更严格,同类、子类可以访问,同包无法访问。
- private[包名]增加包访问权限,包名下的其他类也可以使用
1.6.2 案例
package com.atguigu.scala.test
class Person {
private var name: String = "bobo"
protected var age: Int = 18
private[test] var sex: String = "男"
def say(): Unit = {
println(name)
}
}
object Person {
def main(args: Array[String]): Unit = {
val person = new Person
person.say()
println(person.name)
println(person.age)
}
}
class Teacher extends Person {
def test(): Unit = {
this.age
this.sex
}
}
class Animal {
def test: Unit = {
new Person().sex
}
}
二、类和对象
- 类:可以看成一个模版
- 对象:表示具体的事物
2.1 定义类
2.1.1 基本语法
[修饰符] class 类名 {
类体
}
- 说明
- Scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public)
- 一个Scala源文件可以包含多个类
2.1.2 案例
package com.atguigu.chapter06
//(1)Scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public)
class Person {
}
//(2)一个Scala源文件可以包含多个类
class Teacher{
}
2.2 属性
- 属性是类的一个组成部分
2.2.1 基本语法
[修饰符] var|val 属性名称 [:类型] = 属性值
2.2.2 案例
package tiger.scala.chapter06
import scala.beans.BeanProperty
/*
* 类中属性:
*
* */
object Scala05_TestField {
def main(args: Array[String]): Unit = {
val std:Student05 = new Student05()
// 通过对象.的方式访问属性
// std.name = "jingjing"
// println(std.name)
println(std.sex)
}
}
class Student05{
// 在Scala语言中,属性、方法、类默认修饰是public,但是public不能显式加,类似于java中的default
// 底层生成的字节码文件默认对属性用private进行修饰,提供了公开的获取属性值,以及设置属性值的方法
// 作用1:符合面向对象的封装特性
private var name:String = "zhangsan" // 加上private底层在get/set方法前面也加上了private
// 如果要想生成符合JavaBean规范的get/set方法,需要在属性上加上一个注解@BeanProperty
// 作用2:对一些框架进行支持
@BeanProperty
var age:Int = 18
// 如果想给属性赋默认值,需要在声明的时候,赋_,val修饰的属性不能赋默认值
var sex:String = _
}
2.3 方法
2.3.1 基本语法
def 方法名(参数列表) [:返回值类型] = {
方法体
}
2.3.2 案例
class Person {
def sum(n1:Int, n2:Int) : Int = {
n1 + n2
}
}
object Person {
def main(args: Array[String]): Unit = {
val person = new Person()
println(person.sum(10, 20))
}
}
2.4 创建对象
2.4.1 基本语法
val | var 对象名 [:类型] = new 类型()
2.4.2 案例
- val修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。
- var修饰对象,可以修改对象的引用和修改对象的属性值
- 自动推导变量类型不能多态,所以多态需要显示声明
class Person {
var name: String = "canglaoshi"
}
object Person {
def main(args: Array[String]): Unit = {
//val修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。
val person = new Person()
person.name = "bobo"
// person = new Person()// 错误的
println(person.name)
}
}
2.5 构造器
- Scala构造对象也需要调用构造方法,并且可以有任意多个构造方法。Scala类的构造器包括:主构造器和辅助构造器
2.5.1 基本语法
class 类名(形参列表) { // 主构造器
// 类体
def this(形参列表) { // 辅助构造器
}
def this(形参列表) { //辅助构造器可以有多个...
}
}
- 说明
- 辅助构造器,函数的名称this,可以有多个,编译器通过参数的个数及类型来区分
- 辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。
- 构造器调用其他另外的构造器,要求被调用构造器必须提前声明。
2.5.2 案例
- 如果主构造器无参数,小括号可省略,构建对象时调用的构造方法的小括号也可以省略。
package tiger.scala.chapter06
/*
* 构造器(构造方法)
* 创建对象
* 初始化属性(给对象属性赋值)
* Scala中的构造方法
* 主构造方法
* 在声明类的同时,定义了主构造方法
* 在一个类中主构造方法只能有一个
* 辅助构造方法
* 方法名必须叫this
* 在辅助构造方法的开始必须直接或者间接的调用主构造方法
* 辅助构造方法可以重载
* */
object Scala08_TestConstructor {
def main(args: Array[String]): Unit = {
val std:Student08 = new Student08
val std2:Student08 = new Student08("jingjing")
val std3:Student08 = new Student08("jingjing", 18)
}
}
class Student08 {
println("Student08的主构造方法被调用了")
var name:String = _
var age:Int = _
// 声明辅助构造方法
def this(name:String) {
// 调用主构造方法
this()
println("1-----------Student08的辅助构造方法1被调用了")
}
def this(name:String,age:Int) {
// 间接调用主构造方法
this(name)
println("2-----------Student08的辅助构造方法被调用了")
this.age = age
}
// 以下写法不是构造方法
// def student08() = {
// println("Student08的构造方法被调用了")
// }
}
2.6 构造器参数
2.6.1 说明
- Scala类的主构造器的形参包括三种类型:未用任何修饰、var修饰、val修饰
- 未用任何修饰符修饰,这个参数就是一个局部变量
- var修饰参数,作为类的成员属性使用,可以修改
- val修饰参数,作为类只读属性使用,不能修改
2.6.2 案例
package tiger.scala.chapter06
/*
* 构造方法的参数
*
* */
object Scala09_TestConstructor {
def main(args: Array[String]): Unit = {
// new Student09
val std = new Student09("jingjing", 17)
println(std.name)
}
}
// 只提供无参主构造,单独定义
// 在Scala语言中,以下写法比较少见
//class Student09(nameParam:String, ageParam:Int) {
// var name:String = nameParam
// var age:Int = ageParam
//}
// 在声明主构造方法参数的时候,如果参数前面什么也不加,那么参数就作为当前类的局部变量来使用,不能作为类的属性被访问
// 如果需要将参数作为属性被访问的话,那么在参数声明前加上var或val关键字
//class Student09(var name:String, var age:Int) {
// def m1(): Unit = {
//
// }
//}
// 同时提供主、辅助构造方法
class Student09 {
var name:String = _
var age:Int = _
def this(name:String, age:Int) {
this()
this.name = name
this.age = age
}
}
三、封装
- Scala中的public属性,底层实际为private,并通过get方法(obj.field())和set方法(obj.field_=(value))对其进行操作。所以Scala并不推荐将属性设为private,再为其设置public的get和set方法的做法。但由于很多Java框架都利用反射调用getXXX和setXXX方法,有时候为了和这些框架兼容,也会为Scala的属性设置getXXX和setXXX方法(通过@BeanProperty注解实现)。
- 案例
四、继承
4.1 基本语法
class 子类名 extends 父类名 { 类体 }
- 子类继承父类的方法和属性
- scala是单继承
4.2 案例
- 继承的调用顺序:父类构造器->子类构造器
package tiger.scala.chapter06
/*
* 存在的继承关系子类对象的创建过程
*
* */
object Scala10_TestExtends {
def main(args: Array[String]): Unit = {
// 自动类型推导,不能推导出多态
// val std:Person10 = new Student10() // 1,3
val std1:Person10 = new Student10("jingjing", 15, "000001") // 134
}
}
class Person10{
println("1-父类的主构造方法被调用了")
var name:String = _
var age:Int = _
def this(name:String, age:Int) {
this()
println("2-父类的辅助构造方法被调用了")
this.name = name
this.age = age
}
}
class Student10(name:String, age:Int) extends Person10(name, age) {
println("3-子类的主构造方法被调用了")
var stdNo:String = _
def this(name:String, age:Int, stdNo:String) {
this(name, age)
println("4-子类的辅助构造方法被调用了")
this.stdNo = stdNo
}
}
五、抽象属性和抽象方法
5.1 抽象属性和抽象方法
5.1.1 基本语法
- 定义抽象类
abstract class Person{} //通过abstract关键字标记抽象类
- 定义抽象属性
val|var name:String //一个属性没有初始化,就是抽象属性
- 定义抽象方法
def hello():String //只声明而没有实现的方法,就是抽象方法
5.1.2 案例
- 案例一
package tiger.scala.chapter06
/*
* 抽象:
* 模糊、不具体
* 使用abstract关键字定义抽象类
* 抽象类一般和抽象属性和抽象方法配合使用
* 抽象属性
* 属性只有声明,但是没有赋值
*
* 抽象方法
* 方法只有声明,没有实现
*
* 在一个类中,如果存在抽象属性或者抽象方法,那么这个类一定是抽象类
* 如果一个类是抽象类,那么它不一定包含抽象属性和抽象方法
* 如果一个类中存在抽象属性或抽象方法,那么具体的是想应该交给子类完成
* 如果子类也实现不了抽象类,那么子类也应该声明为抽象类
*
*
* */
object Scala11_TestAbstract {
}
// 愚公移山
abstract class YG {
// 移山
def move():Unit
}
class YGSon extends YG {
override def move(): Unit = {
println("使用锤子凿山")
}
}
abstract class YGDau extends YG {
override def move(): Unit
}
class YGWS extends YGDau {
override def move(): Unit = {
println("蓝翔~~~")
}
}
- 案例二
package tiger.scala.chapter06
object Scala12_TestAbstract {
}
abstract class Person12 {
// 非抽象属性
val name:String = "zhangsan"
// 抽象属性
var age:Int
// 非抽象方法
def eat(): Unit = {
println("Person's eat")
}
// 抽象方法
def sleep(): Unit
}
class Student12 extends Person12{
// 在scala语言中,重写除了方法之外,还要属性的重写
// 在子类中,如果重写的是抽象属性和方法,那么override关键字可以省略
var age: Int = 18
override def sleep(): Unit = {
println("hhhh sleep")
}
// 对父类的非抽象方法进行重写
// override关键字不能省略,必须得加
override def eat(): Unit = {
// 可以通过super关键字,调用父类的方法
super.eat()
// 但是不能使用super关键字访问父类的属性
// println(super.name) 错误
println("Student's eat")
}
// 在子类中,对父类的非抽象属性进行重写
// 父类声明了抽象属性,子类对属性进行实现
// 如果子类需要对父类属性进行重写,属性只能是val修饰
// 父类声明了非抽象属性,子类对属性进行重写
override val name = "jingjing"
}
- 案例三
package tiger.scala.chapter06
object Scala13_TestDynamic {
def main(args: Array[String]): Unit = {
// 不存在多态
// val tt:Teacher13 = new Teacher13
// println(tt.name)
// tt.hello()
// 存在多态
// 在Scala语言中,不管是属性还是方法,都是动态绑定
val tt:Person13 = new Teacher13
println(tt.name) // teacher
tt.hello() // hello teacher
// 定义一个方法对Person进行处理
def m1(): Person13 = {
tt
}
}
}
class Person13 {
val name:String = "person"
def hello(): Unit ={
println("Hello person")
}
}
class Teacher13 extends Person13 {
override val name: String = "teacher"
override def hello(): Unit = {
println("hello teacher")
}
}
5.2 匿名子类
- 和Java一样,可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类。
- 案例
package tiger.scala.chapter06
/*
* 匿名子类
* */
abstract class Person14 {
var name:String
var m1:Unit
}
object Scala14_TestNon {
def main(args: Array[String]): Unit = {
// 抽象类不能被示例化,可以通过匿名子类的方式创建对象
val per:Person14 = new Person14 {
override var name: String = "hhhhh"
override var m1: Unit = {
println("hello")
}
}
println(per.name)
per.m1
}
}
六、单例对象(伴生对象)
- Scala语言是完全面向对象语言,所以并没有静态操作(即在Scala中没有静态的概念)。但是为了能够和Java语言交互(因为Java中有静态概念),就产生了一种特殊的对象来模拟类对象,该对象为单例对象。若单例对象名与类名一致,则称该单例对象这个类的伴生对象,这个类的所有“静态”内容都可以放置在它的伴生对象中声明。
6.1 单例对象的基本语法
object Person{
val country:String="China"
}
- 说明
- 单例对象采用object关键字声明
- 单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。
- 单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。
6.2 案例
//(1)伴生对象采用object关键字声明
object Person {
var country: String = "China"
}
//(2)伴生对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致。
class Person {
var name: String = "bobo"
}
object Test {
def main(args: Array[String]): Unit = {
//(3)伴生对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。
println(Person.country)
}
}
6.3 apply方法
6.3.1 说明
- 通过伴生对象的apply方法,实现不使用new方法创建对象。
- 如果想让主构造器变成私有的,可以在()之前加上private。
- apply方法可以重载。
- Scala中obj(arg)的语句实际是在调用该对象的apply方法,即obj.apply(arg)。用以统一面向对象编程和函数式编程的风格。
- 当使用new关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构建对象时,调用的其实时伴生对象的apply方法。
6.3.2 案例
object Scala15_CreateObject {
def main(args: Array[String]): Unit = {
// 通过构造方法来创建对象
// 通过new的方式,底层调用的是构造方法创建对象
// val std1:Student15 = new Student15()
// println(std1)
// val std2:Student15 = new Student15("jingjing", 18)
// println(std2)
// 底层调用的是apply方法
var std:Student15 = Student15("zs", 20)
println(std.name)
println(Student15())
}
}
object Student15 {
// 无参apply方法创建对象
// def apply: Student15 = new Student15
// 注意:apply方法并不一定创建的是当前类型对象,也可以创建其他类型对象,但是很少见
def apply(): String = new String("abc")
// apply方法可以重载
def apply(name: String, age: Int): Student15 = new Student15(name, age)
}
// 加上private代表主构造方法私有化
class Student15 private() {
var name:String = _
var age:Int = _
// 辅助构造方法私有化
private def this(name:String, age:Int) {
this()
this.name = name
this.age = age
}
override def toString = s"Student15($name, $age)"
}
6.3.3 单例设计模式
package tiger.scala.chapter06
/*
* 单例设计模式
* 懒汉式
* 饿汉式
* 构造方法私有化
* 提供私有静态属性,接收单例模式
* 公共的,静态的getInstance方法
*
* */
object Scala16_TestSingleton {
def main(args: Array[String]): Unit = {
val std1:Student16 = Student16.getInstance()
println(std1)
val std2:Student16 = Student16.getInstance()
println(std2)
}
}
懒汉式
//object Student16 {
// private var s:Student16 = null
// def getInstance():Student16 = {
// if (s == null) {
// s = new Student16
// }
// s
// }
//}
// 恶汉式
object Student16 {
private var s:Student16 = new Student16
def getInstance():Student16 = {
s
}
}
// 主构造方法私有化
class Student16 private() {
}
七、特质
- Scala语言中,采用特质trait(特征)来代替接口的概念,也就是说,多个类具有相同的特质(特征)时,就可以将这个特质(特征)独立出来,采用关键字trait声明。
- Scala中的trait中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可以混入(mixin)多个特质。这种感觉类似于Java中的抽象类。
- Scala引入trait特征,第一可以替代Java的接口,第二个也是对单继承机制的一种补充。
7.1 特质声明
7.1.1 基本语法
trait 特质名 {
trait主体
}
7.1.2 案例
package tiger.scala.chapter06
/*
* 特质的声明以及混入特质
*
* */
object Scala17_TestTrait {
def main(args: Array[String]): Unit = {
var a:PersonTraint17 = new MyClass17
println(a.name)
a.eat()
}
}
// 特质声明
trait PersonTraint17 {
// 抽象属性
var name:String
// 抽象方法
def eat(): Unit
// 非抽象属性
var age:Int = 10
// 非抽象方法
def sleep():Unit = {
println("Person's sleep")
}
}
// 混入特质
class MyClass17 extends PersonTraint17 {
override var name: String = "hhhhh"
override def eat(): Unit = {
println("mc eat")
}
}
7.2 特质基本语法
-
一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素,所以在使用时,也采用了extends关键字,如果有多个特质或存在父类,那么需要采用with关键字连接。
- 说明
- 类和特质的关系:使用继承的关系。
- 当一个类去继承特质时,第一个连接词是extends,后面是with。
- 如果一个类在同时继承特质和父类时,应当把父类写在extends后。
- 特质可以同时拥有抽象方法和具体方法
- 一个类可以混入(mixin)多个特质
- 所有的Java接口都可以当做Scala特质使用
- 动态混入:可灵活的扩展类的功能
- 动态混入:创建对象时混入trait,而无需使类混入该trait
- 如果混入的trait中有未实现的方法,则需要实现
7.2.1 基本语法
- 有无父类的继承关系
package tiger.scala.chapter06
/*
* 类和特质
*
* */
object Scala18_TestTrait {
def main(args: Array[String]): Unit = {
var std1:MyStudent18 = new MyStudent18
std1.run()
std1.speak()
// 特质的动态混入,在创建对象的时候,为该对象单独的混入某个特质
val std2:MyStudent18 with TraitBuyJP with TraitRap= new MyStudent18 with TraitBuyJP with TraitRap {
override def buy(): Unit = {
println("buy baojianping")
}
override def rap(): Unit = {
println("吃完保健品来rap")
}
}
std2.buy()
std2.rap()
}
}
trait TraitA {
def run():Unit
}
trait TraitB{
def speak():Unit
}
trait TraitBuyJP{
def buy():Unit
}
trait TraitRap {
def rap():Unit
}
class Super18{
}
// 如果不存在继承关系,混入多个特质
//class MyClass18 extends TraitA with TraitB {
// override def run(): Unit = ???
//
// override def speak(): Unit = ???
//}
// 如果存在继承关系,同时混入特质
class MyStudent18 extends Super18 with TraitA with TraitB {
override def run(): Unit = {
println("jingjing run")
}
override def speak(): Unit = {
println("jingjing speak")
}
}
- 特质冲突
package tiger.scala.chapter06
/*
* 普通的特质冲突
* 一个类混入多个特质,多个特质之间有相同的抽象方法,特质之间没有关系,直接对相同的方法实现一次即可
* 一个类混入多个特质,多个特质之间有相同的非抽象方法,特质之间没有关系,如果在类中不做处理会报错,特质冲突,应该对相同的非抽象方法进行重写
* */
object Scala19_TestTrait {
def main(args: Array[String]): Unit = {
val mc = new MyClass19
mc.m1()
}
}
trait TraitA1 {
def m1():Unit = {
println("TraitA1 m1")
}
}
trait TraitB1 {
def m1():Unit = {
println("TraitB1 m1")
}
}
class MyClass19 extends TraitA1 with TraitB1 {
override def m1(): Unit = {
println("m1实现")
}
}
- 依赖注入
package tiger.scala.chapter06
/*
* 特质自身类型
* 实现了依赖注入的功能
* 要求混入该特质的同时,要混入特质自身类型
*
* DI依赖注入:
* IOC 控制反转
*
*
* */
object Scala21_TestTrait {
}
class User(var name:String, var age:Int)
trait TraitA3 {
def m1(): Unit = {
println("m1")
}
}
// CUDR
trait UserDao {
// 要求混入该特质的同时,要混入特质自身类型
_:TraitA3 =>
// 向数据库用户表中插入数据
def insert(user:User): Unit = {
println("insert into datab" + user.name)
}
}
// 所有的java接口都可以当作特质被混入
class UserControllor extends UserDao with TraitA3 with Serializable {
// 实现依赖注入功能
// _:UserDao =>
// 可以注入多个
_:UserDao with Exception =>
def regist(user:User):Unit = {
insert(user)
}
}
- 动态混入
package tiger.scala.chapter06
/*
* 类和特质
*
* */
object Scala18_TestTrait {
def main(args: Array[String]): Unit = {
var std1:MyStudent18 = new MyStudent18
std1.run()
std1.speak()
// 特质的动态混入,在创建对象的时候,为该对象单独的混入某个特质
val std2:MyStudent18 with TraitBuyJP with TraitRap= new MyStudent18 with TraitBuyJP with TraitRap {
override def buy(): Unit = {
println("buy baojianping")
}
override def rap(): Unit = {
println("吃完保健品来rap")
}
}
std2.buy()
std2.rap()
}
}
trait TraitA {
def run():Unit
}
trait TraitB{
def speak():Unit
}
trait TraitBuyJP{
def buy():Unit
}
trait TraitRap {
def rap():Unit
}
class Super18{
}
// 如果不存在继承关系,混入多个特质
//class MyClass18 extends TraitA with TraitB {
// override def run(): Unit = ???
//
// override def speak(): Unit = ???
//}
// 如果存在继承关系,同时混入特质
class MyStudent18 extends Super18 with TraitA with TraitB {
override def run(): Unit = {
println("jingjing run")
}
override def speak(): Unit = {
println("jingjing speak")
}
}
7.3 特质叠加
7.3.1 特质叠加顺序
- 列出第一个混入特质的继承关系,作为临时叠加的顺序
- 列出第二个混入特质的继承关系,并且该顺序放到临时叠加顺序的前面,已经出现的特质不在出现
- 将子类放到临时叠加顺序的第一个
7.3.2 案例
package tiger.scala.chapter06
/*
* 特质叠加:解决特质冲突(钻石问题)
*
* */
object Scala20_TestTrait {
def main(args: Array[String]): Unit = {
val operation = new MyOperation
println(operation.describe())
}
}
trait Operation {
def describe(): String = {
"插入数据"
}
}
trait DBOperation extends Operation {
override def describe(): String = {
"向MySQL数据库中" + super.describe()
}
}
trait HDFSOperation extends Operation {
override def describe(): String = {
"向HDFS数据库中" + super.describe()
}
}
class MyOperation extends DBOperation with HDFSOperation {
override def describe(): String = {
"我的操作是-->" + super.describe()
}
}
7.4 特质和抽象类的区别
package tiger.scala.chapter06
/*
* 抽象类和特质关系
* 抽象类中可以定义抽象属性、抽象方法、非抽象属性、非抽象方法
* 特质中可以定义抽象属性、抽象方法、非抽象属性、非抽象方法
* 特质和抽象类都不能被实例化
* 抽象类有构造方法
* 特质也有构造方法
* 如果需要给构造方法传递阐述的话,使用抽象类,因为特质不支持带参的构造
* 优先选择特质,Scala是单继承,如果直接继承不方便后续扩展
* 对大量对象共性进行抽象--->类--->对大量类共性进行抽象-->抽象类
* 一般子类和父类之间应该满足is a的原则
*
* 特质一般是对行为进行抽象,定义规范
*
* */
object Scala22_TestTraitAndAbstract {
def main(args: Array[String]): Unit = {
new MyClass22
}
}
trait Trait22 {
println("特质的构造方法")
def m1():Unit
}
abstract class MyAbstract22 {
println("抽象类的构造方法")
def m1():Unit
}
class MyClass22 extends MyAbstract22 with Trait22 {
println("myclass的构造方法")
override def m1(): Unit = {
println("myclass")
}
}
八、拓展
8.1 类型检查和转换
8.1.1 说明
- obj.isInstanceOf[T]:判断obj是不是T类型。
- obj.asInstanceOf[T]:将obj强转成T类型。
- classOf获取对象的类名。
8.1.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)
}
}
8.2 枚举类和应用类
8.2.1 说明
- 枚举类:需要继承Enumeration
- 应用类:需要继承App,相当于java中的测试,不用创建main方法就可以运行
8.2.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");
}
8.3 Type定义新类型
- 使用type关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名。
- 案例
object Test {
def main(args: Array[String]): Unit = {
type S=String
var v:S="abc"
def test():S="xyz"
}
}