scala學習手記12 - 字段、方法和構造函數


在上一節創建了一個scala類,如果沒有更多的方法,scala類的定義還可以更簡單一些,看一下下面這個CreditCard類的定義:

class CreditCard(val number: Int, var creditLimit: Int)

是的,只用一行就完成了類的定義,連大括號都不需要。

因為scala也是運行在JVM上,可以考慮以java的方式來看看編譯后的類文件。查看的方式還是比較靈活的,可以使用JD-GUI,也可以使用javap –private CreditCard命令,還有一個在線反編譯的網站ShowMyCode。反編譯后的Java代碼:

public class CreditCard {

  public int number() {
    return number;
  }

  public int creditLimit() {
    return creditLimit;
  }

  public void creditLimit_$eq(int x$1) {
    creditLimit = x$1;
  }

  public CreditCard (int number, int creditLimit) {
    this.number = number;
    this.creditLimit = creditLimit;
    super ();
  }

  private final int number;
  private int creditLimit;
}

好長的java代碼。首先scala默認將CreditCard類轉換為了public。因為在CreditCard.scala中將number聲明為val,所以在反編譯生成的java代碼中,number被定義為final。此外在編譯后的代碼中還可以看到一個構造器以及讀寫成員變量的方法。可以看到成員變量的getter和setter與我們在java中習慣使用的命名方式有些不一致。此外由於number有final修飾符,因此就沒有它的setter方法。如果scala中的成員變量的定義符號既不是var也不是val,那Scala就會為之創建一個private字段以及private getter和setter方法,也因此不能在類外部訪問這個成員變量了。

放到類定義中的所有可執行語句或表達式都會被視為類的構造器的組成部分。下面的代碼就是一個示例:

class Sample {
  println("You are constructing an instance of Sample")
}

new Sample

在這段代碼中先定義了一個類Sample,隨后又創建了一個Sample類的實例,執行看一下:

image

在創建實例的時候輸出了類定義中的print語句,因為這段print語句是構造器的一部分。

除了在主構造函數中提供成員變量,我們還可以在類里面定義其他字段、方法、零個或多個副構造函數。在下面這個類中在類里面定義了一個成員變量position、一個副構造函數this()、並且重寫了toString()方法。

class Person(val firstName: String, val lastName: String) {

  private var position: String = _

  println("Creating " + toString())

  def this(firstName: String, lastName: String, positionHeld: String) {
    this(firstName, lastName)
    position = positionHeld
  }

  override def toString(): String = {
    firstName + "" + lastName + " holds " + position + " position "
  }
}

val john = new Person("John", "Smith", "Analyst")
println(john)
val bill = new Person("Bill", "Walker")
println(bill)

執行代碼的結果如下:

image

稍稍關注下副構造函數的實現:如果有主構造函數的話,那么副構造函數的第一行必須是主構造函數或者其它副構造函數的調用。這一點倒是和java繼承父類時有點相似。

此外還值得注意的就是成員變量position的定義,把這一行單獨拎出來看看吧:

private var position: String = _

首先比較有趣的是初始化賦值,賦值是一個“_”——下划線。在這里“_”代表相應類型的默認值。對於Int,它的值是0;對於Double,它的值是0.0;對於String,它的值就是null。通過使用“_”,可以很方便地為var成員變量設置初始默認值。不過不能為val成員使用“_”,因為val成員不允許修改,所以必須顯式指定初始值

通過查看Person.scala的字節碼反編譯出來的java類,可以看到scalac編譯器為成員變量position默認設置了getter和setter方法(雖然沒有按照我們習慣的JavaBean的方式進行設置)。scala中定義的成員變量的可見性在反編譯出來的Java代碼中由getter和setter方法的訪問權限來控制。

如果更喜歡傳統的JavaBean式的注解,可以在成員變量定義時添加注解@BeanProperty:

@BeanProperty  var position: String = _

聲明前記得導入注解。不過這也有一點限制:此時成員變量不可再聲明為private。而且這樣做只是會再額外生成兩個JavaBean式的getter和setter,原來的getter和setter也會繼續保留。這可以在編譯Person類以后再用javap –private驗證一下:

image

就是這樣。

#######


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM