【Scala】Scala面向对象编程之类和对象

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/gongxifacai_believe/article/details/81941692

1、类class

(1)定义类
1.  定义类,包含field以及方法

class HelloWorld {
  private var name = "leo"
  def sayHello() { print("Hello, " + name) }  
  def getName = name
}

2.  创建类的对象,并调用其方法

val helloWorld = new HelloWorld
helloWorld.sayHello() 
print(helloWorld.getName)

调用方法也可以不加括号,如果定义方法时不带括号,则调用方法时也不能带括号
(2)getter与setter
定义不带private的var field,此时scala生成的面向JVM的类时,会定义为private的name字段,并提供public的getter和setter方法,而如果使用private修饰field,则生成的getter和setter也是private的,如果定义val field,则只会生成getter方法,如果不希望生成setter和getter方法,则将field声明为private[this]。
也就是说,用var声明的属性,Scala编译的时候会把这个字段编程private私有的,但是会提供public的对外提供的getter和setter方法,这样的话,就不需要手动定义getter和setter方法。val定义字段的话,只会生成getter,因为它的值不可变。如果是加了private的字段,字段本身是private,那么它的getter和setter方法也是private,只能在类中使用。而定义为prviate[this],没有getter和setter方法,只能在当前类的实例中使用。

class Student {
  var name = "leo"
}

调用getter和setter方法,分别叫做name和name_ =

val leo = new Student
print(leo.name)
leo.name = "leo1"

(3)自定义getter与setter
如果只是希望拥有简单的getter和setter方法,那么就按照scala提供的语法规则,根据需求为field选择合适的修饰符就好:var、val、private、private[this],但是如果希望能够自己对getter与setter进行控制,则可以自定义getter与setter方法,自定义setter方法的时候一定要注意scala的语法限制,签名、=、参数间不能有空格。

class Student {
  private var myName = "leo"
  def name = "your name is " + myName
  def name_=(newValue: String)  {
    print("you cannot edit your name!!!")
  }
}

val leo = new Student
print(leo.name)
leo.name = "leo1"

(4)仅暴露field的getter方法
如果你不希望field有setter方法,则可以定义为val,但是此时就再也不能更改field的值了,但是如果希望能够仅仅暴露出一个getter方法,并且还能通过某些方法更改field的值,那么需要综合使用private以及自定义getter方法。此时,由于field是private的,所以setter和getter都是private,对外界没有暴露;自己可以实现修改field值的方法;自己可以覆盖getter方法。

class Student {
  private var myName = "leo"

  def updateName(newName: String) { 
    if(newName == "leo1") myName = newName 
    else print("not accept this new name!!!")
  }

  def name = "your name is " + myName
}

(5)private[this]的使用
如果将field使用private来修饰,那么代表这个field是类私有的,在类的方法中,可以直接访问类的其他对象的private field,这种情况下,如果不希望field被其他对象访问到,那么可以使用private[this],意味着对象私有的field,只有本对象内可以访问到。

class Student {
  private var myAge = 0
  def age_=(newValue: Int) { 
    if (newValue > 0) myAge = newValue 
    else print("illegal age!") 
  }
  def age = myAge
  def older(s: Student) = {
    myAge > s.myAge
  }
}

(6)Java风格的getter和setter方法
Scala的getter和setter方法的命名与java是不同的,是field和field_=的方式,如果要让scala自动生成java风格的getter和setter方法,只要给field添加@BeanProperty注解即可,此时会生成4个方法,name: String、name_=(newValue: String): Unit、getName(): String、setName(newValue: String): Unit。

import scala.reflect.BeanProperty
class Student {
  @BeanProperty var name: String = _
}
class Student(@BeanProperty var name: String)

val s = new Student
s.setName("leo")
s.getName()

(7)辅助constructor
Scala中,可以给类定义多个辅助constructor,类似于java中的构造函数重载,辅助constructor之间可以互相调用,而且必须第一行调用主constructor。

class Student {
  private var name = ""
  private var age = 0
  def this(name: String) {
    this()
    this.name = name
  }
  def this(name: String, age: Int) {
    this(name)
    this.age = age
  }
}

(8)主constructor
Scala中,主constructor是与类名放在一起的,与java不同,而且类中,没有定义在任何方法或者是代码块之中的代码,就是主constructor的代码,这点感觉没有java那么清晰。

class Student(val name: String, val age: Int) {
  println("your name is " + name + ", your age is " + age)
}

主constructor中还可以通过使用默认参数,来给参数默认的值

扫描二维码关注公众号,回复: 2966833 查看本文章
class Student(val name: String = "leo", val age: Int = 30) {
  println("your name is " + name + ", your age is " + age)
}

如果主constrcutor传入的参数什么修饰都没有,比如name: String,那么如果类内部的方法使用到了,则会声明为private[this] name;否则没有该field,就只能被constructor代码使用而已。
(9)内部类
Scala中,同样可以在类中定义内部类;但是与java不同的是,每个外部类的对象的内部类,都是不同的类。

import scala.collection.mutable.ArrayBuffer
class Class {
  class Student(val name: String) {}
  val students = new ArrayBuffer[Student]
  def getStudent(name: String) =  {
    new Student(name)
  }
}

val c1 = new Class
val s1 = c1.getStudent("leo")
c1.students += s1

val c2 = new Class
val s2 = c2.getStudent("leo")
c1.students += s2
  1. 主构造方法直接跟在类名的后面,主构造方法中的参数最后会被编译成字段或属性
  2. 主构造方法执行的时候,会执行类中的所有语句
  3. 如果参数声明的时候不带val或者是var这类修饰符的话,那么相当于是private[this],只能在内部进行使用

2、对象object

(1)object
object相当于class的单个实例,通常在里面放一些静态的field或者method。第一次调用object的方法时,就会执行object的constructor,也就是object内部不在method中的代码;但是object不能定义接受参数的constructor。注意,object的constructor只会在其第一次被调用时执行一次,以后再次调用就不会再次执行constructor了。object通常用于作为单例模式的实现,或者放class的静态成员,比如工厂方法。

object Person {
  private var eyeNum = 2
  println("this Person object!")
  def getEyeNum = eyeNum
}

(2)伴生对象
如果有一个class,还有一个与class同名的object,那么就称这个object是class的伴生对象,class是object的伴生类,伴生类和伴生对象必须存放在一个.scala文件之中。伴生类和伴生对象,最大的特点就在于,互相可以访问private field。

object Person {
  private val eyeNum = 2
  def getEyeNum = eyeNum
}

class Person(val name: String, val age: Int) {
  def sayHello = println("Hi, " + name + ", I guess you are " + age + " years old!" + ", and usually you must have " + Person.eyeNum + " eyes.")
}

(3)让object继承抽象类
object的功能其实和class类似,除了不能定义接受参数的constructor之外,object也可以继承抽象类,并覆盖抽象类中的方法。

abstract class Hello(var message: String) {
  def sayHello(name: String): Unit
}

object HelloImpl extends Hello("hello") {
  override def sayHello(name: String) = {
    println(message + ", " + name)
  }
}

(4)apply方法
object中非常重要的一个特殊方法,就是apply方法,通常在伴生对象中实现apply方法,并在其中实现构造伴生类的对象的功能,而创建伴生类的对象时,通常不会使用new Class的方式,而是使用Class()的方式,隐式地调用伴生对象的apply方法,这样会让对象创建更加简洁。
比如,Array类的伴生对象的apply方法就实现了接收可变数量的参数,并创建一个Array对象的功能。

val a = Array(1, 2, 3, 4, 5)

比如,定义自己的伴生类和伴生对象。

class Person(val name: String)
object Person {
  def apply(name: String) = new Person(name)
}

(5)main方法
就如同java中,如果要运行一个程序,必须编写一个包含main方法类一样;在scala中,如果要运行一个应用程序,那么必须有一个main方法,作为入口。scala中的main方法定义为def main(args: Array[String]),而且必须定义在object中。

object HelloWorld {
  def main(args: Array[String]) {
    println("Hello World!!!")
  }
}

除了自己实现main方法之外,还可以继承App Trait,然后将需要在main方法中运行的代码,直接作为object的constructor代码;而且用args可以接受传入的参数。

object HelloWorld extends App {
  if (args.length > 0) println("hello, " + args(0))
  else println("Hello World!!!")
}

如果要运行上述代码,需要将其放入.scala文件,然后先使用scalac编译,再用scala执行。

scalac HelloWorld.scala
scala -Dscala.time HelloWorld

App Trait的工作原理为:App Trait继承自DelayedInit Trait,scalac命令进行编译时,会把继承App Trait的object的constructor代码都放到DelayedInit Trait的delayedInit方法中执行。
(6)用object来实现枚举功能
Scala没有直接提供类似于Java中的Enum这样的枚举特性,如果要实现枚举,则需要用object继承Enumeration类,并且调用Value方法来初始化枚举值。

object Season extends Enumeration {
  val SPRING, SUMMER, AUTUMN, WINTER = Value
}

还可以通过Value传入枚举值的id和name,通过id和toString可以获取; 还可以通过id和name来查找枚举值。

object Season extends Enumeration {
  val SPRING = Value(0, "spring")
  val SUMMER = Value(1, "summer")
  val AUTUMN = Value(2, "autumn")
  val WINTER = Value(3, "winter")
}
Season(0)
Season.withName("spring")

使用枚举object.values可以遍历枚举值

for (ele <- Season.values) println(ele)

猜你喜欢

转载自blog.csdn.net/gongxifacai_believe/article/details/81941692