Scala--OOP高级特性

类Class

1.特点

  1. 类通过class关键字定义
  2. 类通过new关键字创建实例
  3. 类拥有 成为变量和办法
  4. 类的成员默认为public,也支持private、protected </font color>
  5. 类中无法定义静态成员变量和方法
  6. 类无需明确定义构造方法,通过构造参数列表声明为类的一部分

2. 权限修饰符

在这里插入图片描述

3. 类的定义

① 构造器:主构造器
② 辅助构造器:关键字this()
③ 定义成员变量与方法
④ 类的实例化
代码例子:

//主构造器执行类定义中的所有语句
class ClassTest(n:Int,m:Int) {
  var x:Int = n   //成员变量
  var y:Int = m
  //辅助构造器
  def this()= {
    this(0,0)     //第一句必须调用其他构造器
  }
  //成员方法
  def move(a:Int,b:Int): Unit ={
    x = a + x
    y = b + y
    println(x,y)
  }


}
object Test{
  def main(args: Array[String]): Unit = {
    var p = new ClassTest();
    p.x
    p.y
    p = new ClassTest(12,11)
    p.x
    p.y
    p.move(1,2)
  }
}

输出:
在这里插入图片描述

4.类的继承

特点:
1、Scala使用”extends“关键字实现继承
2、子类重写父类方法必须使用”override"关键字

abstract class Father {
  def seekBook()={
    println("father look")
  }
}
class Son extends Father {
  override def seekBook(): Unit = {
    super.seekBook()
    println("son book")
  }
}
object Test1{
  def main(args: Array[String]): Unit = {
    var son = new Son
    son.seekBook();
  }
}

输出:
在这里插入图片描述

5、抽象类

① 抽象类可包含未实现的方法,即抽象方法
② 抽象类无法实例化
③ 抽象类使用abstract关键字修饰
注:

  • 子类重写父类抽象方法时,override 关键字可选
  • 子类重写父类非抽象方法,override关键字必写
    例子同上

6、单例对象(object)

Scala使用单例对象来定义静态成员变量、成员方法和静态代码块:
① 使用object 关键字声明,可包含变量、方法与代码定义
② 单例对象中的成员变量、成员方法通过单例对象名直接调用
③ 单例对象第一次访问时初始化,并执行全部代码块
④ 单例对象不能new,且无构造参数
⑤ 程序入口main() 方法必须定义在单例对象中
⑥ 单例对象与同名类定义统一文件中时形成绑定关系

问题:scala的object和class有什么差异?
object为单例对象,里面的变量是静态变量,方法为静态方法
当同名class、object一起出现时,可以通过apply关键词来实现伴生对象和伴生类
效果

//定义单例对象
object Blah {
  println("Blah initializing...")
  def sum(I:List[Int]):Int=I.sum

  def main(args: Array[String]): Unit = {
    println(Blah.sum(List(1,2,3)))
  }
}

结果:
在这里插入图片描述

7.伴生(Companion):伴生对象和伴生类

  1. 单例对象与同名类定义在同一文件中时形成绑定关系
    ① 同名类称为单例对象的伴生类(class)
    ② 单例对象称为同名类伴生对象(object)
  2. 伴生类与伴生对象可互相访问个自私有成员
  3. 伴生对象可为伴生类增加静态成员
    例子:
//需求
//假设类Book有属性title和author(多个),books是Book的列表
//实现Book类,同时使用主构造器与辅助构造器
//实现Book的伴生对象,使用伴生对象创建Book实例
//创建books,使用List[Book]初始化5个以上Book实例
//找出books中书名包含“xxx”的书,并打印书名
//找出books中作者名以“xxx”打头的书,并打印书名
class Book(title:String,author:String) {
  var bookname = title;
  var auth = author;
  def this() {
    this("JAVA编程思想","Bruce Eckel ")
  }
}
object Book{
  def apply(title: String, author: String): Book = new Book(title, author)
  def apply(): Book = new Book()
  def main(args: Array[String]): Unit = {
    var books:List[Book] = List(
      Book("hadoop","zs"),Book("hive","sj"),Book("hbase","sxd"),
      Book("scala","wgr"),Book("spark","some")
    )
    var book = Book()
    println(book.bookname + ":"+ book.auth)
    books.takeWhile(p=>p.bookname.contains("h")).foreach(f=>println(f.bookname))
    books.filterNot(p=>p.auth.contains("a")).foreach(f=>println(f.auth))
  }
}

输出:
在这里插入图片描述

8.特质(trait)

① 特点:

  1. Scala中没有接口(interface)的概念
  2. 特质用于在类之间共享程序接口的字段,类似Java接口
  3. 特质是字段和方法的集合,可以提供字段和方法实现
  4. 类和单例对象都可以扩展特质(extends
  5. 特质不能被实例化,因此没有构造参数,类似Java接口
  6. 特质使用trait关键字定义
  7. 实现特质中的方法使用overrride关键字

1、scala的Trait和java的接口有什么不同?
Trait类似于接口,使用关键字Trait,但是可以实现方法,可以被继承,可以继承一个类,方法不需要全部被重写,接口不会有构造器,Trait有构造器
例子:

//多根继承
abstract class A {
  def eat():Unit
}
class B extends A{
  override def eat(): Unit = {
    println("B吃饭")
  }

}
trait C extends A{
  def sleep: Unit={
    println("C睡觉")
  }
  override def eat(): Unit = {
    println("C吃饭")
  }
}
class D extends B with C{}
object K{
  def main(args: Array[String]): Unit = {
    val d = new D()
    d.sleep
    d.eat()
  }
}

输出:在这里插入图片描述

9. 混入特质(mixin)

① 当某个特质用于组合类时,被称为混入
② 一个类只能由一个父类但是可以由多个混入(分别使用关键字extends和with)
实例代码同上

① 动态混入特质示例

//动态混合特质
class MyTrait {
 self:Eat=>
  def show() = {
    myeat()
  }
}
trait Eat{
  def myeat():Unit
}

trait Person extends Eat{
  override def myeat(): Unit = {
    println("Person eat")
  }
}

trait Pig extends Eat{
  override def myeat(): Unit = {
    println("pig eat")
  }
}
object MyTest{
  def main(args: Array[String]): Unit = {
    (new MyTrait() with Pig).show()
    (new MyTrait() with Person).show()
  }
}

输出:
在这里插入图片描述

② 特质和抽象类的选择

① 优先使用特质

  • 抽象类只能继承一次
  • 特质可以混入多次

② 需要使用带参构造方法时,使用抽象类
③ 与Java互操作性

  • 抽象类与Java完全可互操作
  • 特质只有在不包含任何实现代码时才可互 操作

示例:

需求说明: 现在Book拥有电子版本,可以在多终端上播放
定义Ebook特质,包含play()方法
使Book混入Ebook特质,实现play()方法

class MyBook1(title:String,author:String) {
  self:EBook=>
  var bookName = title
  var auth = author
  def clientP ()={
    println("《"+bookName+"》-"+auth+":\t"+play())
  }
}
trait EBook{
  def play():String
}

trait PC extends EBook{
  override def play(): String = {
    "PC player"
  }
}

trait Mobile extends EBook{
  override def play(): String = {
    "Mobile player"
  }
}

object Test {
  def main(args: Array[String]): Unit = {
    (new MyBook1("流浪地球","刘慈欣") with PC).clientP()
    (new MyBook1("三国演义","罗贯中") with Mobile).clientP()
  }
}

输出结果:
在这里插入图片描述

10. 内部类

特点:

① 一个类可以作为另一个类的成员,称为内部类
② Java内部类是外部类的成员
③ 在Scala中,默认情况下内部类实例和外部对象关联
④ 内部类如果想要访问外部类的属性,可以通过外部类对象访问。即:

  • 访问方式1:外部类名.this.属性名
  • 访问方式2:外部类名别名.属性名
//外部类
class ScalaOuterClass {
  class ScalaInnerClass{}//成员内部类
}
object ScalaOuterClass{
  class ScalaStaticInnerClass{}//静态内部类
}

object  Test{
  def main(args: Array[String]): Unit = {
    //创建外部类实例
    val outer1:ScalaOuterClass = new ScalaOuterClass
    val outer2:ScalaOuterClass = new ScalaOuterClass

    //创建成员内部类的语法是使用对象.内部类
    //在Scala中,默认情况下内部类实例和外部对象关联
    val inner1 = new outer1.ScalaInnerClass
    val inner2 = new outer2.ScalaInnerClass
    
    //创建静态的内部类实例:
    val staticInnerClass = new myscalafirst.classinfo.ScalaOuterClass.ScalaStaticInnerClass
  }
}

实例:
内部类如果想要访问外部类的属性,可以通过外部类对象访问。即:
①访问方式1:外部类名.this.属性名

class ScalaOuterClass {
  //定义属性
  var name = "scoot"
  private var sal = 32431.1
  class ScalaInnerClass{//成员内部类
    def info()={
      //访问方式:外部类名.this.属性名
      //理解:ScalaOutClass.this相当于ScalaOuterClass这个外部类的一个实例
      //然后通过ScalaOuterClass.this 实例对象去访问name属性
      //java 通过反射ScalaOuterClass.class访问外部类对象
      println("name =" + ScalaOuterClass.this.name +
       "\tage =" + ScalaOuterClass.this.sal)
    }
  }
}

object  Test{
  def main(args: Array[String]): Unit = {
    //创建外部类实例
    val outer1:ScalaOuterClass = new ScalaOuterClass

    //创建成员内部类的语法是使用对象.内部类
    //在Scala中,默认情况下内部类实例和外部对象关联
    val inner1 = new outer1.ScalaInnerClass

    //测试一个是否可以访问成功
    inner1.info()
  }
}

输出:

在这里插入图片描述
② 方式2:外部类名别名.属性名

/内部类访问外部类属性的方法2,使用别名的方式
//1.将外部类的属性,写在别名的后面
class ScalaOuterClass {
  myouter => //这里可以看作是外部类的别名
  //定义属性
  var name = "hennry"
  private var sal = 66656.1
  class ScalaInnerClass{//成员内部类
  def info()={
    //访问方式:外部类别名.属性名
    //理解:myouter相当于ScalaOuterClass这个外部类的别名
    println("name =" + myouter.name +
      "\tage~~~ =" + myouter.sal)
  }
  }
}
object ScalaOuterClass{
  class ScalaStaticInnerClass{//静态内部类

  }
}

object Test{
 def main(args: Array[String]): Unit = {
	    //创建外部类实例
    val outer1:ScalaOuterClass = new ScalaOuterClass

    //创建成员内部类的语法是使用对象.内部类
    //在Scala中,默认情况下内部类实例和外部对象关联
    val inner1 = new outer1.ScalaInnerClass

    //测试一个是否可以访问成功
    inner1.info()
	}
}


结果:在这里插入图片描述

11. 样例类

特点:
① 样例类常用于描述不可变的值的对象(Value Object),使用关键字case声明,主要目的是模式匹配优化
② 样例类构造参数默认声明为"val",自动实现类构造参数的getter
③ 样例类构造参数默认声明为var时,自动实现类构造参数是setter和getter
④ 样例类自动创建伴生对象
⑤ 样例类自动实现的其他方法:

  • toString() equals()
  • copy() :创建一个现有对象相同的新对象,并可以通过带名参数来修改某些属性
  • hashCode()
  • 伴生对象中的:
  • apply() :无需使用new关键字就可以构造出相应的对象 var stu = StudentInfo (xxx,xxx)
  • unapply():让匹配模式可以工作
    ⑥ 除以上,样例类和其它类一样,可以添加其他方法和字段,拓展它们

例子1:匹配模式:match

object CaseClassDemo01 {
//样例类匹配简洁
  def main(args: Array[String]): Unit = {
      for (a <- Array(Money(2000.00),Currency(1000.2,"RMB"), NoAmount)){
        var result = a match {
          case Money(v)=> "$" + v
          case Currency(v,u) => u+"" +v
          case NoAmount => ""
        }
        println(a + ":" + result )
      }
  }

}
abstract class Amount
case class Money(value:Double) extends Amount //样例类
case class Currency(value:Double,u:String) extends Amount//样例类
case object NoAmount extends Amount //样例类

输出:
在这里插入图片描述

match模式匹配:数值匹配,守卫模式(case if…),类型匹配,样例类匹配,元组匹配

//模式收尾(if条件)
object mtest{
def main(args: Array[String]): Unit = {
// new MyTt().abc(new Father)
// new MyTt().abc(new Son)

// val kt1 = new kt1 = new KTest[Father]
println(abc("asdf"))
}
// def abc(x:Int)= x match {
// case 1 => x + 10
// case 2 => x + 20
// case _ => x + 30
// }
//模式守卫case i if i<10 => x + 10
// def abc(x:Int)= x match {
// case i if i<10 => x + 10
// case _ => x + 30
// }

//类型匹配
def abc(x:Any)= x match {
case i:Int if i<10 => Integer.parseInt(i.toString) + 10
case i:String => "hello"
case _ => x
}
}

//scala类型转化:
asInstanceOf[类型]
//类型匹配
def abc(x:Any)= x match {
// case i:Int if i<10 => Integer.parseInt(i.toString) + 10
case i:Int if i<10 => x.asInstanceOf[Int] + 10
case i:String => "hello"
case _ => x
}

输出:
在这里插入图片描述

例子2:copy()

object CaseClassDemo02 {
  def main(args: Array[String]): Unit = {
    val cash = new Currency3(3000.2,"RMB")
    val cash2 = cash.copy() //克隆操作,创建的对象和cash的属性一样
    println("cash2.value: " + cash2.value + "\ncash2.u:  " + cash2.u )
    println(cash2)
    //可通过copy修改属性
    val cash3 = cash.copy(value = 6000.0)
    print(cash3)
  }
}

abstract class Amount3
case class Money3(value:Double) extends Amount3 //样例类
case class Currency3(value:Double,u:String) extends Amount3//样例类
case object NoAmount3 extends Amount3 //样例类

输出:
在这里插入图片描述

case语句中的中置表达式

注:如果unapply方法产出一个元组,那么可以在case语句中使用中置表达式,比如匹配一个LIst序列:

object MidCase {
  def main(args: Array[String]): Unit = {
    List(1,3,4,5) match{
    //1.两个元素间:: 称为中置表达式,之上first,second两个匹配才行
    //2. first 匹配第一个,second匹配第二个,rest 匹配剩余部分(Any)
    case first :: second :: rest => println(first+":"+second+":"+rest)
    case _=> println("未匹配")
    }
  }
}

输出:
在这里插入图片描述

匹配嵌套结构

基本介绍:操作原理类似于正则表达式

案例:商品捆绑打折出售
要求:现在有一些商品,使用Scala设计相关的案例类,完成商品捆绑打折出售。要求
① 商品可以是单个商品,也可以是多个商品
② 打折时按照折扣进行设计
③ 能够统计出私有捆绑商品打折后的最终价格

12. 泛型

特点:
① 泛型类只可以接受类型参数的类,泛型类在集合中被广泛使用
② 与Java不同,定义泛型类使用[]

引用场景:要求函数的参数可以接受任意类型,可以使用泛型,这个类型可以代表任意的数据类型

object GenericDemo01 {
  def main(args: Array[String]): Unit = {
    val int = new IntMessage[Int](10)
    println(int)
    val string = new StringMessage[String]("a")
    print(string)
  }

}

/*
编写一个Message类,
可以构建Int类型的Message
String类型的Message
要求使用泛型类完成设计
 */
abstract class Message[T](s:T){
  def get = s
}
class IntMessage[Int](v:Int) extends Message(v)
class StringMessage[String](v:String) extends Message(v)

例子二:

object GenericDem02 {
  def main(args: Array[String]): Unit = {
    val list1 = List("a","b","c")
    val list2 = List(1,2,3)
    println(minList(list1))
    println(minList(list2))
  }
  /*
定义一个函数获取各种类型的List的中间index
使用泛型完成
 */
  def minList[E](l:List[E])={
    l(l.length/2)
  }
}

13. 类型边界

类型上界

  1. T<:A表示变量T应该是类型A的子类
  2. A是具体类型,T是泛型

类型下届

  1. T>:A表示类型T是类型A的上界(不符合父子类关系也不报错,所以和直接写泛型T没什么分别)
  2. A是具体类型,T是泛型

14. 型变

协变

说明:对于两种类型A和B,如果B是A的子类型,满足Fool[B]也符合Fool[A]的子类型,那么就称为convariance( 协变)

class Foo[+T] //协变类
//如:声明
trait List[+T]
//声明的时候
val a:List[String] = new List[Any]("1")//是不会出错的,虽然没啥关系这两个List类型

逆变

说明:对于两种类型A和B,如果B是A的子类型,满足Bar[A]也符合Bar[B]的子类型,那么就称为contravariance( 逆变)

class Bar[-T] //逆变

不可变:既不支持协变也不支持逆变

偏函数

关键字:PartialFunction
只针对函数定义域的一个子集定义的函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值