Scala编程(二)面向对象编程

Scala编程(二)面向对象编程

1.类的定义

//scala类
class Person {
  //用val定义的成员变量,只提供了getter方法
  val id = "1234"
  //用var定义的成员变量,提供了setter和getter方法
  var name = "jack"
  var age = 20
  //方法
  def sleep()={
    println("正在休息。。。。。")
  }
}
object Person extends App {
  val p = new Person()
  //获取和修改成员变量
  //p.id = "23432"  报错val修饰的成员变量不能修改
  println("id:" + p.id)
  p.age = 22
  println("age:" + p.age)
  println(p.name)
  p.sleep()
}

2.构造器

Scala中的每个类都有一个主构造器,主构造器的参数直接放在类后面,并且主构造器会执行类中定义所有语句

//主构造器放在类名后面
class Student (val n :String,var a :Int){
  val name :String = n
  //var修饰可修改
  a = a + 1
  var age = a
  //使用占位符时需要指定参数的类型
  //scala类中所使用的占位符”_”,只有在声明var变量时才可以使用
  var sex : String= _
  println("主构造器执行了类中定义的所有语句")
  //构造器(构造方法) 辅构造器
  def this(n :String,a :Int,sex :String){
    //调用主构造器,不可省略
    this(n,a)
    println("调用了辅构造器")
    this.sex = sex
  }
  //方法
  def study(s :String): Unit ={
    println(name + "在学习" + s)
  }

}


object Student extends App{
  //主构造器
  val stu1 = new Student("jack",20)
  println(stu1.age)  //21
  //赋值操作会在其他语句之后执行
  stu1.age = 30
  stu1.study("scala")
  println(stu1.age)  //30
  //辅构造器
  val stu2 = new Student("lisi",20,"男")
  stu2.study("hadoop")
}

执行结果:

主构造器执行了类中定义的所有语句
21
jack在学习scala
30
主构造器执行了类中定义的所有语句
调用了辅构造器
lisi在学习hadoop

3.访问权限

3.1构造器的访问权限

//主构造器放在类名后面
class Student private(val n :String,var a :Int){
  val name :String = n
  //var修饰可修改
  a = a + 1
  var age = a
  //使用占位符时需要指定参数的类型
  //scala类中所使用的占位符”_”,只有在声明var变量时才可以使用
  var sex : String= _
  println("主构造器执行了类中定义的所有语句")
  //构造器(构造方法) 辅构造器
  private def this(n :String,a :Int,sex :String){
    //调用主构造器,不可省略
    this(n,a)
    println("调用了辅构造器")
    this.sex = sex
  }
  //方法
  def study(s :String): Unit ={
    println(name + "在学习" + s)
  }

}


object Test extends App{
  val stu1 = new Student("张三",20)
  val stu2 = new Student("李四",30,"女")
}

运行结果会出错:在主构造器或辅构造器修饰为private后,访问权限仅限:本类和伴生对象中使用

伴生对象:指的是对象名与类名相同的对象

3.2类中变量的访问权限

当类中的成员变量为私有时,有如下两种解决方法

1、在Student类中添加:getter、setter方法

2、使用伴生对象

//scala类
class Person {
  private var name :String = _
  private var age :Int = _

  //方法
  def sleep()={
    println(s"年龄为:$age 的 $name 正在休息。。。。。")
  }
}

object Test extends App{
  //创建对象
  var p = new Person()
//p.id   报错并不能访问私有的成员
  p.sleep()
}

解决方法:

//scala类
class Person { //默认的无参主构造器
  private var name :String = _
  private var age :Int = _
  //get和set方法
  def setName(name: String) ={
    this.name = name
  }
  def getName: String ={
    this.name
  }
  def setAge(age :Int)={
    this.age = age
  }
  def getAge : Int = {
    this.age
  }
  //全参构造器(辅构造器)
  def this(name :String,age : Int){
    this()
    this.name = name
    this.age = age
  }

  //方法
  def sleep()={
    println(s"年龄为:$age 的 $name 正在休息。。。。。")
  }
}

object Test extends App{
  //创建对象  主构造器
  var p = new Person()
  //p.id   报错并不能访问私有的成员
  p.setAge(20)
  p.setName("jack")
  p.sleep()

  //辅构造器
  var p1 = new Person("lisi",30)
  p1.sleep()
}

对象

1.Scala中的object

object相当于class的单个实例(单例模式),通常在里面放一些静态的field或者method
在Scala中没有静态方法和静态字段,但是可以使用object这个语法结构来达到同样的目的

object的单例模式

class Session {}

object Session extends App {
  //相当于静态块
  val session = new Session
  //相当于静态方法
  def getSession() : Session={
    session
  }
}

object Test1 extends App {
  //单例对象
  val session1 = Session.session
  val session2 = Session.getSession()
}

2.scala中的伴生对象

伴生对象的解释:
如果有一个class,还有一个与class同名的object,那么就称这个object是class的伴生对象,class是object的伴生类
要求: 伴生类和伴生对象必须存放在一个.scala文件中
特点: 伴生类和伴生对象的最大特点是,可以相互访问(可以访问私有成员)

//伴生类
class Student private{
    //私有成员
 private var name :String = _
  private var age :Int = _
  //get和set方法
  def setName(name: String) ={
    this.name = name
  }
  def getName: String ={
    this.name
  }
  def setAge(age :Int)={
    this.age = age
  }
  def getAge : Int = {
    this.age
  }
  //私有全参构造器(辅构造器)
  private def this(name :String,age : Int){
    this()
    this.name = name
    this.age = age
  }
  //方法
  def study(s :String): Unit ={
    println(name + "在学习" + s)
  }
}
//伴生对象
object Student{
  val stu1 = new Student()
  stu1.name = "zhangsan"
  stu1.age = 20
  stu1.study("java")
  val stu2 = new Student("lisi",30)
}

3.Scala中的apply方法

//伴生类
class Student private{
  //私有成员
  private var name :String = _
  private var age :Int = _
  //get和set方法
  def setName(name: String) ={
    this.name = name
  }
  def getName: String ={
    this.name
  }
  def setAge(age :Int)={
    this.age = age
  }
  def getAge : Int = {
    this.age
  }
  //私有全参构造器(辅构造器)
  private def this(name :String,age : Int){
    this()
    this.name = name
    this.age = age
  }
  //方法
  def study(s :String): Unit ={
    println(name + "在学习" + s)
  }
}
//伴生对象
object Student{
  //无参
  def apply(): Student = new Student()
  //有参
  def apply(name : String,age : Int): Student = new Student(name,age)
}

//测试类
object Test1 extends App {
  //利用伴生对象创建对象
  var stu = Student()
  //相当于  var stu = Student.apply()
  stu.setName("张三")
  stu.setAge(20)
  stu.study("java")
  //var stu = Student.apply(name,age)
  var stu2 = Student("李四",30)
  stu2.study("scala")
}

继承

1.继承的概念

继承是面向对象的概念,用于代码的可重用性。被扩展的类称为超类或父类, 扩展的类称为派生类或子类。
Scala 中,让子类继承父类,与 Java 一样,也是使用 extends 关键字;

//父类
class Person{
   var name :String = _
   var age :Int = _
}
//子类
class Student extends Person{
  //子类特有的方法
  def study(s : String): Unit ={
    //name是继承的person中的变量
    println(name + "在学习" + s)
  }
}
object Test1 extends App {
  var stu = new Student()
  stu.name = "jack"
  stu.age = 30
  stu.study("scala")
}

继承就代表,子类可继承父类的field和method,然后子类还可以在自己的内部实现父类没有的,子类特有的 field 和method,使用继承可以有效复用代码
在Scala中的继承:
1、private修饰的field和method不可以被子类继承,只能在类的内部使用
2、使用final修饰符时,修饰类:类不能被继承、修饰field和method:不能被覆写

2.Scala中的override和super关键字

override

override的使用场景:
1、Scala中,如果子类要覆盖父类中的一个非抽象方法,必须要使用 override 关键字
2、子类可以覆盖父类的val修饰的field,只要在子类中使用 override 关键字即可
(注意:针对父类中的var修饰的field,子类不能覆写)

super

super的应用场景: super.父类中的方法
在子类覆盖父类方法后,如果在子类中要调用父类中被覆盖的方法,则必须要使用super关键字(显示的指出要调用的父类方法)

override和super的应用案例:

//父类
class Phone {
  //val不可修改的变量
  val id = "12345"
  def call = println("打电话")
}
//子类
class NewPhone extends Phone {
  //覆写父类中的val变量和非抽象方法必须使用override关键字
  override val id: String = "6789"
  override def call: Unit = {
    //调用父类的方法使用super关键字
    super.call
    println("开启视频")
  }
}
object Test1 extends App {
  var p = new NewPhone()
  //调用子类覆写的方法
  p.call
}

3.scala中的protected

在Scala中同样提供了protected关键字来修饰field和method,方便子类去继承父类中的field和method

//父类
class Person{
  //protected 是为继承提供的
  //protected [this] 只允许在本类和子类中使用(子类的伴生对象不能访问)
   protected [this] var name :String = _
   protected var age :Int = _
  protected def say(s :String)= println(s)
}
//子类
class Student extends Person{
  //子类特有的方法
  def study(s : String): Unit ={
    //name是继承的person中的变量
    println(name + "在学习" + s)
  }
  def setName(n :String)={
    this.name = n
  }
}
object Student extends App {
  var stu = new Student()
  //这里不能直接访问父类的name成员
  stu.setName("张三")
  stu.age = 20
  stu.study("scala")
}

4.调用父类的constructor

创建子类对象时,会自动调用子类相应的构造器:

1、调用子类主构造器
2、调用子类辅助构造器,辅构造器会再去调用主构造器
和java一样,创建子类对象时,也会先去调用父类的构造器:子类主构造器去调用父类中的构造器

5.scala中的抽象类

一个类中,如果含有一个抽象方法或抽象field,就必须使用abstract将类声明为抽象类,该类是不可以被实例化的
在子类中覆盖抽象类的抽象方法时,可以不加override关键字

//抽象类  抽象field和方法都需要放在方法抽象类中
abstract class Person{
  //抽象的field没有初始值
   var name :String
   var age :Int = _
  //抽象方法没有方法体实现
  def study(s: String)
  def say:String
}
//子类继承抽象类
class Student extends Person{
  //覆写所有的抽象内容  同时可以省略override
  def study(s : String): Unit ={
    //name是继承的person中的变量
    println(name + "在学习" + s)
  }
  override var name: String = _

  override def say: String = "hello"
}
object Student extends App {
  var stu = new Student()
  stu.name = "jack"
  stu.age = 20
  var hello = stu.say
  stu.study("scala")
}

6.scala中的isInstanceOf和asInstanceOf 多态

在实例化了子类的对象,并将其赋予了父类类型的变量后,父引用无法去调用子类中特有的方法,如果想要调用子类中特有的方法,应该类型转换
在java中,进行类型转换时,为了避免类型转换异常,会使用instanceof先判断类型,再进行类型转换

//父类 
class Person{
  var name :String = _
  var age :Int = _
   def eat(s :String)={
     println("吃" + s)
   }
}
//子类
class Student extends Person{
  //子类特有的方法
  def study(s : String): Unit ={
    //name是继承的person中的变量
    println(name + "在学习" + s)
  }
  //子类覆写父类的方法
  override def eat(s: String): Unit = {
    println(this.name + "吃" + s)
  }
}

object Test extends App {
  //声明一个父类型变量指向子类型
  var person : Person = new Student()
  person.name = "jack"
  person.age = 20
  person.eat("米饭")
  //判断person对象是否为student的实例
  if (person.isInstanceOf[Student]){
    //将person对象转成student实例
    var stu : Student = person.asInstanceOf[Student]
    //调用子类对象特有的方法
    stu.study("java")
  }
}

Trait

1.将trait作为接口使用

Scala中的Trait(特质)相当于Java的接口,但实际上它比接口要功能强大,与传统的接口不同之处是:它除了可以定义抽象方法外还可以定义属性和方法的实现
在Scala中没有 implement 的概念,无论继承类还是trait,统一都是 extends
类继承后,必须实现所有的抽象方法,实现时不需要使用 override 关键字

trait Demo1{
  def sayHello(s :String)
}
//子类继承需要重写抽象方法
class Person extends Demo1 {
  override def sayHello(s: String): Unit = {
    println("打招呼," + s)
  }
}
object TraitDemo1 extends App {
  val p = new Person()
  p.sayHello("jack")
}

Scala不支持对类进行多继承,但是支持多重继承 trait,使用 with 关键字即可

trait Demo1{
  def sayHello(s :String)
}
trait Demo2{
  def say():String
}
class Person extends Demo1 with Demo2 {
  override def sayHello(s: String): Unit = {
   println( say() + s)
  }
  override def say(): String = "你好"
}
object TraitDemo1 extends App {
  val p = new Person()
  p.sayHello("scala")
}

在Traint中除了可以书写抽象方法外,还可以书写:抽象字段、具体方法、具体字段

2.Trait高级应用

2.1在实例对象指定混入某个trait

Trait高级知识: 创建对象实例时,trait加入到对象实例中
可在创建类的对象时,为该对象指定混入某个trait,且只有混入了trait的对象才具有trait中的方法,而其他该类的对象则没有
格式: val 引用变量 = new 类名() with Trait
在创建对象时,使用with关键字指定混入某个trait

trait TraitLogger{
  def log(msg : String)={
    println("日志内容:------" + msg)
  }
}
trait MyLogger extends TraitLogger{
  override def log(msg: String): Unit = {
    println(System.currentTimeMillis() + msg)
  }
}
class Person extends TraitLogger{
    log("打印日志。。。")
}
object TraitDemo2 extends App {
  val p = new Person() with MyLogger
}
2.2Trait调用链

当去调用多个trait中的方法时,首先会从最右边的trait中的方法开始执行,然后依次往左边的trait执行,形成一个调用链条(这个特性非常强大:是设计模式中责任链模式的一种具体实现)

trait TraitOne{
  def handle(data : String)={
    println("获取数据--" + data)
  }
}
trait TraitTwo extends TraitOne{
  override def handle(data : String)={
    println("处理数据--"+ data)
    super.handle(data)
  }
}
trait TraitThree extends TraitOne{
  override def handle(data : String)={
    println("分析数据--"+ data)
    super.handle(data)
  }
}
class RequestResult(val data : String) extends TraitThree with TraitTwo {
  def getParam={
    println("参数:" + data)
    //调用多个trait中方法名相同的方法
    handle(this.data)
  }
}

object traitdemo3 extends App {
  val p = new RequestResult("大数据")
  p.getParam
}
2.3混合使用trait的具体方法和抽象方法
trait traitOne{
  def getName : String
  def valid(data : String):Boolean={
    data.equals(this.getName)
  }
}
class Person(data :String) extends traitOne{
  override def getName: String = this.data
}
object traitdemo4 extends App {
  val p = new Person("数据")
  if (p.valid("测试")){
    println("数据合法")
  }else{
    println("数据不合法")
  }
}
2.4Trait的构造机制

2.4.1构造机制

在Trait中只有无参构造(主构造器)

trait TraitOne{
  println("TraitOne的构造器。。。。")
}
trait TraitTwo{
  println("TraitTwo的构造器。。。。")
}
class TraitChlid extends TraitOne with TraitTwo {
  println("TraitChlid的构造器。。。。")
}
object traitdemo5 extends App {
  val t = new TraitChlid()
}

子类没有继承父类,只继承多个独立的Trait(Trait没有继承)时,构造机制:
从extends后面第一个Trait构造器开始执行,依次向后面的Trait构造器执行

class Parent{
  println("Parent的构造器。。。。")
}
trait MyTrait{
  println("MyTrait的构造器。。。。")
}
trait TraitOne extends MyTrait{
  println("TraitOne的构造器。。。。")
}
trait TraitTwo extends MyTrait{
  println("TraitTwo的构造器。。。。")
}
class TraitChlid extends Parent with TraitOne with TraitTwo {
  println("TraitChlid的构造器。。。。")
}
object traitdemo5 extends App {
  val t = new TraitChlid()
}

子类继承了父类的同时,也继承了多个Trait(Trait也有继承)时,构造机制:
1、父类的构造器
2、多个Trait从左向右依次执行(构造Trait时,先构造父Trait)
注意:如果多个Trait继承同一个父Trait,则父Trait只会构造一次
3、子类的构造器

2.4.2Trait中的field初始化

提前定义Trait中的field

trait traitHello{
  //抽象field
  val msg : String
  println("信息的长度:"+ msg.length)
}
class TraitClass extends {override val msg :String = "初始化值"} with traitHello{
    //方法一在类上覆写抽象field
}
object traitdemo6 extends App {
  val t = new TraitClass()
  //方法二在实例化时覆写抽象field
  /**
    * val t = new {
    * override val msg :String = "初始化值"
    * } with TraitClass with traitHello
    */
}

猜你喜欢

转载自blog.csdn.net/lsy107816/article/details/84678679