第九讲 类

和java类似,scala也有类,而且概念相同不再赘述。

本章要点

  • 定义类
  • getter和setter
  • 对象私有属性
  • Bean属性
  • 构造器
  • 嵌套类

9.1 类的定义

scala简单类

class Counter {
  private var value: Int = 0;//你必须初始化字段
  def increment() {//方法默认是公有的
    value += 1
  }
  def current(): Int = {
    value
  }
}

在Scala中,类并不声明为public。Scala源文件可以包含多个类,所有这些类都具有公有可见性。使用该类需要做的就是构造对象并按照通常的方式来调用方法:

val myCounter=new Counter // 或new Counter()
myCounter.increment()//counter.increment;也可
println (myCounter.current) // counter.current()也可,结果为1

注意:调用无参方法比如current时,你可以写上圆括号,也可以不写,应该用哪一种形式呢,通常认为对于改值器方法,即改变对象状态的方法使用(),而对于取值器方法不会改变对象状态的方法去掉()是不错的风格。
可以通过不带()声明current的方式来强制这种风格:

 def current: Int = {
    value
  }

9.2 scala类的getter、setter

Scala对每个字端都提供getter和setter方法。在这里,我们定义一个公有字段:

class Person{
  var name="zhaosc";
}

Scala生成面向JVM的类,其中有一个name字段以及相应的getter方法和setter方法,这两个方法是公有(public)的,因为我们没有将name声明为private;而对私有字段而言,getter和setter方法也是私有的。
可以编译Person类,然后用javap查看字节码,如下:


信息.png

可以看到,编译器创建了name和name_$eq方法。=号被翻译成$eq,是因为JVM不允许在方法名中出现=,同时默认给出了一个无参的构造方法。

调用如下

    var person=new Person
    person.name="zsc"//setter
    print(person.name)//getter

说明:在Scala中,getter和setter方法并非被命名为getXxx和setXxx,不过它们的用意是相同的。后面会介绍如何生成Java风格的getXxx和setXxx方法,以使得你的Scala类可以与Java工具实现互操作。

重新定义getter、setter方法

为了便于理解scala的getter、setter此版本编写的,有点类似于java风格,不太建议,如下:

class Person{
  private var name="";
  def getName:String={
    this.name
  }
  def setName(name:String){
    this.name=name;
  }
}

调用

    var person=new Person
    person.setName("赵世超")
    println(person.getName)

scala风格版本:

class Person{
  private var nameStr="";
  def name:String={
    this.nameStr
  }
  def name_=(name:String){
    this.nameStr=name;
  }
}

调用

    var person=new Person
    person.name_=("赵世超")
    println(person.name)

注意:上文提到过Scala对每个字段生成getter和setter方法,不过你可以控制这个过程如下:

  • 如果字段是私有的,则getter和setter方法也是私有的
  • 如果字段是val,则只有getter方法被生成(val声明的是常量,常量一旦赋值,无法更改,所以无setter)
    例如:
class Person{
  private val nameStr="zhaosc";
}

它的编译信息如下:


信息.png

可见,只有getter没有setter;并且val字段,自动加final。

  • 如果你不需要任何getter或setter,可以将字段声明为private[this](下一小节讲解)

总结:
  1) var 变量: Scala自动合成一个getter和一个setter
  2) val 常量: Scala自动合成一个getter
  3) 自己定义变量(如:var name)的getter和setter (如:name和name_= 的方法)
   4) 自己定义getter(如:name方法)方法

但在Scala中,你不能实现只写属性,即只有setter但没有getter的属性。当你在Scala类中看到字段的时候,记住它和Java或c++中的字段不同。它是一个私有字段,加上getter方法(对val字段而言)或者getter和setter了法(对var字段而言),总之scala类中的字段必须有getter。

9.3 对象的私有属性

我们通常所说的属性一般都是类(class)的属性,私有属性也是类的私有属性,和java不同的是scala竟然有对象的私有属性。
声明方式是通过 private[this],对于对象的私有属性,Scala是不会生成getter或setter方法的。
例如:

class Person {
  private var name = "zhaosc";
  private[this] var default_salary = 100; //private[this]
  private var salary = default_salary;
  def raise(value: Int) {
    this.salary = this.default_salary + value;// default_salary 只能这么访问,其他方式报错
  }
  def info(p: Person) {
    print(p.name + p.salary)
  }
}

编译信息如下:


信息.png

可见对于对象的私有属性,Scala是不会生成getter或setter方法的。

另外:
Scala还允许将访问权赋予指定的类,private[类名] 修饰符可以定义仅有指定类的方法可以访问给定的字段。这里的类名必须是当前定义的类,或者是包含该类的外部类。在这种情况下,编译器会生成辅助的getter相setter方法,允许外部类访问该字段。这些类将会是公有的,因为JVM并没有更细粒度的访问控制系统,并且它们的名称也会随着JVM实现不同而不同。
用法和private[this]类似不在举例

9.4 Bean属性

scala虽然默认会为字段生成getter和setter方法,但是生成的方法名和我们的编程习惯却大不相同。
此时,可以通过@BeanProperty注解,这样的方法会自动生成,以实现和java代码风格一致

package com.study.scala
import scala.beans.BeanProperty
class Person {
  @BeanProperty
   var name:String=_;
}
object Person{
  def main(args: Array[String]): Unit = {
    var person=new Person;
    person.setName("zhaosc")
    print(person.getName())
  }
}

9.5 构造器

scala的构造器分为:主构造器和辅助构造器。
1、主构造器
每个类都有一个主构造器,scala的主构造器并不是以this来定义,而是和类的定义交织在一起。
如下:

package com.study.scala
import scala.beans.BeanProperty
class Person (var name:String,var age:Int){
}
object Person{
  def main(args: Array[String]): Unit = {
    val person=new Person("zhaosc",18);
    print("name:"+person.name+"   age:"+person.age)
  }
}

当然,也可以通过注解@BeanProperty,添加符合javabean规范的getter和stter方法。

package com.study.scala
import scala.beans.BeanProperty
class Person (@BeanProperty var name:String,@BeanProperty var age:Int){
}
object Person{
  def main(args: Array[String]): Unit = {
    val person=new Person("zhaosc",18);
    print("name:"+person.getName()+"   age:"+person.getAge())
  }
}

还可以通过在主构造器中使用默认参数来避免过多地使用辅助构造器。例如:

class Person (val name:String="",val age: Int =0 ){
}

TIPS:

  1. 构造参数也可以是普通的方法参数,不带val或var,这样的参数如何处理取决于它们在类中如何被使用。如果不带val或var的参数至少被一个方法所使用,它将被升格为字段。例如:
class Person(name: String, age: Int) {
  def description=name+"is"+age+"years old"
}

上述代码声明并初始化了不可变字段name和age,而这两个字段都是对象私有的。类似这样的字段等同于private[this] val字段的效果。否则,该参数将不被保存为字段。它仅仅是一个可以被主构造器中的代码访问的普通参数。严格地说,这是一个具体实现相关的优化。

  1. 如果定义类的时候,类名之后没有参数,则系统会默认提供一个无参构造。

2、辅助构造器
scala除了主构造器还有辅助构造器,一个类可以有任意多的辅助构造器。
 - 辅助构造器的名称为this。在Java或C++中,构造器的名称和类名相同,当你修改类名时就不那么方便了
 - 每一个辅助构造器都必须以一个对先前已定义的其他辅助构造器或主构造器的调用开始
例子,如下:

class Person {
 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
 }
}

9.6 嵌套类

在Scala中,你几乎可以在任何语法结构中内嵌任何语法结构。你可以在函数中定义函数,在类中定义类。
例子如下:

import scala.collection.mutable.ArrayBuffer
class Network {
  class Member(val name: String) {//Member嵌套类
   val contacts = new ArrayBuffer[Member]
  }
  private val members=new ArrayBuffer[Member]
  def join(name: String) ={
    val m=new Member(name)
    members+=m
    m
  }
}
val chatter = new Network
val myFace = new Network

在Scala中,每个实例都有它自己的Member类,也就是说,chatter.Member和myFace.Member是不同的两个类。
说明:
这和Java不同,在Java中内部类从属于外部类。
Scala采用的方式更符合常规,举例来说,要构建一个新的内部对象,你只需要简单的new这个类名:new chatter.Member。而在Java中,你需要使用一个特殊语法:chatter.new Member()。

Scala内嵌类访问
在内嵌类中,你可以通过外部类.this的方式来访问外部类的this引用,就像Java那样。如果你觉得需要,也可以用如下语法建立一个指向该引用的别名:

class Network(val name: String) { outer =>
  class Member(val name: String) {
    def dascription = "outside:" + outer.name+"  inside:"+ name
  }
}

object Network {
  def main(args: Array[String]): Unit = {
    val network = new Network("wuxian");
    val member=new network.Member("luyou")
     print(member.dascription)
  }
}

class Network { outer=>语法使得outer变量指向Network.this。对这个变量,你可以用任何合法的名称。

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

推荐阅读更多精彩内容