Scala之面向对象

一、包

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下的FruitVegetable

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"
    }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值