<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ### 1. 為什么沒有多重繼承 - 準備這個Chapter講文件和正則表達式,但該內容按照其他語言安排一般都是在最后幾章節,所以暫時先忽略該章節,后面會補上。 - 轉入正題,如果有兩個類Student和Employee,它們都有name這個屬性,如果要同時擴展這兩個基類該如何做,主要問題是name屬性如何處理?如果保留兩個,那么訪問時到底訪問的是哪個呢?如果只保留一個,那么保留哪一個?該問題就是**菱形問題**。畫一個形象的圖形如下: ![這里寫圖片描述](https://box.kancloud.cn/2016-04-07_57061f76d1442.jpg "") - Scala通過提供**特質**解決這個問題,特質可以同時擁有抽象方法和具體方法,而類可以實現多個特質。 ### 2. 當做接口使用的特質 - 特質**完全**可以像Java接口那樣工作。 - 特質中未被實現的方法默認是抽象方法,不需要用`abstract`申明。 - 重寫特質抽象方法時不需要給出`override`關鍵字。 - 特質不止一個,可以使用`with`關鍵字來添加額外的特質。 - Scala類只能有一個超類,可以有任意數量的特質。 ### 3. 帶有具體實現的特質 - 特質中可以有具體的方法。 ~~~ trait ConsoleLogger { def log(msg: String) { println(msg) } // 具體方法 } class Account { protected var balance = 0.0 } class SavingsAccount extends Account with ConsoleLogger { def withdraw(amount: Double) { if (amount > balance) log("Insufficient funds") else balance -= amount } } ~~~ ### 4. 帶有特質的對象 - 構造單個對象時,可以為它添加特質,用`with`關鍵字。 ~~~ trait Logged { def log(msg: String) { } } trait ConsoleLogger extends Logged { override def log(msg: String) { println(msg) } } class Account { protected var balance = 0.0 } class SavingsAccount extends Account with Logged { def withdraw(amount: Double) { if (amount > balance) log("Insufficient funds") else balance -= amount } } object Main extends App { val acct1 = new SavingsAccount acct1.withdraw(100) // 沒有任何信息會打印出來 println("Overdrawing acct2"); val acct2 = new SavingsAccount with ConsoleLogger // 添加特質進來 acct2.withdraw(100) // 會打印信息 } ~~~ ### 5. 添加多個特質 > **個人理解:**添加多個特質要研究的問題實際是,添加的這幾個特質哪個先執行?即執行的順序,執行完的結果是要傳給另一個特質進行下一步處理,這里有點像linux中pipe的概念。 - 類或對象可以添加多個特質,特質從最后一個開始執行,非常適合分階段處理的場景。 ~~~ trait Logged { def log(msg: String) { } } trait ConsoleLogger extends Logged { override def log(msg: String) { println(msg) } } trait TimestampLogger extends Logged { // 給消息添加時間戳 override def log(msg: String) { super.log(new java.util.Date() + " " + msg) } } trait ShortLogger extends Logged { // 截斷過長的信息 val maxLength = 15 override def log(msg: String) { super.log( if (msg.length <= maxLength) msg else msg.substring(0, maxLength - 3) + "...") } } class Account { protected var balance = 0.0 } class SavingsAccount extends Account with Logged { def withdraw(amount: Double) { if (amount > balance) log("Insufficient funds") // 調用特質中的log方法 else balance -= amount } } object Main extends App { val acct1 = new SavingsAccount with ConsoleLogger with TimestampLogger with ShortLogger val acct2 = new SavingsAccount with ConsoleLogger with ShortLogger with TimestampLogger acct1.withdraw(100) acct2.withdraw(100) } ~~~ - 由于特質添加的順序,上面的執行結果為: ![運行結果](https://box.kancloud.cn/2016-04-07_57061f76e514e.jpg "") ### 6. 在特質中重寫抽象方法 > **個人理解:**這節就是想區分用類來擴展特質是不需要加override,而特質擴展特質就要加override。 - 特質中重寫抽象方法需要加`abstract`和`override`關鍵字。 ~~~ trait Logger { def log(msg: String) // 抽象的方法 } trait TimestampLogger extends Logger { abstract override def log(msg: String) { super.log(new java.util.Date() + " " + msg) } } trait ConsoleLogger extends Logger { override def log(msg: String) { println(msg) } // 這里說明abstract是可以省略的 } ~~~ ### 7. 當做富接口使用的特質 > ***個人理解:**這節無非是上面的基本應用,train中可以根據不同的應用場景來定義多個同一功能的方法。 - 比如下面這段代碼,每個日志消息都會區分消息的類型。 ~~~ trait Logger { def log(msg: String) def info(msg: String) { log("INFO: " + msg) } def warn(msg: String) { log("WARN: " + msg) } def severe(msg: String) { log("SEVERE: " + msg) } } ~~~ ### 8. 特質中的具體字段 > **個人理解:**這節主要目的是知道特質中可以有具體的字段,具體的意思就是經過初始化的字段。并且**類**在擴展特質后,具體字段不是被繼承的,而是**直接被加入到子類中**。說白了就是在類中又拷貝了該字段的一個副本,類中可以直接使用。 ### 9. 特質中的抽象字段 > **個人理解:**具體字段可以直接使用,那么如果是抽象字段該怎么辦?這節給出特質中如果有抽象字段,**類**中使用就必須要重新定義該字段,并且不需要使用override關鍵字,這在第二小節已經明確。 ~~~ trait Logger { val maxLength: Int // 抽象的字段 } class TimestampLogger extends Logger { val maxLength: Int = 20 // 不需要寫override } ~~~ ### 10. 特質中的構造順序 > **個人理解:**和類一樣,特質也有構造器,同樣特質中也存在構造執行順序的問題。記住特質的構造順序對寫程序是很有幫助的。 - 特質的構造器執行順序: 1. 首先調用超類構造器; 1. 特質構造器在超類構造器之后、類構造器之前執行; 1. 特質由左到右構造; 1. 每個特質中,父特質先被構造; 1. 如果過個特質共有一個父特質,而父特質已被構造,則不會再次被構造; 1. 所有特質構造完畢,子類被構造。 ### 11. 初始化特質中的字段 > **個人理解:**首先知道**特質是不能有構造參數**,對某種定制的特質來說這就是一個問題,那么該如何解決?這小結給給出了兩種解決方案:**提前定義**和**懶值**。 - 特質不能有構造參數,但都有一個無參的構造器,缺少構造器參數這是特質和類之間**唯一**的技術差別,特質可以具備類的所有特性。 - 提前定義的方法如下: ~~~ trait Logger { def log(msg: String) } // 使用提前定義定義變量filename trait FileLogger extends Logger { val filename: String val out = new PrintWriter(filename) def log(msg: String) { out.println(msg); out.flush() } } class Account { protected var balance = 0.0 } abstract class SavingsAccount extends Account with Logger { def withdraw(amount: Double) { if (amount > balance) log("Insufficient funds") else balance -= amount } } object Main extends App { val acct = new { // new之后就是提前定義塊,在構造器執行前就定義好 val filename = "myapp.log" } with SavingsAccount with FileLogger acct.withdraw(100) } ~~~ - 懶值方法,懶值字段會在第一次使用時才會被初始化。 ~~~ trait Logger { def log(msg: String) } // 使用懶值 trait FileLogger2 extends Logger { val filename: String lazy val out = new PrintWriter(filename) def log(msg: String) { out.println(msg); out.flush() } } class Account { protected var balance = 0.0 } abstract class SavingsAccount extends Account with Logger { def withdraw(amount: Double) { if (amount > balance) log("Insufficient funds") else balance -= amount } } object Main extends App { val acct2 = new SavingsAccount with FileLogger2 { val filename = "myapp2.log" } acct2.withdraw(100) } ~~~ ### 12. 擴展類的特質 > **個人理解:**標題有點繞,其實意思就是**某個特質擴展了類**,這種情況scala會有哪些特殊的地方需要注意。 - 特質是可以擴展特質的,其實特質也是可以擴展類,擴展后這個類自動成為該特質的超類。 ~~~ trait Logged { def log(msg: String) { } } trait LoggedException extends Exception with Logged { def log() { log(getMessage()) } } ~~~ 這里LoggedException擴展了Exception類,并調用了從Exception超類繼承下來的getMessage()方法。 ### 13. 自身類型 > **個人理解:**除上面可以擴展某個類的方法之外,scala還提供另外一種方式,不用擴展某個類,直接把某個類作為自身的一個類型,從而達到同樣的目的。 - 定義語法:`this: 類型 =>`,特質定義自身類型后,只能被混入指定類型的子類。比如: ~~~ trait Logged { def log(msg: String) { } } trait LoggedException extends Logged { this: Exception => // 特質不是擴展Exception類,而是有一個自身類型Exception def log() { log(getMessage()) } } ~~~ - 自身類型還可以用來處理結構類型,比如只指定一個方法,而不是類名。 ~~~ trait Logged { def log(msg: String) { } } trait LoggedException extends Logged { this: { def getMessage() : String } => def log() { log(getMessage()) } } ~~~ 【待續】
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看