Scala學(xué)習(xí)筆記05_面向?qū)ο缶幊讨惡蛯?duì)象

定義一個(gè)簡單的類

// 定義類,包含field及方法
scala> :paste
// Entering paste mode (ctrl-D to finish)

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

// Exiting paste mode, now interpreting.

defined class HelloWorld
// 創(chuàng)建類的對(duì)象蚯窥,并調(diào)用其方法
scala> val helloWorld = new HelloWorld
helloWorld: HelloWorld = HelloWorld@380e4452
// 如果方法無參葵姥,可以不加括號(hào)颊咬,如果定義方法時(shí)不帶括號(hào),則調(diào)用方法時(shí)也不能帶括號(hào)
scala> helloWorld.sayHello()
Hello, leo
scala> helloWorld.sayHello
Hello, leo
scala> helloWorld.getName
res9: String = leo

scala> helloWorld.getName()
<console>:14: error: not enough arguments for method apply: (index: Int)Char in class StringOps.
Unspecified value parameter index.
       helloWorld.getName()
                         ^

getter與setter

定義不帶private的var field麸澜,此時(shí)scala生成的面向JVM的類時(shí)熟史,會(huì)定義為private的name字段碘菜,并提供public的getter和setter方法。

而如果使用private修飾field计雌,則生成的getter和setter也是private的。

如果定義val field眷细,則只會(huì)生成getter方法。

如果不希望生成setter和getter方法校读,則將field聲明為private[this]歉秫。

scala> class Student {
     | var name = "leo"
     | }
defined class Student

scala> val s = new Student
s: Student = Student@2a88981e
// 調(diào)用getter和setter方法钞螟,分別叫做name和name_=
scala> s.name
res0: String = leo

scala> s.name()
<console>:14: error: not enough arguments for method apply: (index: Int)Char in class StringOps.
Unspecified value parameter index.
       s.name()
             ^

scala> s.name = "jack"
s.name: String = jack

scala> s.name
res2: String = jack

scala> s.name_ = "jen"
<console>:15: error: value name_ is not a member of Student
val $ires1 = s.name_
               ^
<console>:13: error: value name_ is not a member of Student
       s.name_ = "jen"
         ^

自定義getter與setter

如果只是希望擁有簡單的getter和setter方法洞焙,那么就按照Scala提供的語法規(guī)則褒链,根據(jù)需求為field選擇合適的修飾符就好:var甫匹、val哀墓、private、private[this]吠各。

如果希望能夠自己對(duì)getter與setter進(jìn)行控制,則可以自定義getter與setter方法纵散。

自定義setter方法的時(shí)候一定要注意Scala的語法限制伍掀,簽名蜜笤、=把兔、參數(shù)間不能有空格县好。

scala> :paste
// Entering paste mode (ctrl-D to finish)

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

// Exiting paste mode, now interpreting.

<console>:14: error: not found: value newName
         def name_ = (newName:String) {
                      ^

scala> :paste
// Entering paste mode (ctrl-D to finish)

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

// Exiting paste mode, now interpreting.

defined class Student

scala> val s = new Student
s: Student = Student@4fc8cd5c

scala> val s = new Student()
s: Student = Student@1dafc862

scala> s.name
res3: String = your name is leo

scala> s.name = "leo1"
you cannot edit your name!s.name: String = your name is leo

僅暴露field的getter方法

如果不希望field有setter方法聘惦,則可以定義為val善绎,但是此時(shí)就再也不能更改field的值了禀酱。

如果希望能夠僅僅暴露出一個(gè)getter方法剂跟,并且還能通過某些方法更改field的值曹洽,那么需要綜合使用private以及自定義getter方法。此時(shí)税产,由于field是private的辟拷,所以setter和getter都是private衫冻,對(duì)外界沒有暴露隅俘,自己可以實(shí)現(xiàn)修改field值的方法,自己可以覆蓋getter方法。

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Student {
  private var myName = "leo"

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

  def name = "your name is " + myName
}

// Exiting paste mode, now interpreting.

defined class Student

scala> val s = new Student
s: Student = Student@3186acfb

scala> s.name
res4: String = your name is leo

scala> s.updateName("leo2")
not accept this new name, leo2

scala> s.updateName("leo1")

scala> s.name
res7: String = your name is leo1

private[this]的使用

如果將field使用private來修飾董朝,那么代表這個(gè)field是類私有的祟绊,在類的方法中遥赚,可以訪問類的其他對(duì)象的private field孕惜。這種情況下,如果不希望field被其他對(duì)象訪問到,那么可以使用private[this]丰榴,意味著對(duì)象私有的field,只有本對(duì)象內(nèi)可以訪問到戈二。

scala> :paste
// Entering paste mode (ctrl-D to finish)

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

// Exiting paste mode, now interpreting.

defined class Student

scala> val s1 = new Student
s1: Student = Student@7ba9d3ec

scala> s1.age = 20
s1.age: Int = 20

scala> val s2 = new Student
s2: Student = Student@2dd6713

scala> s2.age = 25
s2.age: Int = 25

scala> s1.older(s2)
res8: Boolean = false

private[this]的使用仆邓,只有本對(duì)象內(nèi)可以訪問到搞疗。

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Student {
  private[this] var myAge = 0
  def age_=(newAge:Int) {
    if(newAge>0) myAge = newAge
    else println("illegal age!")
  }
  def age = myAge
  def older(s:Student) = {
    myAge > s.myAge
  }
}

// Exiting paste mode, now interpreting.

<console>:23: error: value myAge is not a member of Student
           myAge > s.myAge
                     ^

Java風(fēng)格的getter和setter方法

Scala的getter和setter方法的命名與Java是不同的扳埂,是fieldfield_=的方式柜思。如果要讓Scala自動(dòng)生成Java風(fēng)格的getter和setter方法,只要給field添加@BeanProperty注解即可。此時(shí)會(huì)生成4個(gè)方法抛姑,name:String毫目、name_=(newValue:String):UnitgetName():StringsetName(newValue:String):Unit

scala> import scala.reflect.BeanProperty
<console>:13: error: object BeanProperty is not a member of package reflect
       import scala.reflect.BeanProperty
              ^

scala> import scala.beans.BeanProperty
import scala.beans.BeanProperty

scala> :paste
// Entering paste mode (ctrl-D to finish)

class Student {
  @BeanProperty var name:String = _
}

// Exiting paste mode, now interpreting.

defined class Student

scala> val s = new Student
s: Student = Student@1828b826

scala> s.setName("leo")

scala> s.getName()
res10: String = leo

scala> s.name = "jack"
s.name: String = jack

scala> s.name
res12: String = jack

在主構(gòu)造函數(shù)方式加注解,

scala> class Student(@BeanProperty var name:String)
defined class Student

scala> val s = new Student("leo")
s: Student = Student@148bf213

scala> s.getName()
res17: String = leo

scala> s.setName("jack")

scala> s.getName
res19: String = jack

scala> s.name
res20: String = jack

輔助constructor

Scala中,可以給類定義多個(gè)輔助constructor,類似于Java中的構(gòu)造函數(shù)重載,輔助constructor之間可以互相調(diào)用裹虫,而且必須第一行調(diào)用主constructor。

scala> :paste
// Entering paste mode (ctrl-D to finish)

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
  }
}

// Exiting paste mode, now interpreting.

defined class Student

scala> val s1 = new Student
s1: Student = Student@5eb6d96d

scala> val s2 = new Student("leo")
s2: Student = Student@b34c972

scala> val s3 = new Student("leo", 30)
s3: Student = Student@1182aa34

主constructor

Scala中,主constructor是與類名放在一起的,與Java不同,而且類中旭贬,沒有定義在任何方法或者是代碼塊之中的代碼稀轨,就是主constructor的代碼,這點(diǎn)感覺沒有Java那么清晰。

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

scala> val s = new Student
<console>:14: error: not enough arguments for constructor Student: (name: String, age: Int)Student.
Unspecified value parameters name, age.
       val s = new Student
               ^

scala> val s = new Student("leo", 30)
your name is leo, your age is 30
s: Student = Student@60cdee08

主construntor中還可以通過使用默認(rèn)參數(shù)雌澄,來給參數(shù)默認(rèn)的值。

scala> class Student(val name:String="leo", val age:Int=30) {
     |   println("your name is " + name + ", your age is " + age)
     | }
defined class Student

scala> val s = new Student
your name is leo, your age is 30
s: Student = Student@79eef059

如果主constructor傳入的參數(shù)什么修飾都沒有旗唁,比如name:String参袱,那么如果類內(nèi)部的方法使用到了,則會(huì)聲明為private[this] name,否則沒有該field,就只能被constructor代碼使用而已攒读。

scala> class Student(name:String="leo", age:Int=30) {
     |   println("your name is " + name + ", your age is " + age)
     | }
defined class Student

scala> val s = new Student("leo", 30)
your name is leo, your age is 30
s: Student = Student@115989a9

scala> s.name
<console>:14: error: value name is not a member of Student
       s.name
         ^

內(nèi)部類

Scala中邓梅,同樣可以在類中定義內(nèi)部類殿遂,但是與Java不同的是,每個(gè)外部類的對(duì)象的內(nèi)部類,都是不同的類邑飒。

c2.Student類风科,c1.Student類,是不同的外部類的實(shí)例的不同的類顶瞳。

scala> :paste
// Entering paste mode (ctrl-D to finish)

import scala.collection.mutable.ArrayBuffer

class Class {
  class Student(val name:String)
  val students = new ArrayBuffer[Student]()
  def getStudent(name:String) = {
    new Student(name)
  }
}

// Exiting paste mode, now interpreting.

import scala.collection.mutable.ArrayBuffer
defined class Class

scala> val c1 = new Class
c1: Class = Class@7d6340d6

scala> val s1
     |  = c1.getStudent("leo")
s1: c1.Student = Class$Student@2662e5cf

scala> c1.students += s1
res1: c1.students.type = ArrayBuffer(Class$Student@2662e5cf)

scala> val c2 = new Class
c2: Class = Class@d207f78

scala> val s2 = c2.getStudent("leo")
s2: c2.Student = Class$Student@56de11b8

scala> c1.students += s2
<console>:19: error: type mismatch;
 found   : c2.Student
 required: c1.Student
       c1.students += s2
                      ^

object

object,相當(dāng)于class的單個(gè)實(shí)例备蚓,通常在里面放一些靜態(tài)的field或者method扎即,第一次調(diào)用object的方法時(shí)谚鄙,就會(huì)執(zhí)行object的constructor闷营,也就是object內(nèi)部不在method中的代碼傻盟,但是object不能定義接受參數(shù)的constructor规哲。

object的constructor只會(huì)在其第一次被調(diào)用時(shí)執(zhí)行一次唉锌,以后再次調(diào)用就不會(huì)再次執(zhí)行constructor了糊秆。

object通常用于作為單例模式的實(shí)現(xiàn),或者放class的靜態(tài)成員汞舱,比如工具方法。

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

scala> Person.getEyeNum
this is Person object constructor is execting
res4: Int = 2

scala> Person.getEyeNum
res5: Int = 2

伴生對(duì)象

如果有一個(gè)class,還有一個(gè)與class同名的object欢际,那么就稱這個(gè)object是class的伴生對(duì)象损趋,class是object的伴生類桐玻。伴生類和伴生對(duì)象必須存放在一個(gè).scala文件之中,伴生類和伴生對(duì)象褪子,最大的特點(diǎn)在于,互相可以訪問private field刻坊。

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

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

scala> val p = new Person("leo", 30)
p: Person = Person@6b1e9a68

scala> p.sayHello
Hi, leois30years old, and you have 2 eyes.
# 伴生類里面可以訪問伴生對(duì)象的private field,在外面不行。
scala> Person.eyeNum
<console>:15: error: value eyeNum is not a member of object Person
       Person.eyeNum
              ^

object繼承抽象類

object的功能和class類似,除了不能定義接收參數(shù)的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)
  }
}

scala> HelloImpl.sayHello("leo")
hello,leo

apply方法

object中重要的一個(gè)特殊方法,apply方法忙厌,通常在伴生對(duì)象中實(shí)現(xiàn)apply方法,并在其中實(shí)現(xiàn)構(gòu)造伴生類的對(duì)象的功能挟阻。而創(chuàng)建伴生類的對(duì)象時(shí),通常不會(huì)使用new Class的方式惯雳,而是使用Class()的方式,隱式調(diào)用伴生對(duì)象的apply方法挨决,讓對(duì)象創(chuàng)建更簡潔眼虱。如Array類的伴生對(duì)象的apply方法就實(shí)現(xiàn)了接收可變數(shù)量的參數(shù),并創(chuàng)建一個(gè)Array對(duì)象的功能庙洼。

scala> val a = Array(1,2,3)
a: Array[Int] = Array(1, 2, 3)

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

scala> val p1 = new Person("leo")
p1: Person = Person@78f71925

scala> val p2 = Person("leo")
p2: Person = Person@d5b8b3f

scala> p2.name
res10: String = leo

main方法

在Scala中,main方法作為應(yīng)用程序的入口,Scala中的main方法定義為def main(args:Array[String])发乔,而且必須定義在object中纵菌。

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

scala> HelloWorld.main(_)
res15: Array[String] => Unit = <function1>

除了自己實(shí)現(xiàn)main方法围来,還可以繼承App Train醇滥,然后將需要在main方法中運(yùn)行的代碼购城,直接作為object的constructor代碼,而且用args可以接受傳入的參數(shù)薄坏。

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

AppTrait繼承自DelayedInit Trait矮瘟,scalac命令進(jìn)行編譯時(shí)写妥,會(huì)把繼承App Trait的object的consturctor代碼都放到DelayedInit Trait的delayedInit方法中執(zhí)行症脂。

用object實(shí)現(xiàn)枚舉功能

Scala沒有直接提供類似于Java的Enum枚舉特性,如果要實(shí)現(xiàn)枚舉,則需要用object繼承Enumeration歪沃,并且調(diào)用Value方法來初始化枚舉值。

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

scala> Season.SPRING
res1: Season.Value = SPRING

還可以通過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")
}

scala> Season.SPRING.id
res2: Int = 0

scala> Season.SPRING.toString
res3: String = spring

scala> Season(0)
res4: Season.Value = spring

scala> Season.withName("winter")
res5: Season.Value = winter

scala> for(ele <- Season.values) println(ele)
spring
summer
autumn
winter

本文首發(fā)于steem魔策,感謝閱讀擂橘,轉(zhuǎn)載請(qǐng)注明灾馒。

https://steemit.com/@padluo


微信公眾號(hào)「padluo」古涧,分享數(shù)據(jù)科學(xué)家的自我修養(yǎng),既然遇見昔字,不如一起成長啸罢。

數(shù)據(jù)分析

讀者交流電報(bào)群

https://t.me/sspadluo


知識(shí)星球交流群

知識(shí)星球讀者交流群
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鹦牛,一起剝皮案震驚了整個(gè)濱河市汉规,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌篷就,老刑警劉巖未辆,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拙友,死亡現(xiàn)場離奇詭異病曾,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人渊季,你說我怎么就攤上這事朋蔫∏嗳樱” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵凛剥,是天一觀的道長轻姿。 經(jīng)常有香客問我,道長炊昆,這世上最難降的妖魔是什么医窿? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任渣聚,我火速辦了婚禮症歇,結(jié)果婚禮上闰蛔,老公的妹妹穿的比我還像新娘。我一直安慰自己钞护,他們只是感情好盖喷,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著难咕,像睡著了一般课梳。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上余佃,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天暮刃,我揣著相機(jī)與錄音,去河邊找鬼爆土。 笑死椭懊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的步势。 我是一名探鬼主播氧猬,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼坏瘩!你這毒婦竟也來了盅抚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤倔矾,失蹤者是張志新(化名)和其女友劉穎妄均,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哪自,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丰包,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了壤巷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片邑彪。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖胧华,靈堂內(nèi)的尸體忽然破棺而出锌蓄,到底是詐尸還是另有隱情升筏,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布瘸爽,位于F島的核電站您访,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏剪决。R本人自食惡果不足惜灵汪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望柑潦。 院中可真熱鬧享言,春花似錦、人聲如沸渗鬼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽譬胎。三九已至差牛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間堰乔,已是汗流浹背偏化。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留镐侯,地道東北人侦讨。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像苟翻,于是被迫代替她去往敵國和親韵卤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 其實(shí)生活中有很多事是我們不想讓它發(fā)生卻又實(shí)實(shí)在在發(fā)生了的崇猫。 這真的不是我們自己能掌控的事情沈条。像不小心弄灑的咖啡,像...
    王怪人閱讀 279評(píng)論 2 0
  • 淺淺的呼吸 香甜在別人的夢里 無眠是獨(dú)屬你的深夜
    水筆仔o12530閱讀 116評(píng)論 0 1