1. 程式人生 > >Scala筆記整理(三):Scala面向對象—類詳解1

Scala筆記整理(三):Scala面向對象—類詳解1

大數據 Scala

[TOC]


getter和setter

簡單類和無參方法

需要說明的是,官方給出的參考資料對於這方面講解得十分詳細,目前入門來說,不需要達到這樣的理解,只需要可以進行開發即可,這一部分我給出的是官方的一些文檔說明,但是後面的定制和註解,就直接簡單說明能用就好了。

class PersonOps {
    private var age = 0 //你必須初始化一個字段
    def increment() {age += 1} //方法默認是公有的
    def currentAge() = age
}

1)在Scala中,類並不聲明為public。Scala源文件可以包含多個類,所有這些類都具有公有可見性。

2)如何進行調用?

object MainOps{
    def main(args: Array[String]) {
        val personOps = new PersonOps
        personOps.increment()
        println("currentAge=> " + personOps.currentAge())
    }
}

3)不能用類直接調用age,因為age是私有字段,只能在PersonOps中訪問到。

4)無參方法

println("currentAge=>" + personOps.currentAge())
println("currentAge=>" + personOps.currentAge)

建議:對設置值的時候,即改變對象狀態值或者狀態時使用(),而對於取值來說(不會改變對象的狀態和值)去掉()是個不錯的風格,這也是我們事例中的方法。

personOps.increment()
println("currentAge=> " + personOps.currentAge)

5)你可以通過以不帶()的方式聲明currentAge來強制這種風格:

class PersonOps {
    private var age = 0 //你必須初始化一個字段
    def increment() {age += 1} //方法默認是公有的
    def currentAge = age
}

結果:這樣一來在調用時,必須要用不帶()的進行方法調用

println("currentAge=>" + personOps.currentAge)

6)帶getter和setter的屬性

Java中屬性定義

public class PersonAge{ //這是Java
    private int age;
    public int getAge() { return age; }
    public void setAge(int age) { this.age=age; }
}

getter和setter方式比共有字段(public)好在什麽地方呢?

之所以說getter和setter方法比公有字段更好,是因為它們讓你可以從簡單的get/set機制出發,並在需要的時候做改進。

5)scala中的getter和setter方法

class PersonA{
    var age = 0
}

a.Scala生成面向JVM的類,其中有一個私有的age字段以及相應的getter方法和setter方法。這兩個方法是公有的,因為我們沒有將age聲明為private。而對私有字段而言,getter和setter方法也是私有的。

a.在Scala中,getter和setter分別叫做age和age_=例如:

val personA = new PersonA
println("startAge=> " + personA.age)
personA.age = 21
println("endAge=> " + personA.age)

執行下面的命令:

Scalac PersonOps.scala
\src\main\scala\tw\tw>javap -p PersonA.class
Compiled from "PersonOps.scala"

然後會生成下面的內容:

public class tw.PersonA {
    private int age;
    public int age();
    public void age_$eq(int);
    public tw.PersonA();
}

正如你看到的那樣,編譯器創建了ageage_$eq,是因為JVM不允許在方法名中出現=

說明:在Scala中,getter和setter方法並非被命名為getXxx和setXxx,不過它們的用意是相同的。後面會介紹如何生成Java風格的getXxx和setXxx方法,以使得你的Scala類可以與Java工具實現互操作

定制的getter/setter方法

這部分先不用搞太復雜,直接使用Java版本的getter/setter方法即可,如下面一個類:

class Student {
  private var age:Int = 0

  def setAge(age:Int): Unit = {
    this.age = age
  }

  def getAge() = age

}

測試如下:

scala> val s = new Student()
s: Student = Student@1608bb5d

scala> s
res200: Student = Student@1608bb5d

scala> s.getAge()
res201: Int = 0

scala> s.getAge
res202: Int = 0

scala> s.setAge(18)

scala> s.getAge
res204: Int = 18

官方關於getter/setter的知識內容非常多,入門的時候這些案例可以先不用管,先從Java的角度出來能夠使用scala進行開發即可。

@BeanProperty註解

如果對屬性使用了@BeanProperty註解,那麽就會自動生成getter/setter方法,但是需要註意的是,其並沒有隱藏原來的屬性,也就是說原來的屬性還是可以直接訪問的,並且其不可以使用private進行修飾。

看下面一個例子:

import scala.beans.BeanProperty
class Student {
  @BeanProperty var age:Int = 0 
}

測試如下:

scala> var s = new Student
s: Student = Student@46482990

scala> s.getAge()
res205: Int = 0

scala> s.setAge(18)

scala> s.getAge()
res207: Int = 18

scala> s.age
res208: Int = 18

總結

上面啰嗦了很多,其實直接用下面的代碼來進行說明就OK了:

/**
  * scala面向對象第一章
  *     關於對象的構造
  *     類的構造(和java一樣)
  *
  *   要運行一個scala的程序,不能在class來執行,需要在object中執行
  *   你可以將這個object中的所有的字段、成員,都作為java中的靜態的成員對待
  *
  *   在創建scala函數的時候,如果函數空參,我們可以在創建的時候省略掉這個(),但是在訪問的時候也就不能使用帶()的方式
  *   反之我們既可以使用帶(),也可以使用不帶()的方式進行調用
  *   ab.foreach(println)
  *
  *   為什麽我們要在javabean對字段創建對應的getter和setter
  *     帶getter和setter的屬性
  *       就是為了程序的安全性?
  *         屏蔽一些不合法的操作,提高程序的健壯性
  */
object _01ClazzFieldsOps {
    def main(args: Array[String]): Unit = {
        val person:Person = new Person()
        person.increment()
        println(person.currentAge())
        println(person.currentAge)

        val stu = new Student

//        stu.age = -1
        stu.setAge(-4)
        stu.getName

        val e = new Employee
    }
}

class Person {
    private var age:Int = 0 //創建一個類型為Int的私有化成員

    def increment(): Unit = {
        age += 1
    }

    def currentAge() = age
}

class Student {
    private var age:Int = 15

    private var name:String = "劉向前"
    def setAge(a:Int):Unit = {
        if(a < 1) {
            throw new RuntimeException(s"你們家的孩子才是($a)歲呢")
        }
        age = a
    }
    def getAge = age
    def getName = name
}

class Employee {
    @BeanProperty var age:Int = 5
}

構造器

關於構造器的說明和使用,直接看下面的測試代碼就可以了,非常簡潔:

package cn.xpleaf.bigdata.p2.constructor

/**
  * scala中的類的構造器說明
  *   scala類的構造器分為主構造器和輔助構造器
  *   其構造方式不同於java中的構造方式,public 類名(參數列表){},在scala中的構造器如何定義?
  * scala中把類名後面的一對{}括起來的內容稱為主構造器的函數體,默認的主構造器為空參構造器,
  *   如何定義一個有參的主構造器呢?
  *   就在類名後面寫上函數的定義即可
  *
  *   當主構造器滿足不了我們的需求之後,我們就可以創建更多的輔助構造器來配合我們的業務,輔助構造器如何創建?
  *   def this  // 輔助構造器的函數名是this
  *   註意,在輔助構造中的第一句話,必須是調用該類的主構造器或者其他輔助構造器,this(參數)
  *   
  *   在一個類中只能有一個主構造器,可以有若幹輔助構造器,在輔助構造器的第一句話,調用this
  *
  */
object _02ConstructorOps {
  def main(args: Array[String]): Unit = {
    val p = new Person
    // p.show()
    println("=================================")
    val stu = new Student("前向劉", 17)
    stu.show()
    println("=================================")
    val s = new Student
    println("=================================")
    val s1 = new Student(true)
  }
}

class Person {
  private var name:String = "劉向前"
  private var age:Int = 18

/*  def Person(n:String, a:Int): Unit = {
    name = n
    age = a
    println("這是scala中的構造器嗎?")
  }

  def Person(): Unit = {
    println("這是scala中的構造器嗎?")
  }*/

  println("這是scala中的構造器嗎?")

  def show() = println(s"name is $name and age is $age")
}

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

  def this() {
    this("劉銀鵬", 25)
    println("this is 輔助構造器")
  }

  private  var married:Boolean = false
  def this(isMarried:Boolean) {
    this()
    married = isMarried
    println(s"this($isMarried) 是另外一個構造器")
  }

  println("這是scala中的構造器嗎?")
  def show() = println(s"name is $name and age is $age")
  // show() // 類構造時就會執行該方法,屬性name和age也是默認有的,因為在主構造器中有
}

內部類

直接看下面的一個完整案例:

package cn.xpleaf.bigdata.p2.inner

/**
  * 事物的內部還包含著事物,被包含的事物不能使用非常簡單的成員變量來描述,只能使用更為復雜的結構去描述,
  * 這個時候就用我們的內部類去定義
  *
  * 當多個變量重名的時候,遵循一個原則:局部優先
    public class InnerClassOps {
        public static void main(String[] args) {
            Outer.Inner i = new Outer().new Inner();
            i.show();
        }
    }
    class Outer {
        private int x = 5;

        class Inner {
            private int x = 6;
            public void show() {
                int x = 7;
                System.out.println("Inner show: " + x);
            }
        }
    }

  this關鍵字,是本類的引用,當前類的實例的引用
  外部類的引用使用外部類名.this
  scala同樣提供了一種較為簡潔的寫法,就是在我們的最外層大括號裏寫一個引用名稱outer =>
  在內部類中需要調用外部類的成員的時候,直接使用outer.成員代替外部類名.this
  */
object _03InnerClassOps {
  def main(args: Array[String]): Unit = {
    val outer = new Outer
    val inner = new outer.Inner
    inner.show()
  }
}

class Outer { o =>
  private val x = 5

  class Inner { i =>
    private var x = 6
    def show(): Unit = {
      val x = 7
      println("Inner show: " + this.x)  // 6
      println("Inner show: " + i.x)     // 6
      println("Inner show: " + Outer.this.x)  // 5
      println("Inner show: " + o.x)           // 5
    }
  }
}

Scala筆記整理(三):Scala面向對象—類詳解1