如今有兩個程序員共同開發一個項目,程序員xiaoming但願定義一個類取名Dog,程序員xiaohong也想定一個類也叫Dog,兩個程序員還爲此吵了起來,該怎麼辦?java
--->使用包便可解決這個問題程序員
1) 區分相同名字的類編程
2) 當類不少時,能夠很好的管理類安全
3) 控制訪問範圍性能優化
-打包基本語法框架
package com.c;ide
-打包的本質分析函數
實際上就是建立不一樣的文件夾來保存類文件性能
使用打包技術來解決上面的問題,不一樣包下Dog類學習
public class TestTiger { public static void main(String[] args) { //使用xm的Tiger com.c.scala_exercise.javapackage.xm.Tiger tiger01 = new com.c.scala_exercise.javapackage.xm.Tiger(); //使用xh的Tiger com.c.scala_exercise.javapackage.xh.Tiger tiger02 = new com.c.scala_exercise.javapackage.xh.Tiger(); System.out.println("tiger01=" + tiger01 + "tiger02=" + tiger02); } }
和Java同樣,Scala中管理項目可使用包,但Scala中的包的功能更增強大,使用也相對複雜些
使用打包技術來解決上面的問題,不一樣包下Dog類
object boke_demo01 { def main(args: Array[String]): Unit = { //使用xh的Tiger val tiger1 = new com.c.scala_exercise.scalapackage.xh.Tiger //使用xm的Tiger val tiger2 = new com.c.scala_exercise.scalapackage.xm.Tiger println(tiger1 + " " + tiger2) } }
-基本語法
package 包名
-Scala包的做用(和Java同樣)
1) 區分相同名字的類
2) 當類不少時,能夠很好的管理類
3) 控制訪問範圍
4) 能夠對類的功能進行擴展
-Scala中包名和源碼所在的系統文件目錄結構能夠不一致,可是編譯後的字節碼文件路徑和包名會保持一致(這個工做由編譯器完成)
object boke_demo01 { def main(args: Array[String]): Unit = { //使用xh的Tiger val tiger1 = new com.c.scala_exercise.scalapackage.xh.Tiger //使用xm的Tiger val tiger2 = new com.c.scala_exercise.scalapackage.xm.Tiger println(tiger1 + " " + tiger2) } } class Employee { }
-命名規則:
只能包含數字、字母、下劃線、小圓點.,可是不能用梳子開頭,也不要使用關鍵字
demo.class.exercise //錯誤,由於class是關鍵字
demo.12a //錯誤,由於不能以梳子開頭
-命名規範:
通常是小寫字母+小圓點通常是
com.公司名.項目名.業務模塊名 好比:com.baidu.io.model com.baidu.io.controller
1) Scala進行package打包時,能夠有以下形式
//代碼說明 //1. package com.boke{} 表示咱們建立了包 com.boke ,在{}中 // 咱們能夠繼續寫它的子包 scala //com.boke.scala, 還能夠寫類,特質trait,還能夠寫object //2. 即Sacla支持,在一個文件中,能夠同時建立多個包,以及給各個包建立類,trait和object package com.boke { //包 com.boke // class User { // 在com.boke包下建立個 User類 // def sayHello(): Unit = { // //想使用 com.boke.scala2包下的 Monster // import com.boke.scala2.Monster // val monster = new Monster() // } // } // // package scala2 { // 建立包 com.boke.scala2 // class User { // 在com.boke.scala2 包下建立個 User類 // } // // class Monster { // // // } // // } // //說明 //1. 在包中直接寫方法,或者定義變量,就錯誤==>使用包對象的技術來解決 //2. package object scala表示建立一個包對象scala, 它是com.boke.scala這個包對應的包對象 //3. 每個包均可以有一個包對象 //4. 包對象的名字須要和子包同樣 //5. 在包對象中能夠定義變量,方法 //6. 在包對象中定義的變量和方法,就能夠在對應的包中使用 //7. 在底層這個包對象會生成兩個類 package.class 和 package$.class package object scala { var name = "king" def sayHiv(): Unit = { println("package object scala sayHI~") } } package scala { //包 com.boke.scala class Person { // 表示在 com.boke.scala下建立類 Person val name = "Nick" def play(message: String): Unit = { println(this.name + " " + message) } } class User { def testUser(): Unit = { println("name = " + name) sayHiv() } } object Test1 { //表示在 com.boke.scala 建立object Test1 def main(args: Array[String]): Unit = { println("name=" + name) name = "yy" sayHiv() // println("ok") // //咱們能夠直接使用父包的內容 // //1.若是有同名的類,則採用就近原則來使用內容(好比包) // //2.若是就是要使用父包的類,則指定路徑便可 // val user = new User // println("user=" + user) // // val user2 = new com.boke.User() // println("user2" + user2) } } } }
2) 包也能夠像嵌套類那樣嵌套使用(包中有包),好處:能夠在同一個文件中,將類(class/object)、trait建立在不一樣的包中,這樣就很是靈活了
3) 做用域原則:能夠直接向上訪問。即Scala中子包中直接訪問父包的內容,大括號體現做用域。(提示:Java中子包使用父包的類,須要import)。在子包和父包類重名時,默認採用就近原則,若是但願指定使用某個類,則帶上包名便可
4) 父包要訪問子包的內容時,須要import對應的類等
5) 能夠在同一個.scala文件中聲明多個並列的package(建議嵌套的package不要超過3層)
6) 包名能夠相對也能夠絕對,好比訪問 BeanProperty 的絕對路徑是: _root_.scala.beans.BeanProperty,在通常狀況下,咱們使用相對路徑來引入包,只有當包名衝突時,使用絕對路徑來處理
import scala.beans.BeanProperty class Manager(var name: String) { //第一種形式 [使用相對路徑引入包] @BeanProperty var age: Int = _ //第二種形式, 和第一種同樣,都是相對路徑引入 @scala.beans.BeanProperty var age2: Int = _ //第三種形式, 是絕對路徑引入,能夠解決包名衝突 @_root_.scala.beans.BeanProperty var age3: Int = _ } object TestBean { def main(args: Array[String]): Unit = { val m = new Manager("jack") println("m=" + m) } }
基本介紹:包能夠包含類、對象和特質(trait),但不能包含函數/方法或變量的定義。這是Java虛擬機的侷限。爲了彌補這一點,Scala提供了包對象的概念來解決這個問題
/說明 //1. 在包中直接寫方法,或者定義變量,就錯誤==>使用包對象的技術來解決 //2. package object scala表示建立一個包對象scala, 它是com.boke.scala這個包對應的包對象 //3. 每個包均可以有一個包對象 //4. 包對象的名字須要和子包同樣 //5. 在包對象中能夠定義變量,方法 //6. 在包對象中定義的變量和方法,就能夠在對應的包中使用 //7. 在底層這個包對象會生成兩個類 package.class 和 package$.class package object scala { var name = "king" def sayHiv(): Unit = { println("package object scala sayHI~") } } package scala { //包 com.boke.scala class Person { // 表示在 com.boke.scala下建立類 Person val name = "Nick" def play(message: String): Unit = { println(this.name + " " + message) } } class User { def testUser(): Unit = { println("name = " + name) sayHiv() } } object Test1 { //表示在 com.boke.scala 建立object Test1 def main(args: Array[String]): Unit = { println("name=" + name) name = "yy" sayHiv() } } }
如圖所示:一個包對象會生成兩個類package和package$
如圖所示:說明了包去使用包對象的變量或者方法的原理
1) 每一個包均可以有一個包對象,須要在父包中定義它
2) 包對象名稱須要和包名一致,通常用來對包的功能補充
Java提供四種訪問控制修飾符號來控制方法和變量的訪問權限(範圍)
1) 公開級別:用public修飾,對外公開
2) 受保護級別:用protected修飾,對於子類和同一包中的類公開
3) 默認級別:沒有修飾符,向同一個包中的類公開
4) 私有級別:用private修飾,只有類自己能夠訪問,不對外公開
1) 修飾符能夠用來修飾類中的屬性,成員方法以及類
2) 只有默認的和public才能修飾類!而且遵循上述訪問權限的特色
在Java中,訪問權限分爲:public,private,protected和默認。在Scala中,能夠經過相似的修飾符達到一樣的效果,可是使用上有所區別
案例演示
object boke_demo01 { def main(args: Array[String]): Unit = { val c = new Clerk() c.showInfo() Clerk.test(c) } } //類 class Clerk { var name: String = "jack" // private var sal: Double = 9999.9 protected var age = 23 var job: String = "大數據工程師" def showInfo(): Unit = { //在本類可使用私有的 println(" name " + name + " sal= " + sal) } } object Clerk { def test(c: Clerk): Unit = { //這裏體現出在伴生對象中,能夠訪問c.sal println("test() name=" + c.name + " sal= " + c.sal) } }
1) 當屬性訪問權限爲默認時,從底層看屬性是private的,可是由於提供了xxx_$eq()[相似setter]/xxx()[相似getter]方法,所以從使用效果看是任何地方均可以訪問
2) 當方法訪問權限爲默認時,默認爲public訪問權限
3) private爲私有權限,只有在類的內部和伴生對象中可用
4) protected爲受保護權限,Scala中受保護權限比Java中更爲嚴格,只能子類訪問,同包沒法訪問
5) 在Scala中沒有public關鍵字,即不能用public顯示的修飾屬性和方法
6) 包訪問權限(表示屬性有了限制,同時包也有了限制),這點和Java不同,體現出Scala包的靈活性
package com.scala.exercise class Person { //增長包訪問權限後 //1.private同時起做用,不只同類可使用 //2.com.scala.exercise中包下的其它類也可使用 private[exercise] val name = "Jack" //固然,也能夠將可見度延展到上層包 private[scala] val age = 23 //說明:private能夠變化,好比protected[scala],很是的靈活 }
7) 總體的案例演示
object boke_demo01 { def main(args: Array[String]): Unit = { val c = new Clerk() c.showInfo() Clerk.test(c) } } //類 class Clerk { var name: String = "jack" // private var sal: Double = 9999.9 protected var age = 23 var job: String = "大數據工程師" def showInfo(): Unit = { //在本類可使用私有的 println(" name " + name + " sal= " + sal) } } //當一個文件中出現了 class Clerk 和 object Clerk //1. class Clerk 稱爲伴生類 //2. object Clerk 的伴生對象 //3. 由於Scala設計者將static拿掉, 他就是設計了 伴生類和伴生對象的概念 //4. 伴生類 寫非靜態的內容 伴生對象 就是靜態內容 //5. object Clerk { def test(c: Clerk): Unit = { //這裏體現出在伴生對象中,能夠訪問c.sal println("test() name=" + c.name + " sal= " + c.sal) } } class Person { //這裏咱們增長一個包訪問權限 //下面private[scala] : 1,仍然是private 2. 在scala包(包括子包)下也可使用name ,至關於擴大訪問範圍 protected[scala] val name = "Jack" }
Scala引入包也是使用import,基本的原理跟機制和Java同樣,可是Scala中的import功能更佳強大,也更靈活。由於Scala語言源自Java,因此java.lang包中的類會自動引入到當前環境中,而Scala中的scala包和predef包的類也會自動引入到當前環境中,即起其下的類能夠直接使用。若是想要把其它包中的類引入到當前環境中,須要使用import
1) 在Scala中,import語句能夠出如今任何地方,並不只限於文件頂部,import語句的做用一直延伸到包含該語句的塊末尾。這種語法的好處是:在須要時引入包,縮小import包的做用範圍,提升效率
class User { import scala.beans.BeanProperty @BeanProperty var name : String = "" } class Dog { @BeanProperty var name : String = "" //能夠嗎? No }
2) Java中若是想要導入包中全部的類,能夠經過通配符*,Scala中採用_(下劃線)
3) 若是不想要某個包中所有的類,而是其中幾個類,能夠採用選取器(大括號)
def test(): Unit = { //可使用選擇器,選擇引入包的內容,這裏,咱們只引入 HashMap, HashSet import scala.collection.mutable.{HashMap, HashSet} var map = new HashMap() var set = new HashSet() }
4) 若是引入的多個包中含有相同的類,那麼能夠將不須要的類進行重命名進行區分,這個就是重命名
def test2(): Unit = { //下面的含義是 將 java.util.HashMap 重命名爲 JavaHashMap import java.util.{HashMap => JavaHashMap} import scala.collection.mutable._ var map = new HashMap() // 此時的 HashMap 指向的是 scala 中的 HashMap var map1 = new JavaHashMap(); // 此時使用的 java 中 hashMap 的別名 }
5) 若是某個衝突的類根本就不會用到,那麼這個類能夠直接隱藏掉
import java.util.{ HashMap=>_, _} // 含義爲 引入 java.util 包的全部類,可是忽略 HahsMap 類. var map = new HashMap()
-如何理解抽象
咱們在前面去定義一個類的時候,實際上就是把一類事物的共有的屬性和行爲提取出來,造成一個物理模型(模版),這種研究問題的方法稱爲抽象
面向對象有三大特徵:封裝、繼承、多態
封裝(encapsulation)就是把抽象出的數據和對數據的操做封裝在一塊兒,數據被保護在內部,程序的其它部分只有經過被受權的操做(成員變量),才能對數據進行操做
1) 隱藏實現細節
2) 能夠對數據進行驗證,保證安全合理
3) 同時能夠加入業務邏輯
1) 對類中的屬性進行封裝
2) 經過成員方法,包實現封裝
1) 將屬性進行私有化
2) 提供一個公共的set方法,用於對屬性判斷並賦值
def setXxx(參數名 : 類型) : Unit = { //加入數據驗證的業務邏輯 屬性 = 參數名 }
3) 提供一個公共的get方法,用於獲取屬性的值
def getXxx() [: 返回類型] = { return 屬性 }
1) Scala中爲了簡化代碼的開發,當聲明屬性var時,自己就自動提供了對應setter/getter方法,若是屬性聲明爲private的,那麼自動生成的setter/getter方法也是private的,若是屬性省略訪問權限修飾符,那麼自動生成的setter/getter方法時public的
2) 所以咱們若是隻是對一個屬性進行簡單的set和get,只要聲明一下該屬性(屬性使用默認訪問修飾符),不用寫專門的set和get,默認會建立,訪問時,直接對象.變量。這樣也是爲了保持訪問一致性
3) 從形式上看 dog.food 直接訪問屬性,其實底層仍然是訪問的方法,看一下反編譯的代碼就會明白
4) 有了上面的特性,目前不少新的框架,在進行反射時,也支持對屬性的直接反射
class 子類名 extends 父類名 { 類體 }
繼承能夠解決代碼複用,讓咱們的編程更佳靠近人類的思惟,當多個類存在相同的屬性(變量)和方法時,能夠從這些類中抽象出父類(好比Student),在父類中定義這些相同的屬性和方法,全部的子類不須要重複定義這些屬性和方法,只須要經過extends語句來聲明繼承父類便可。和Java同樣,Scala也支持類的單繼承
class 子類名 extends 父類名 { 類體 }
object boke_demo01 { def main(args: Array[String]): Unit = { //使用 val student = new Student student.name = "jack" //調用了student.name() student.studying() student.showInfo() } } class Person { //Person類 var name: String = _ var age: Int = _ def showInfo(): Unit = { println("學生信息以下:") println("名字:" + this.name) } } //Student類繼承Person class Student extends Person { def studying(): Unit = { //這裏可使用父類的屬性 println(this.name + "學習 scala中....") } }
1) 代碼的複用性提升了
2) 代碼的擴展性和維護性提升了
子類繼承了全部的屬性,只是私有的屬性不能直接訪問,須要經過公共的方法去訪問[debug代碼驗證能夠看到]
//說明 //1. 在scala中,子類繼承了父類的全部屬性 //2. 可是private的屬性和方法沒法訪問 object boke_demo01 { def main(args: Array[String]): Unit = { val sub = new Sub() sub.sayOk() //sub.test200() //編譯器不讓過. } } //父類(基類) class Base { var n1: Int = 1 //public n1() , public n1_$eq() protected var n2: Int = 2 private var n3: Int = 3 // private n3() , private n3_$eq() def test100(): Unit = { // 默認 public test100() println("base 100") } protected def test200(): Unit = { // public println("base 200") } private def test300(): Unit = { //private println("base 300") } //編譯原理->業務邏輯->性能優化 } //Sub 繼承 Base class Sub extends Base { def sayOk(): Unit = { this.n1 = 20 //這裏訪問本質this.n1_$eq() this.n2 = 40 println("範圍" + this.n1 + this.n2) test100() // test200() //在子類中使用protected } }
說明:Scala明確規定,重寫一個非抽象方法須要用override修飾符,調用超類的方法使用super關鍵字
object boke_demo01 { def main(args: Array[String]): Unit = { val emp = new Emp emp.printName() } } //Person類 class Person { var name: String = "tom" def printName() { //輸出名字 println("Person printName() " + name) } def sayHi(): Unit = { println("sayHi...") } } //這裏咱們繼承Person class Emp extends Person { //這裏須要顯式的使用override override def printName() { println("Emp printName() " + name) //在子類中須要去調用父類的方法,使用super super.printName() sayHi() } }
-基本介紹
要測試某個對象是否屬於某個給定的類,能夠用isInstanceOf方法。用asInstanceOf方法將引用轉換爲子類的引用。classOf獲取對象名
classOf[String]就如同Java的String.class
obj.isInstanceOf[T]就如同Java的 obj instanceofT 判斷obj是否是T類型
obj.asInstanceOf[T] 就如同Java的(T)obj 將obj強轉成T類型
-案例演示
object boke_demo01 { def main(args: Array[String]): Unit = { //ClassOf的使用,能夠獲得類名 println(classOf[String]) // 輸出 val s = "king" println(s.getClass.getName) //使用反射機制 //isInstanceOf asInstanceOf var p1 = new Person var emp = new Emp //將子類引用給父類(向上轉型,自動) p1 = emp //將父類的引用從新轉成子類引用(多態),即向下轉型 var emp2 = p1.asInstanceOf[Emp] emp2.sayHello() } } //Person類 class Person { var name: String = "tom" def printName() { //輸出名字 println("Person printName() " + name) } def sayHi(): Unit = { println("sayHi...") } } //這裏咱們繼承Person class Emp extends Person { //這裏須要顯式的使用override override def printName() { println("Emp printName() " + name) //在子類中須要去調用父類的方法,使用super super.printName() sayHi() } def sayHello(): Unit = { } }
-最佳實踐
類型檢查和轉換的最大價值在於:能夠判斷傳入對象的類型,而後轉成對應的子類對象,進行相關操做,這裏也體現出多態的特色
說明:從代碼能夠看出,在Java中,建立子類對象時,子類的構造器老是去調用一個父類的構造器(顯示或者隱式調用)
public class JavaBaseConstractor { public static void main(String[] args) { //1.A() //2.B() B b = new B(); //1.A(String name) jack //2.B(String name) jack B b2 = new B("jack"); } } class A { public A() { System.out.println("A()"); } public A(String name) { System.out.println("A(String name)" + name); } } class B extends A { public B() { //這裏會隱式調用super(); 就是無參的父類構造器A() //super(); System.out.println("B()"); } public B(String name) { super(name); System.out.println("B(String name)" + name); } }
1) 類有一個主構造器和任意數量的輔助構造器,而每一個輔助構造器都必須先調用主構造器(也能夠是間接調用)
2) 只有主構造器能夠調用父類的構造器,輔助構造器不能直接調用父類的構造器,在Scala的構造器中,不能調用super(params)
3) 案例演示
object boke_demo01 { def main(args: Array[String]): Unit = { //分析執行的順序 //1.Person... //2.Emp .... //3.Emp 輔助構造器~ val emp1 = new Emp("smith") println("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%") //Person.. //Emp .... val emp2 = new Emp("terry", 10) emp2.showInfo() // 僱員的名字 terry } } //父類Person class Person(pName: String) { var name = pName println("Person...") def this() { this("默認的名字") println("默認的名字") } } //子類Emp繼承Person class Emp(eName: String, eAge: Int) extends Person(eName) { println("Emp ....") //輔助構造器 def this(name: String) { this(name, 100) // 必須調用主構造器 this.name = name println("Emp 輔助構造器~") } def showInfo(): Unit = { println("僱員的名字 ", name) } }
-基本介紹
在Scala中,子類改寫父類的字段,咱們稱之爲覆寫/重寫字段。覆寫字段須要使用override修飾
-回顧
在Java中只有方法的重寫,沒有屬性/字段的重寫,準確的講,是隱藏字段代替了重寫
-回顧-Java另外一重要特性:動態綁定機制
動態綁定機制:
1) 若是調用的是方法,則JVM機會將改方法和對象的內存地址綁定
2) 若是調用的是一個屬性,則沒有動態綁定機制,在哪裏調用就返回對應值
public class JavaDaynamicBind { public static void main(String[] args) { //將一個子類的對象地址,交給了一個AA(父類的)引用 //java的動態綁定機制的小結 //1.若是調用的是方法,則Jvm機會將該方法和對象的內存地址綁定 //2.若是調用的是一個屬性,則沒有動態綁定機制,在哪裏調用,就返回對應值 AA obj = new BB(); System.out.println(obj.sum()); // 30 System.out.println(obj.sum1()); // 20 } } class AA { public int i = 10; public int sum() { return getI() + 10; } public int sum1() { return i + 10; } public int getI() { return i; } } class BB extends AA { public int i = 20; public int getI() { return i; } }
-Scala覆寫字段快速入門
object ScalaFiledOverride { def main(args: Array[String]): Unit = { val obj1: AAA = new AAA val obj2: BBB = new BBB //obj1.age => obj1.age() //動態綁定機制 //obj2.age => obj2.age() println("obj1.age=" + obj1.age + "\t obj2.age=" + obj2.age) } } class AAA { val age: Int = 10 // 會生成 public age() } class BBB extends AAA { override val age: Int = 20 // 會生成 public age() }
反編譯後的代碼:
-覆寫字段的注意事項和細節
1) def只能重寫另外一個def(即:方法只能重寫另外一個方法)
2) val只能重寫另外一個val屬性 或 重寫不帶參數的def
-案例演示1(val只能重寫另外一個val屬性)
object ScalaFiledOverride { def main(args: Array[String]): Unit = { val obj1: AAA = new AAA val obj2: BBB = new BBB //obj1.age => obj1.age() //動態綁定機制 //obj2.age => obj2.age() println("obj1.age=" + obj1.age + "\t obj2.age=" + obj2.age) } } //若是 val age 改爲 var 報錯 class AAA { val age: Int = 10 // 會生成 public age() } class BBB extends AAA { override val age: Int = 20 // 會生成 public age() }
-案例演示2(重寫不帶參數的def)
object boke_demo01 { def main(args: Array[String]): Unit = { val b1 = new BB() println(b1.sal) // 0 val b2: AA = new BB() println("b2.sal=" + b2.sal()) // 0 } } class AA { def sal(): Int = { return 10 } } class BB extends AA { override val sal: Int = 0 //底層 public sal }
3) var只能重寫另外一個抽象的var屬性
object boke_demo01 { def main(args: Array[String]): Unit = { println("hello~") } } //在AA中,有一個抽象的字段(屬性) //1. 抽象的字段(屬性):就是沒有初始化的字段(屬性) //2. 當一個類含有抽象屬性時,則該類須要標記爲abstract //3. 對於抽象的屬性,在底層不會生成對應的屬性聲明,而是生成兩個對應的抽象方法(name name_$eq) abstract class AA { var name: String //抽象 var age: Int = 10 } class Sub_AA extends AA { //說明 //1. 若是咱們在子類中去重寫父類的抽象屬性,本質是實現了抽象方法 //2. 所以這裏咱們能夠寫override ,也能夠不寫 override var name: String = "" }
-抽象屬性:聲明未初始化的變量就是抽象的屬性,抽象屬性在抽象類中
-var重寫抽象的var屬性小結
1) 一個屬性沒有初始化,那麼這個屬性就是抽象屬性
2) 抽象屬性在編譯成字節碼文件時,屬性並不會聲明,可是會自動生成抽象方法,因此類必須聲明爲抽象類
3) 若是是覆寫一個父類的抽象,那麼override關鍵字能夠省略[緣由:父類的抽象屬性,生成的是抽象方法,所以不涉及到方法重寫的概念,override能夠省略]
-基本介紹
在Scala中,經過abstract關鍵字標記不能被實力化的類。方法不用標記abstract,只要省掉方法體便可,抽象類能夠擁有抽象字段,抽象字段/屬性就是沒有初始值的字段
-快速入門案例
將Animal作成抽象類,包含一個抽象方法cry()
object AbstractDemo01 { def main(args: Array[String]): Unit = { } } //抽象類 abstract class Animal { var name: String //抽象的字段 var age: Int // 抽象的字段 var color: String = "black" //普通屬性 def cry() //抽象方法,不須要標記 abstract }
1) 抽象類不能被實例
//默認狀況下,一個抽象類是不能實例化的,可是你實例化時,動態的實現了抽象類的全部 //抽象方法,也能夠,以下 val animal = new Animal { override def sayHello (): Unit = { println ("say hello~~~~") } } animal.sayHello ()
2) 抽象類不必定要包含abstract方法,也就是說,抽象類能夠沒有abstract方法
abstract class Animal { //在抽象類中能夠有實現的方法 def sayHi (): Unit = { println("hello") } }
3) 一旦類包含了抽象方法或者抽象屬性,則這個類必須聲明爲abstract
4) 抽象方法不能有主體,不容許使用abstract修飾
5) 若是一個類繼承了抽象類,則它必須實現抽象類中全部的抽象方法和抽象屬性,除非它本身也聲明爲abstract類
abstract class Animal { def sayHello() var food: String } class Dog extends Animal { override def sayHello(): Unit = { println("小狗汪汪叫!") } override var food: String = _ }
6) 抽象方法和抽象屬性不能使用private、final來修飾,由於這些關鍵字都是和重寫/實現相違背的
7) 抽象類中能夠有實現的方法
8) 子類重寫抽象方法不須要override,寫上也不會錯
-基本介紹
和Java同樣,能夠經過包含帶有定義或重寫的代碼塊的方式建立一個匿名的子類
-回顧-Java中匿名子類的使用
public class NoNameDemo01 { public static void main(String[] args) { //在java中去建立一個匿名子類對象 A a = new A() { @Override public void cry() { System.out.println("cry..."); } }; a.cry(); } } abstract class A { abstract public void cry(); }
-Scala匿名子類的使用
object boke_demo01 { def main(args: Array[String]): Unit = { val monster = new Monster { override def cry(): Unit = { println("...:)") } override var name: String = _ } monster.cry() } } abstract class Monster { var name: String def cry() }
-Scala繼承層級一覽圖
-對上圖的一個小結
1) 在Scala中,全部其它類都是AnyRef的子類,相似Java的Obiect
2) AnyVal和AnyRef都擴展自Any類,Any類是子節點
3) Any中定義了isInstanceOf、asInstanceOf方法,以及哈希方法等
4) Null類型的惟一實例就是null對象,能夠將null賦值給任何引用,但不能賦值給值類型的變量
5) Nothing類型沒有實例,它對於泛型結構是有用處的,舉例:空列表Nil的類型就是List[Nothing],它是List[T]的子類型,T能夠是任何類