scala-类和对象

类和对象

Scala是一个函数式面向对象语言

什么是面向对象?

面向对象是一种变成语言,它是基于面向过程的,强调的是以对象为基础完成各种操作

三大特点:

  • 跟符合程序员的思考习惯
  • 把复杂的事情简单化
  • 把程序员从执行之变为指挥者

什么是类?

类是属性和行为的集合,是一个抽象的概念,看不见也摸不着

类和无参构造器

在Scala中,类并不用声明为public;Scala源文件中可以包含多个类,所有这些类都具有公有可见性;val修饰的变量(常量),值不能改变,只提供getter方法,没有setter方法;var修饰的变量,值可以改变,对外提供getter、setter方法;如果没有定义构造器,类会有一个默认的无参构造器;

  • 如果类是空的,没有任何成员,可以省略{}
  • 如果构造器的参数为空,可以省略()
package hhb.cn.part04

/**
 * @description:
 * 在Scala中,类都有一个无参构造器
 * @date: 2020-09-24 10:05
 **/
class Person {
  //声明字段必须进行初始化,Scala编译器会根据初始化值的数据类型自动推断字段类型,字段类型可以省略
  var name = "huanghongbo"
  // _ 下划线表示一个占位符,编译器会根据变量的数据类型赋予相应的初始值
  //使用 _ 占位符进行赋初始值的时候,数据类型必须指定
  var nickName: String = _
  var age: Int = _
  var numDouble: Double = _
  var flag: Boolean = _
  // 使用val修饰的变量不能使用占位符
  //  val test:Int = _
  val num = 30
  var a = 20
  //如果对String类型赋值为null,必须指定类型,否则默认类型为Null
  var address: String = null
  // 类中的私有字段,有私有的getter 和 setter方法
  // 可以在类的内部访问,也可以被其伴生对象访问
  private var hobby = "旅游"
  //对象的私有字段,访问权限更小,只能在当前类中访问
  private[this] var cardInfo = "10010"
  def hello(message: String): Unit = {
    //只能在当前类中访问cardInfo
    println(s"$message   , $cardInfo    ,   $hobby")
  }
  //自定义方法实现两个数据求和
  def addNum(num1: Int, num2: Int): Int = {
    num1 + num2
  }
}

object ClassDemo {
  def main(args: Array[String]): Unit = {
    //使用无参构造器创建对象,小括号可以省略
    val person = new Person()
    var p = new Person
    println(s"${person.name}     ${person.nickName}     ${person.age}     ${person.numDouble}      ${person.flag}")
    //给类的属性赋值
    person.age = 50
    //注意:这种方式赋值其实就是调用 age_= 这个setter方法
    person.age_=(20)
    //这种就是调用了他的getter方法
    println(person.age)
    //调用类中的方法
    person.hello("你好")
    println(person.addNum(1, 3))
    //无法调用类中的私有字段和对象的私有字段
    //    person.hobby
    //    person.cardInfo

  }
}

自定义Getter和Setter方法

对于 Scala 类中的每一个属性,编译后会有一个私有的字段和相应的getter、setter方法生成。如果属性是私有的,生成的getter、setter方法也是私有的

package hhb.cn.part04

/**
 * @description:
 * @date: 2020-09-24 10:48
 **/
class Dog {
  private var _leg = 0

  private var test1 = 0
  var test2 = 0

  //自定义getter方法
  def leg: Int = _leg

  //自定义setter方法
  def leg_=(newLeg: Int) {
    _leg = newLeg
  }

}
object GetterAndSetterDemo {
  def main(args: Array[String]): Unit = {
    val dog = new Dog
    //调用自定义的setter方法
    dog.leg_=(10)
    //调用自定义的getter方法
    println(dog.leg)

    //私有的属性不自定义setter方法,直接使用报错
//    dog.test1_=(1)
    dog.test2_=(1)
  }
}
反编译.png

自定义变量的getter和setter方法需要遵循以下原则:

  • 字段属性名以"_"作为前缀,如:_leg
  • getter 方法定义为:def leg = _leg
  • setter 方法定义为:def leg_=(newLeg:Int)

Bean属性

JavaBean规范把Java属性定义为一堆getter和setter方法。类似于Java,当将Scala字段标注为 @BeanProperty时,getFoo和setFoo方法会自动生成。使用@BeanProperty并不会影响Scala自己自动生成的getter和setter方法。在使用时需要导入包scala.beans.BeanProperty

package hhb.cn.part04

import scala.beans.BeanProperty

/**
 * @description:
 * @date: 2020-09-24 11:05
 **/
class Teacher {
  @BeanProperty var name: String = _
}

object BeanDemo {
  def main(args: Array[String]): Unit = {

    val teacher = new Teacher
    teacher.name = "张三"
    teacher.name_=("李四")
    println(teacher.name)

    //@BeanProperty 生成的set、get方法
    teacher.setName("王五")
    println(teacher.getName)
  }
}

构造器

如果没有定义构造器,Scala类中会有一个默认的无参构造器;Scala当中类的构造器分为两种:主构造器和辅助构造器;主构造器的定义与类的定义交织在一起,将主构造器的参数直接放在类名之后。当主构造器的参数不用var或val修饰时,参数会生成类的私有val成员。Scala中,所有的辅助构造器都必须调用另外一个构造器,另外一个构造器可以是辅助构造器,也可以是主构造器。

package hhb.cn.part04

//主构造器与类名交织在一起,类名后面的参数就是主构造器的参数
//主构造器直接在类中,其代码不包含在任何方法中
class Animal(name: String, age: Int) {
  //下面三行代码也属于主构造器的方法
  println(name)
  println(age)
  println("=================================")

  var gender: String = ""

  def this(name: String, age: Int, gender: String) {
    //在类中,每个辅助构造器必须以主构造器或其他辅助构造器的调用作为第一行代码
    this(name, age)
    this.gender = gender
  }

  var color: String = ""

  def this(name: String, age: Int, gender: String, color: String) {
    //此处调用的是其他构造器
    this(name, age, gender)
    this.color = color
  }
}

object ConstructorDemo {

  def main(args: Array[String]): Unit = {
    val animal1 = new Animal("啦啦1", 5)
    val animal2 = new Animal("啦啦2", 6,"公")
    val animal3 = new Animal("啦啦3", 7,"公","红色")
  }
}

备注:每个辅助构造器必须以主构造器或其他辅助构造器的调用作为第一行代码

对象

单例对象

Scala并没有提供Java那样的静态方法或静态字段;

可以采用object关键字实现单例对象,具备和Java静态方法同样的功能;

使用object语法结构【object是Scala中的一个关键字】达到静态方法和静态字段的目的;对象本质上可以拥有类的所有特性,除了不能提供构造器参数;

对于任何在Java中用单例对象的地方,在Scala中都可以用object实现:

  • 作为存放工具函数或常量的地方
  • 高效地共享单个不可变实例
package hhb.cn.part04

/**
 * @description:
 * @author: huanghongbo
 **/
object Object {
  println("这是一个单例对象!!!")

  def printInfo: Unit = {
    println("Hello Scala Object")
  }
}

object ObjectDemo {

  def main(args: Array[String]): Unit = {
    // 只会输出一次这是单例对象
    //    val object1 = Object
    //    val object2 = Object
    // 同样只会输出一次这是单例对象
    Object.printInfo
    Object.printInfo

  }
}

Scala中的单例对象具有如下特点:

  1. 创建单例对象不需要使用new关键字
  2. object中只有无参构造器
  3. 主构造代码块只能执行一次,因为它是单例的

伴生类与伴生对象

当单例对象与某个类具有相同的名称时,它被称为这个类的“伴生对象”;

类和它的伴生对象必须存在于同一个文件中,而且可以相互访问私有成员(字段和方法);

package hhb.cn.part04

//伴生类和伴生对象在一个文件中,文件名相同
/**
 * 伴生类
 */
class ClassObject {

  private var name = "hhb"

  def printInfo: Unit = {
    //在伴生类中可以访问伴生对象的私有成员
    println(ClassObject.num)
    println("Hello Object!")
  }

}

/**
 * 伴生对象
 */
object ClassObject {
  private var num = 10

  def main(args: Array[String]): Unit = {
    val classObject = new ClassObject
    //在伴生对象中可以访问伴生类的私有成员
    println(classObject.name)
    classObject.printInfo
  }
}

应用程序与对象

每个Scala应用程序都必须从一个对象的main方法开始,这个方法的类型为 Array[String] => Unit;

备注:main方法写在class中是没有意义的,在IDEA中这样的 class 连run的图标都不能显示

除了main方法以外,也可以扩展App特质(trait)

package hhb.cn.part04

/**
 * App源码里面有一个main方法。我们不需要写了,只需要直接继承App即可
 */
object AppDemo extends App {

  println("Hello Spark")

}

apply方法

object 中有一个非常重要的特殊方法 -- apply方法;

  • apply方法通常定义在伴生对象中,目的是通过伴生类的构造函数功能,来实现伴生对象的构造函数功能;

  • 通常我们会在类的伴生对象中定义apply方法,当遇到类名(参数1,...参数n)时apply方法会被调用

  • 在创建伴生对象或伴生类的对象时,通常不会使用new class/class() 的方式,而是直接使用 class()隐式的调用伴生对象的 apply 方法,这样会让对象创建的更加简洁;

package hhb.cn.part04

class Student(name: String, age: Int) {

  private var gender: String = _

  def sayHi: Unit = {
    println(s"大家好,是$name , 年龄 $age, $gender 生")
  }

}

object Student extends App {


  def apply(name: String, age: Int): Student = new Student(name, age)

  //直接使用class类名(参数……) 这种方式隐式调用伴生对象中apply方法创建class Student 对象
  val student = Student("zhangs", 20)

  //伴生类和伴生对象可以相会访问私有成员
  student.gender = "男"

  student.sayHi
}

问题:在Scala中实现工厂方法,让子类声明哪种对象应该被创建,保持对象创建在同一位置。例如,假设要创建Animal工厂,让其返回Cat和Dog类的实例,基于这个需求,通过实现Animal伴生对象的apply方法,工厂的使用者可以像这样创建新的Cat和Dog实例。

package hhb.cn.part04

abstract class Animal {
  def speak
}

class Dog extends Animal {
  override def speak: Unit = {
    println("============")
  }
}

class Cat extends Animal {
  override def speak: Unit = {
    println("+++++++++++")
  }
}

object Animal {

  def apply(message: String): Animal = {
    if (message == "dog") {
      new Dog
    } else {
      new Cat
    }
  }

  def main(args: Array[String]): Unit = {
    val cat = Animal("cat")
    cat.speak

    val dog = Animal("dot")
    dog.speak
  }
}
第四个模块错题集.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,552评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,666评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,519评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,180评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,205评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,344评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,781评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,449评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,635评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,467评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,515评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,217评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,775评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,851评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,084评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,637评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,204评论 2 341

推荐阅读更多精彩内容

  • 类 类是对象的模板,在scala中可以使用new关键字声明同结构的对象class Person { privat...
    hipeer阅读 295评论 0 0
  • 如果类没有内容(body),可以省略空的花括号,只写一行语句 类可以带参数,类名称C之后圆括号内的参数,x称为类参...
    wangdy12阅读 849评论 0 0
  • 类 定义类 类的定义用关键字class 定义Student学生类,Student是类名称,建议列名称首字母大写。类...
    _羊羽_阅读 325评论 0 0
  • 类定义 Kotlin 类可以包含:构造函数和初始化代码块、函数、属性、内部类、对象声明。Kotlin 中使用关键字...
    bruce1990阅读 333评论 0 0
  • PS:有小伙伴说配图有点意思,嘿嘿,今天的配图是: 把这四节的内容都掌握了,基本就算kotlin入门了不逼逼,开始...
    coder_pig阅读 4,022评论 8 9