Scala入門到精通——第六節:類和物件(一)
本節主要內容
1 類定義、建立物件
2 主構造器
3 輔助構造器
類定義、建立物件
//採用關鍵字class定義
class Person {
//類成員必須初始化,否則會報錯
//這裡定義的是一個公有成員
var name:String=null
}
Person類在編譯後會生成Person.class檔案
利用javap -prviate Person命令檢視位元組碼檔案內容,可以看得到以下內容
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二進位制檔案Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
public java.lang.String name();
public void name_$eq(java.lang.String);
public cn.scala.xtwy.Person();
}
從位元組碼檔案內容可以看到:雖然我們只在Person類中定義了一個類成員(域)name,型別為String,但Scala會預設幫我們生成name()與name_=()及建構函式Person()。其中name()對應java中的getter方法,name_=()對應java中的setter方法(由於JVM中不允許出現=,所以用$eq代替。值得注意的是定義的是公有成員,但生成的位元組碼中卻是以私有的方式實現的,生成的getter、setter方法是公有的
因此,可以直接new操作建立Person物件
//預設已經有構建函式,所以可以直接new
scala> val p=new Person()
p: Person = Person@84c504
//直接呼叫getter和setter方法
//setter方法
scala> p.name_=("john")
//getter方法
scala> p.name
res2: String = john
//直接修改,但其實呼叫的是p.name_=("jonh")
scala> p.name="jonh"
p.name: String = jonh
//getter方法
scala> p.name
res28: String = jonh
你也可以定義自己的getter和setter方法
class Person{
//定義私有成員
private var privateName:String=null;
//getter方法
def name=privateName
//setter方法
def name_=(name:String){
this.privateName=name
}
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二進位制檔案Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String privateName;
private java.lang.String privateName();
private void privateName_$eq(java.lang.String);
public java.lang.String name();
public void name_$eq(java.lang.String);
public cn.scala.xtwy.Person();
}
從生成的位元組碼中可以看出:(1)定義成私有成員,其getter、setter方法也是私有的;(2)直接能訪問的是我們自己定義的getter、setter方法。下面給出的是呼叫方式
scala> val p=new Person()
p: Person = Person@12d0b54
scala> p.name
res29: String = null
//直接賦值法
scala> p.name="john"
p.name: String = john
scala> p.name
res30: String = john
從程式碼執行產生的結果,我們可以知道:通過p.name=“john”這種方式進行賦值,呼叫者並不需要知道是其通過方法呼叫還是欄位訪問來進行操作的,這便是著名的統一訪問原則
如果類的成員域是val型別的變數,則只會生成getter方法
class Person {
//類成員必須初始化,否則會報錯
//這裡定義的是一個val公有成員
val name:String="john"
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二進位制檔案Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private final java.lang.String name;
public java.lang.String name();
public cn.scala.xtwy.Person();
}
從位元組碼檔案中可以看出:val變數對應的是java中的final型別變數,只生成了getter方法
如果將成員域定義為private[this],則不會生成getter、setter方法
class Person {
//類成員必須初始化,否則會報錯
//private[this]修飾
private[this] var name:String="john"
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二進位制檔案Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
public cn.scala.xtwy.Person();
}
在java語言當中,在定義JavaBean的時候生成的都是setXxx()、getXxx()方法,但scala語言生成的getter方法和setter方法並不是這樣的,如果也需要程式自動會生成getter方法和setter方法,則需要引入 scala.reflect.BeanProperty
然後採用註解的方式修飾變數
class Person {
//類成員必須初始化,否則會報錯
//@BeanProperty用於生成getXxx,setXxx方法
@BeanProperty var name:String="john"
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二進位制檔案Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
public java.lang.String name();
public void name_$eq(java.lang.String);
public void setName(java.lang.String);
public java.lang.String getName();
public cn.scala.xtwy.Person();
}
下圖給出的是getter、setter方法產生的規則
來源:scala for the impatient
類主構造器
主構造器的定義與類的定義交織在一直,將構造器引數直接放在類名稱之後,如下程式碼:
//下列程式碼不但定義了一個類Person,還定義了主構造器,主構造器的引數為String、Int型別
class Person(val name:String,val age:Int)
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二進位制檔案Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private final java.lang.String name;
private final int age;
public java.lang.String name();
public int age();
public cn.scala.xtwy.Person(java.lang.String, int);
}
//不難看出:上面的程式碼與下列java語言編寫的程式碼等同
public class Person{
private final String name;
private final int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String getName(){ return name}
public int getAge() {return age}
}
//具體使用操作如下:
scala> val p=new Person("john",29)
p: Person = Person@abdc0f
scala> p.name
res31: String = john
scala> p.age
res32: Int = 29
主構造器會執行類定義中的所有語句,例如
//當在建立物件時,需要進行相關初始化操作時,可以將初始化語句放在類體中,同樣也可以在類中新增或重寫相關方法
class Person(val name:String,val age:Int){
//println將作為主構建器中的一部分,在建立物件時被執行
println("constructing Person ........")
//重寫toString()方法
override def toString()= name + ":"+ age
}
scala> val p=new Person("john",29)
constructing Person ........
p: Person = john:29
回過頭來看的話,前面我們定義的Person類是一種無參主構建器
//Person類具有無參主構建器
class Person {
println("constructing Person....")
val name:String="john"
}
scala> val p=new Person()
constructing Person....
p: Person = [email protected]79895f
主構建器還可以使用預設引數
//預設引數的主構建器
class Person(val name:String="",val age:Int=18){
println("constructing Person ........")
override def toString()= name + ":"+ age
}
scala> val p=new Person
constructing Person ........
p: Person = :18
scala> val p=new Person("john")
constructing Person ........
p: Person = john:18
主構造器中的引數還可以加訪問控制符
//預設引數的主構建器,引數帶訪問控制符號
//age變成私有成員,其getter方法是私有的,外部不能訪問
class Person(val name:String="",private val age:Int=18){
println("constructing Person ........")
override def toString()= name + ":"+ age
}
當主構造器的引數不用var或val修飾的時候,引數會生成類的私有val成員,並且不會產生getter和setter方法
//不加變數修飾符
class Person(name:String,age:Int){
println("constructing Person ........")
override def toString()= name + ":"+ age
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二進位制檔案Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private final java.lang.String name;
private final int age;
public java.lang.String toString();
public cn.scala.xtwy.Person(java.lang.String, int);
}
//與下面類定義等同
class Person(private[this] val name:String,private[this] val age:Int){
println("constructing Person ........")
override def toString()= name + ":"+ age
}
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二進位制檔案Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private final java.lang.String name;
private final int age;
public java.lang.String toString();
public cn.scala.xtwy.Person(java.lang.String, int);
}
值得注意的是,將上述Person類中的toString()方法去掉,則類中無任何地方使用了主構造器的引數,此時主構造器引數不會生成類成員
即將
//不加變數修飾符
class Person(name:String,age:Int){
println("constructing Person ........")
override def toString()= name + ":"+ age
}
改成:
class Person( val name:String,age:Int){
println("constructing Person ........")
}
其位元組碼檔案如下:
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二進位制檔案Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
public cn.scala.xtwy.Person(java.lang.String, int);
}
//可以看出,主構造器引數不會生成類成員
下面圖給出了Scala中主構建器引數生成類成員和方法時的規則
來源:scala for the impatient
在某些情況下,可能需要禁用主構建器,程式碼如下:
//類名後面緊跟private關鍵字可以將主構建器設為私有,不允許外部使用
class Person private(var name:String,var age:Int){
println("constructing Person ........")
}
//生成的位元組碼檔案如下,可以看到其構建函式已經為private了
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二進位制檔案Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
private int age;
public java.lang.String name();
public void name_$eq(java.lang.String);
public int age();
public void age_$eq(int);
private cn.scala.xtwy.Person(java.lang.String, int);
}
//此時不能直接這麼用
scala> val p=new Person("john",19)
<console>:9: error: constructor Person in class Person cannot be accessed in obj
ect $iw
val p=new Person("john",19)
^
輔助建構函式
前面講了,如果禁用掉了主構建器,則必須使用輔助建構函式來建立物件。輔助建構函式具有兩個特點:(1)輔助構建器的名稱為this,java中的輔助建構函式與類名相同,這常常會導致修改類名時出現不少問題,scala語言避免了這樣的問題;(2)呼叫輔助建構函式時,必須先呼叫主建構函式或其它已經定義好的建構函式。
3.1 我們首先看一下只有輔助建構函式的Person類
//只有輔助建構函式的類
class Person{
//類成員
private var name:String=null
private var age:Int=18
private var sex:Int=0
//輔助構造器
def this(name:String){
this()
this.name=name
}
def this(name:String,age:Int){
this(name)
this.age=age
}
def this(name:String,age:Int,sex:Int){
this(name,age)
this.sex=sex
}
}
//位元組碼檔案
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二進位制檔案Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
private int age;
private int sex;
private java.lang.String name();
private void name_$eq(java.lang.String);
private int age();
private void age_$eq(int);
private int sex();
private void sex_$eq(int);
public cn.scala.xtwy.Person();
public cn.scala.xtwy.Person(java.lang.String);
public cn.scala.xtwy.Person(java.lang.String, int);
public cn.scala.xtwy.Person(java.lang.String, int, int);
}
//在定義輔助建構函式時,需要注意建構函式的順序
class Person{
//類成員
private var name:String=null
private var age:Int=18
private var sex:Int=0
//輔助構造器
def this(name:String,age:Int,sex:Int){
this(name,age)//此處會發生編譯錯誤,這是因為def this(name:String,age:Int)沒有被定義
this.sex=sex
}
def this(name:String){
this()
this.name=name
}
def this(name:String,age:Int){
this(name)
this.age=age
}
}
3.2 帶主建構函式、輔助建構函式的Person類
//具有主構建函式和輔助構建函式的Person類
class Person(var name:String,var age:Int){
//類成員
private var sex:Int=0
//輔助構造器
def this(name:String,age:Int,sex:Int){
this(name,age)
this.sex=sex
}
}
生成的位元組碼檔案如下:
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二進位制檔案Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
private int age;
private int sex;
public java.lang.String name();
public void name_$eq(java.lang.String);
public int age();
public void age_$eq(int);
private int sex();
private void sex_$eq(int);
public cn.scala.xtwy.Person(java.lang.String, int);
public cn.scala.xtwy.Person(java.lang.String, int, int);
}
在主建構函式小節當中我們提到,有時候可能會禁用掉主建構函式,此時只能通過輔助建構函式來建立物件
//禁用主建構函式
class Person private(var name:String,var age:Int){
//類成員
private var sex:Int=0
//輔助構造器
def this(name:String,age:Int,sex:Int){
this(name,age)
this.sex=sex
}
}
//其位元組碼檔案內容如下
D:\ScalaWorkspace\ScalaChapter06\bin\cn\scala\xtwy>javap -private Person
警告: 二進位制檔案Person包含cn.scala.xtwy.Person
Compiled from "Person.scala"
public class cn.scala.xtwy.Person {
private java.lang.String name;
private int age;
private int sex;
public java.lang.String name();
public void name_$eq(java.lang.String);
public int age();
public void age_$eq(int);
private int sex();
private void sex_$eq(int);
private cn.scala.xtwy.Person(java.lang.String, int);
public cn.scala.xtwy.Person(java.lang.String, int, int);
}
新增公眾微訊號,可以瞭解更多最新Spark、Scala相關技術資訊