您好,登錄后才能下訂單哦!
魯春利的工作筆記,好記性不如爛筆頭
1、擴展類
extends是Scala中實現繼承的保留字;
class week extends month{......}
week類繼承了month類所有非私有成員;
week類是month類的子類,month類是week類的超類;
子類能重寫超類的成員(字段、方法);
class week(val num : Int) extends month(val num : Int) {......}
單例對象同樣能從類中繼承,與類的繼承語法相同:object day extends week {......}
重寫
Scala中使用override保留字進行方法、字段重寫
class week extends month { override def firstday () {......} }
override保留字聲明其后的字段或方法是對超類的重寫,也可以寫在類定義參數中。
class week (override val lastday : String) extends month(val lastday : String)
重新定義的字段和方法不可重寫(override),方法不同(參數類型或個數)不可重寫。
scala> class month { | def secondary(m : String) { | println("secondary is " + m); | } | } defined class month scala> scala> class week extends month { | override def secondary(m : String) { // 重寫該方法 | println("secondary is " + m); | } | } defined class week
2、重寫規則
重寫def
用val:利用val能重寫超類沒有參數的方法;
用def:子類方法與超類成員重名;
用var:同時重寫getter、setter方法,只重寫getter方法報錯。
重寫val:
用val:子類的一個私有字段與超類的字段重名,getter方法重寫超類的getter方法
重寫var:
用var:當超類的var是抽象的才能被重寫,否則超類的var都會被繼承。
// 新建文件month.scala,內容為: abstract class month { val zero : Int; val one = 25; // 可在子類中用val重寫 var two = 15; // 不可在子類中用var重寫,因為不是抽象的 var three : Int; def firstday ; // 可在子類中用val重寫 def now ; // 可在子類中用var重寫 def now_ ; def lastday(m : Char) = {} // 可在子類中用def重寫 } // 通過scalac命令編譯該文件 D:\LuclAppServ\scala-SDK\source>scalac month.scala D:\LuclAppServ\scala-SDK\source>javap.exe -private month.class // 通過javap命令查看生成的文件 Compiled from "month.scala" public abstract class month { // val變量且被初始化了 private final int one; // var變量且被初始化了 private int two; // val變量但為抽象的,直接生成了getter方法 public abstract int zero(); // 只有getter方法 public int one(); // 同時具有getter和setter方法(=被轉義為$eq) public int two(); public void two_$eq(int); // var變量但為抽象的,直接生成了getter和setter方法 public abstract int three(); public abstract void three_$eq(int); // 其他抽象的方法 public abstract void firstday(); public abstract void now(); public abstract void now_(); // 具有方法體,非抽象方法 public void lastday(char); // 構造函數 public month(); }
通過IDE工具生成的week.scala代碼如下
/** * @author lucl */ class week extends month { override val zero : Int = 10; override var three : Int = 3; override def firstday : Unit = { println("method of firstday."); } override def now : Unit = { println("method of now."); } override def now_ : Unit = { println("method of now_."); } } object week { def main (args : Array[String]) { var w = new week(); println(w.zero + "\t" + w.now); } }
查看生成的week子類代碼
D:\LuclAppServ\workspaces\scala\scalaproj\bin>javap -private week.class Compiled from "week.scala" public class week extends month { private final int zero; private int three; public int zero(); public int three(); public void three_$eq(int); public void firstday(); public void now(); public void now_(); public week(); public static void main(java.lang.String[]); } D:\LuclAppServ\workspaces\scala\scalaproj\bin>javap -private week$.class Compiled from "week.scala" public final class week$ { public static final week$ MODULE$; public static {}; public void main(java.lang.String[]); private week$(); }
說明:
子類構造器運行在超類構造器之后,在超類的構造器調用的子類被重寫后,返回值可能不正確。
/** * @author lucl */ class A { val num = 31; val days = new Array[Int](num); println("When invoke Class A the length of days is " + days.length + "."); def dayLength = { println("Class A : the length of days is " + days.length + ".") } } /** * @author lucl */ object B extends A { override val num = 7; def main (args : Array[String]) { dayLength; println("The finally value of num is " + num); } }
運行結果:
構造B對象前先執行A的構造器,num被初始化為31,days被初始化為Array數組;
Array數組初始化時需要調用num,但num被子類重寫了,但此時B的構造器還未被調用,num被初始化為0,days被初始化為長度為0的數組;
A的構造器執行完畢,執行B的構造器,num被初始化為7,但此時A中days已初始化過不會再更新其初始化信息,days的數組長度為0。
解決方法:
將超類的val聲明為final(不可再被子類重寫);
將超類的val聲明為lazy;
在子類中使用提前定義語法。
a. final
當A類中的num聲明為final val num : Int = 7,則子類中不可再重寫該字段;
b. lazy
/** * @author lucl */ class A { lazy val num = 31; // 通過lazy標注 val days = new Array[Int](num); println("When invoke Class A the length of days is " + days.length + "."); def dayLength = { println("Class A : the length of days is " + days.length + ".") } } /** * @author lucl */ object B extends A { override lazy val num = 7; def main (args : Array[String]) { dayLength; println("The finally value of num is " + num); } }
運行結果
c. 提前定義
把需要提前定義的語句塊放在extends與超類之間,并后接with保留字。
class B extends {override val num = 7; } with A {......}
/** * @author lucl */ object B extends {override val num = 7; } with A { def main (args : Array[String]) { dayLength; println("The finally value of num is " + num); } }
執行結果:
3、抽象類
不能被實例的類叫做抽象類,用保留字abstract標記;
抽象類的某個或某幾個成員沒有被完整定義,這些沒有被完整定義的成員為抽象字段或方法。
/** * @author lucl */ abstract class year { val name : Array[String]; // 抽象的val,帶有一個抽象的getter方法 var num : Int; // 抽象的var,帶有抽象的getter/setter方法 def sign; // 沒有方法體/函數體,是一個抽象方法 }
只要類中有任意一個抽象成員,必須使用abstract標記;
重寫抽象方法、抽象字段不需要使用override保留字。
保護
當一個類不希望被集成、拓展時,可在類聲明前加上final保留字
final class year {......}
當一個類的某些成員不希望被重寫時,可在成員聲明前加上final保留字
class year {final def sign {......}}
當超類中的某些成員需要被子類繼承,又不想對子類以外成員可見時,在成員聲明前加上protected保留字;
protected[this],將訪問限定于當前對象(子類也不可訪問),類似于private[this];
/** * @author lucl * 只要類中有一個成員是抽象的,則類就需要聲明為抽象類 */ abstract class Human { var name : String; // 抽象字段 def sleep() : String; // 抽象方法 def info (address : String); } /** * */ abstract class Teacher (tname : String, age : Int) extends Human { println(tname + "\t" + age); override var name : String = tname; // 若將類聲明為def sleep = "8 hours",在下面調用super.sleep()的位置會提示返回的為Unit override def sleep() : String = "8 hours."; def info (address : String); } /** * Worker繼承Teacher時有兩個參數name和age需要從Worker中傳遞參數 * Worker的的參數名字需要與Teacher中一致,否則IDE會提示錯誤 */ class Worker(tname : String, age : Int, salary : Int) extends Teacher (tname, age) { override def info (address : String) { println(tname + "' home is in " + address); println(tname + "'s age is " + age + ", earn ¥" + salary + "."); } override def toString = { tname + " is a worker, sleep " + super.sleep; } } object AbstractClassOps { def main(args : Array[String]) { val w = new Worker ("zhangsan", 25, 3000); w.info("BeiJing"); println(w); } } /** zhangsan 25 zhangsan' home is in BeiJing zhangsan's age is 25, earn ¥3000. zhangsan is a worker, sleep 8 hours. */
4、類的private屬性
/** * @author lucl */ // 默認是public類型的 class Person { // age必須賦值,否則該類必須為abstract的 private var age : Int = 0; // 沒有private修飾默認是public的 // 無參的方法可以省略(),調用時可以省略(); def increment() = age += 1; // 若聲明的方法不帶(),則調用時不可帶() def current = age; // 類可以直接訪問伴生對象的私有屬性 def speak = Person.sayHello; } class Student { /** * 聲明為private類型的參數,只能通過當前類的函數來訪問 */ private var privateAge : Int = 0; // 僅限于類的當前實例對象訪問,其他傳入的對象(如下面的other)將不可訪問private[this]修飾的變量 private [this] val name : String = ""; // 自定義的getter/setter方法 ,用來操作私有字段 def age = privateAge; def age_ (newAge : Int) { privateAge = newAge; } /** * this對象的使用,表示調用該方法的當前對象 */ def sameStudent (other : Student) = { // 上面的等號表示有返回結果,否則最后的true會提示: // a pure expression does nothing in statement position; // you may be omitting necessary parentheses if (this.privateAge != other.privateAge) { false; } /** * 此時通過other將無法訪問該name對象 * value name is not a member of Student */ /*if (this.name != other.name) { false; }*/ true; } // 在student中則不可通過Person類直接訪問sayHello方法,提示: // method sayHello in object Person cannot be accessed in object Person // def speak = Person.sayHello; // 但可以通過如下方式訪問: var p = new Person; p.speak; // 這里會直接執行 } /** * 對象為類的伴生對象,類為對象的伴生類 */ object Person { def main (args : Array[String]) { var p = new Person(); println("age is : " + p.age); // 可以訪問到私有屬性 p.increment; println("age is : " + p.age); println("current is : " + p.current); // 帶有()則提示“Int does not take parameters” // p.current(); val s = new Student(); // variable privateAge in class Student cannot be accessed in Student // s.privateAge; println(s.age); s.age_(20); println(s.age); } private def sayHello () { println("Singleton object Person to say."); } } /** // 輸出結果 age is : 0 age is : 1 current is : 1 Singleton object Person to say. 0 20 */
5、嵌套類
Scala允許任何語法結構中嵌套任何語法結構,因此能在類中定義類,類似于Java中的內部類。
內部類中可以訪問外部類的成員,利用外部類.this或指針實現。
scala> class HelloWorld {pointto => val value2 = "HelloWorld"; class HI { var value3 = HelloWorld.this.value2; var value4 = pointto.value2; } } scala> var one = new HelloWorld; one: HelloWorld = HelloWorld@4b134f33 scala> one.value2; res52: String = HelloWorld scala> class Family (val hname : String, val wname : String) { class Husband (var name : String) { println("Husband is : " + name); } class Wife (var name : String) { println("Wife is " + name); } def info () { var husband = new Husband(hname); var wife = new Wife(wname); println("This family holds husband " + husband.name + ", wife " + wife.name); } } scala> val f = new Family("Tom", "Jerry"); f: Family = Family@62de96e8 scala> f.info(); Husband is : Tom Wife is Jerry This family holds husband Tom, wife Jerry
Java內部類:內部類是屬于外部類的;
/** * * @author lucl * Java內部類示例 * 說明:Java內部類是從屬于外部類的 */ public class JavaOuter { private String name; public JavaOuter (String name) { this.name = name; } /** * 內部類 */ // 一旦用static修飾內部類,它就變成靜態內部類了。 class Inner { private String name; public Inner (String name) { this.name = name; } public void foo (Inner inner) { System.out.println("\t" + JavaOuter.this.name + "\t" + inner.name); } } public void foo () { System.out.println("Outer : " + this.name); } /** * @param args */ public static void main(String[] args) { JavaOuter outer1 = new JavaOuter("Spark"); JavaOuter outer2 = new JavaOuter("Hadoop"); JavaOuter.Inner inner1 = outer1.new Inner("scala"); JavaOuter.Inner inner2 = outer2.new Inner("java"); outer1.foo(); inner1.foo(inner1); outer2.foo(); inner2.foo(inner2); outer1.foo(); inner1.foo(inner2); // 在這里inner1可以調用inner2 } } /** // 輸出結果 Outer : Spark Spark scala Outer : Hadoop Hadoop java Outer : Spark Spark java */
Scala內部類:內部類是屬于外部類的對象的;
/** * @author lucl * Scala內部類示例 * 說明:Scala內部類是從屬于外部類的對象的 */ class ScalaOuter(val name : String) {outer => /** * 內部類 */ class Inner (val name : String) { def foo (inner : Inner) { println("\t" + outer.name + "\t" + inner.name + "."); } } def foo () { println("Outer : " + outer.name); } } object OOPInScala { /** * main方法 */ def main (args : Array[String]) { val outer1 = new ScalaOuter ("Spark"); val outer2 = new ScalaOuter ("Hadoop"); val inner1 = new outer1.Inner("scala"); val inner2 = new outer2.Inner("java"); outer1.foo; inner1.foo(inner1); outer2.foo; inner2.foo(inner2); // 對于scala來說,這inner1調用foo方法傳遞參數時,是不可以將inner2作為參數傳遞的 // IDE提示:type mismatch; found : outer2.Inner required: outer1.Inner // inner1.foo(inner2); } } /** // 輸出結果 Outer : Spark Spark scala. Outer : Hadoop Hadoop java. */
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。