七、类的类型检查和转换
scala中的类型检查和类型转换
- 类型检查:obj.isInstanceOf[类型]
- 类型转换:obj.asInstanceOf[类型]
示例代码:
package extendsDemo /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/9/22 * @time : 4:09 下午 * * scala中的类型检查和类型转换 * 类型检查:obj.isInstanceOf[类型] * 类型转换:obj.asInstanceOf[类型] */ object ObjectEqualsOps { def main(args: Array[String]): Unit = { val w1 = new Worker("张三",15) val w2 = new Worker("张三",15) println(w1.equals(w2)) } } class Worker{ var name:String = _ var age:Int = _ def this(name:String,age:Int){ this() this.name = name this.age = age } // 传统写法 // override def equals(obj: Any): Boolean = { // if (obj == null){ // false // } // else if (!obj.isInstanceOf[Worker]){ // false // } else { // // 将obj转化为Worker // val that:Worker = obj.asInstanceOf[Worker] // this.name.eq(that.name) && this.age == that.age // } // } /** 使用Scala中的模式匹配来完成类型检查和类型转换 注意:在写模式匹配的时候,一定要把默认的选项加上,避免所有的可能性都没有匹配成功,此时就会报错:scala.MatchError */ override def equals(obj: Any): Boolean = { obj match { case that:Worker =>{ this.name.eq(that.name) && this.age == that.age } case _ =>{ // 匹配不上前面的可能性,就使用这种默认的 println("类型不匹配,不能进行比较") false } } } }
运行结果:
true
八、受保护的字段
1、跟java一样,scala中同样 可以使用protected关键字来修饰field和method,这样在于类中就不需要super关键字,直接就可以访问field和method
2、scala 中还提供了一个protected[this],则只能在当前子类对象中访问父类的field和method,无法通过其他子类对象访问父类的fieId和method
示例代码:
package extendsDemo /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/10/7 * @time : 11:20 上午 * scala 中被protected修饰的成员特点 * scala在使用protected和private做访问权限修饰的时候,除了传统的意义意外,还可以做到非常精准的控制某一个成员在某一个package下面被访问。 * 就在protected/private[具体包名],该成员只能在该包,及其子包下面被访问 * 其中有一个特例,就是protected[this],只能子在本类及其子类中被使用,不能被子类实例中来进行访问 */ object ProtectedOps { def main(args: Array[String]): Unit = { var dog1 = new Dog("dog1") var dog2 = new Dog("dog2") dog1.makeFriends(dog2) } } class Animal{ var name:String=_ // protected var age = 3 protected[extendsDemo] var age = 3 def this(name:String,age:Int){ this() this.name = name this.age = age } def show(): Unit ={ println(s"Animal:${name},${age}") } } class Dog extends Animal{ age = 5 def this(name:String){ this() this.name = name } def makeFriends(dog: Dog): Unit ={ println(s"${this.name} age is ${this.age} 要和 ${dog.name} age is ${dog.age} 交朋友") } }
运行结果:
dog1 age is 5 要和 dog2 age is 5 交朋友
九、超类的构造
1、一个类有一个主构造器和任意数量的辅助构造器,而每个辅助构造器都必须以对先前定义的辅助构造器或主构造器的调用开始。这样做帶来的后果是,辅助构造器永远都不可能直接调用超类的构造器。
2、子类的辅助构造器最终都会调用主构造器,只有主构造 器可以调用超类的构道器。主构造器是和类定义交织在一起的,调用超类构造器的方式也同样交织在一起。
示例代码:
package extendsDemo /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/10/7 * @time : 2:47 下午 * scala中超类的构造过程 * 1、Scala中在继承体系中,构造子类的时候,先有构造父类 * 2、子类在构造器中要想传递参数到父类的构造器中,只能通过主构造器 * 因为辅助构造器的第一句话,只能调用本类的主构造器,或者其他辅助构造器 */ object ExtendsOps2 { def main(args: Array[String]): Unit = { val zi:Fu = new Zi(13) } } class Fu(name:String,age:Int){ println("----------Fu-primary-constructor----------") def this(name:String){ this(name,13) println("----------Fu-this(name:String)-constructor----------") } } class Zi(name:String,age:Int) extends Fu(name) { println("----------Zi-primary-constructor----------") def this(age:Int){ this("zhangsan",age) println("----------Zi-this(name:String)-constructor----------") } }
运行结果:
----------Fu-primary-constructor---------- ----------Fu-this(name:String)-constructor---------- ----------Zi-primary-constructor---------- ----------Zi-this(name:String)-constructor----------
十、匿名内部类
1、在Scala中, 匿名子类是非常常见,而且非常强大,因为Spark源码中也大量使用了这种匿名子类。
2、匿名子类,也就是说,可以定义一个类的没有名称的子类,并直接创建其对象,然后将对象的引用赋予一个变量。之后甚至可以将该匿名子类的对象传递给其他函数
示例代码:
package extendsDemo /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/10/7 * @time : 3:24 下午 * * scala中的匿名子类---匿名内部类 * 匿名的意思就是说该类名名称 * 通常出现在继承体系中,对于接口,抽象类只被调用一次的情况,同时父类中的(抽象)方法相对较少 * * class Xxx{}---这不是匿名的 * * new Xxx{} --- 匿名子类、 * * 常见的作用:作为方法的参数出现 */ object AnnominyInnerClassOps { def main(args: Array[String]): Unit = { // 调用非匿名子类来实现 showName(new NameAnnominy) println("通过匿名子类来实现") val annominy = new Annominy(){ // 这是Annominy的一个匿名子类 override def show(): Unit = { super.show() println("hello scala") } def myPrint(): Unit ={ println("hello java!") } } annominy.show() annominy.myPrint() showName(annominy) println("通过局部匿名内部类来实现") showName(new Annominy(){ override def show(): Unit = { super.show() println("hello scala") } }) } def showName(annominy: Annominy): Unit ={ annominy.show() } } class Annominy{ val name:String = "Hello World!" def show(): Unit ={ println(name) } } // 非匿名子类 class NameAnnominy extends Annominy{ }
运行结果:
Hello World! 通过匿名子类来实现 Hello World! hello scala hello java! Hello World! hello scala 通过局部匿名内部类来实现 Hello World! hello scala
十一、抽象类
Scala中的抽象类
1、Scala中一个类的方法或者字段只做了一个声明没有进行实现或者初始化,我们把这类称之为抽象类,需要使用关键字abstract来进行声明
2、Scala中的抽象类和Java一样,既可以有抽象成员,也可以有非抽象成员
3、Scala类中子类复写父类的抽象成员的时候,我们可以省略掉override关键字
4、Scala中的抽象成员,可以省略abstract关键字
示例代码:
package abstracts /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/10/8 * @time : 1:01 下午 * * Scala中的抽象类 * 1、Scala中一个类的方法或者字段只做了一个声明没有进行实现或者初始化,我们把这类称之为抽象类,需要使用关键字abstract来进行声明 * 2、Scala中的抽象类和Java一样,既可以有抽象成员,也可以有非抽象成员 * 3、Scala类中子类复写父类的抽象成员的时候,我们可以省略掉override关键字 * 4、Scala中的抽象成员,可以省略abstract关键字 */ object AbstractOps1 { def main(args: Array[String]): Unit = { // 父类引用指向子类对象,实现多态 val bat:Animal = new Bat bat.sleep() bat.dead() val dog:Animal = new Dog dog.sleep() dog.dead() } } abstract class Animal{ var color:String = _ // 只有方法的定义,没有方法的实现,这就是一个抽象方法 def sleep() // 非抽象成员 def dead(): Unit ={ println("动物皆有一死") } } class Bat extends Animal{ color = "黑色" override def sleep(): Unit = { println("倒挂金钟") } override def dead(): Unit = { println("禁止吃野生动物") } } class Dog extends Animal{ color = "黄色" override def sleep(): Unit = { println("趴着睡觉") } override def dead(): Unit = { println("狗是人类忠诚的朋友") } }
运行结果:
倒挂金钟 禁止吃野生动物 趴着睡觉 狗是人类忠诚的朋友
十二、抽象字段
Scala中的抽象字段:所谓抽象字段,就是只有字段的声明,没有初始化的字段
示例代码:
package abstracts /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/10/8 * @time : 1:26 下午 * * Scala中的抽象字段 * 所谓抽象字段,就是只有字段的声明,没有初始化的字段 */ object AbstractOps2 { def main(args: Array[String]): Unit = { val abstractZi:AbstractZi = new AbstractZi println("name:"+abstractZi.name) println("age:"+abstractZi.age) } } abstract class AbstractFu{ // 定义了一个抽象的val和var的字段 val name:String var age:Int } class AbstractZi extends AbstractFu{ override val name: String = "张三" override var age: Int = 23 }
运行结果:
name:张三 age:23
十三、特质Trait
特质(Traits) 用于在类(Class)之间共享程序接口(Interface)和字段 (Fields)。 它们类似于 Java8的接口。类和对象 (Objects) 可以扩展特质,但是特质不能被实例化,因此特质没有参数。
特质的定义除了使用关键字trait之外,与类定义无异。
在triat中可以定义抽象方法,就与抽象类中的抽象方法一样, 只要不给出方法的具体实现即可。
类可以使用extends关键字继承trait,注意,这里不是implement,而是extends, 在scala中没有implement的概念,无论继承类还是trait,统一都是extends.
示例代码:
package abstracts /** * @author : 蔡政洁 * @email :caizhengjie888@icloud.com * @date : 2020/10/8 * @time : 2:28 下午 * * Scala的特质Trait * 什么是trait特质? * 特质trait,就是在Scala中一种和class、object同一级别的语法结构,需要被trait关键字进行声明 * 为什么要有trait特质? * Java和Scala的继承特点? * 不仅仅指的是:封装、继承、多态、抽象。 * 只能进行单继承,不可以进行多继承。 * 这种单继承,是有局限的,只能单一的继承某一个类的成员,在Scala和Java中是无法做到再去继承其他类的特性。 * 为了弥补这个缺陷,在Java和Scala中,首先就有多层继承 * A extend B, B extend C <=> A继承了B,同时也继承了C的特性 * 其次在Java中还有一个多实现的概念,被实现的结构称之为接口(interface),接口中的所有的方法都是抽象的 * * 要进行实现的所有的方法都是抽象,那如果一个接口的方法很多,在实现起来很麻烦,所以在Java中又有一种设计模式——适配器 * * 于是,在Scala中就弥补这个设计上的缺憾——Java中多实现的方法都需要自己来实现,那么也就是说,在Scala中是可以多实现的,同时 * 多实现的方法不一定都是抽象。 * * Scala中把类似Java中的这种多实现接口(interface),不叫多实现,而称之为trait特质的多扩展 * Scala中的trait在一定程度上,是可以看作Java中的接口interface,如果一个trait特质中的所有的方法都是抽象的,那么就可以将其视为Java中的一个接口 * * 在Java中,实现多个接口的时候,使用的是关键字interface,多个使用","来进行分割 * 在Scala中,扩展特质trait和扩展父类使用的是相同的关键字extends,扩展多个trait的时候使用with关键字进行分割 * 而且,如果即继承一个类,又扩展一个特质,书写的顺序是继承类优先,其次在with特质 */ object TraitOps { def main(args: Array[String]): Unit = { val consoleLog = new ConsoleLog with TraitMix consoleLog.log("行车不规范,亲人两行泪") consoleLog.show() consoleLog.method() // 混入 consoleLog.mix() } } class TraitFu{ def method(): Unit ={ println("---TraitFu-method---") } } /* 在运行时,让一个类具备另外一个类的特征,把这种操作,称之为Scala中的混入,此时的影响只是在局部 只需要在创建类对象的时候,使用关键字with连接需要具备的类即可 */ trait TraitMix{ def mix(): Unit ={ println("这是为了证明Scala中的特质还有更NB的地方-混入") } } trait Log{ // 抽象方法 def log(msg:String) def show(): Unit ={ println("这就是为了证明,Scala中的trait要比Java中的interface接口更NB") } } // 继承类优先,其次with特质 class ConsoleLog extends TraitFu with Log with Serializable { override def log(msg: String): Unit = { println("控制台:"+msg) } } // 扩展特质trait用关键字extends class FileLog extends Log{ override def log(msg: String): Unit = { println("文件:"+msg) } }
运行结果:
控制台:行车不规范,亲人两行泪 这就是为了证明,Scala中的trait要比Java中的interface接口更NB ---TraitFu-method--- 这是为了证明Scala中的特质还有更NB的地方-混入