1 Scala 包
1.1 包風格
??Scala 有兩種包的管理風格。
- 第一種 Java 的包管理風格相同,每個源文件一個包(包 名和源文件所在路徑不要求必須一致),包名用“.”進行分隔以表示包的層級關系,如 com.atguigu.scala。
- 另一種風格,通過嵌套的風格表示層級關系,一個源文件中可以聲明多個 package,子包中的類可以直接訪問父包中的內(nèi)容,而無需導包
package com {
package scala {
package chapter06 {
object TestPackage {
def main(args: Array[String]): Unit = {
println("package test!")
}
}
}
}
}
package com {
import com.scala.chapter06.other.Inner.in //父包訪問子包需要導包
package scala {
package chapter06 {
object TestPackage {
val out: String = "out"
def main(args: Array[String]): Unit = {
println("package test!")
println(in)
}
}
package other {
object Inner {
val in: String = "in"
def main(args: Array[String]): Unit = {
println(TestPackage.out) //子包訪問父包無需導包
}
}
}
}
}
}
1.2 包對象
- 在 Scala 中可以為每個包定義一個同名的包對象,定義在包對象中的成員,作為其對 應包下所有 class 和 object 的共享變量,可以被直接訪問。
- 若使用 Java 的包管理風格,則包對象一般定義在其對應包下的 package.scala 文件中,包對象名與包名保持一致。
package com.scala
package object chapter06 {
}
- 如采用嵌套方式管理包,則包對象可與包定義在同一文件中,但是要保證包對象 與包聲明在同一作用域中。
package com {
package scala {
package chapter06 {
object TestPackage {
val out: String = "out"
def main(args: Array[String]): Unit = {
println("package test!")
println(in)
}
}
}
}
}
package object com {
val shareValue = "share"
def shareMethod() = {}
}
1.3 導包
- 和 Java 一樣,可以在頂部使用 import 導入,在這個文件中的所有類都可以使用。
- 局部導入:什么時候使用,什么時候?qū)搿T谄渥饔梅秶鷥?nèi)都可以使用
- 通配符導入:import java.util._
- 給類起名:import java.util.{ArrayList=>JL}
- 導入相同包的多個類:import java.util.{HashSet, ArrayList}
- 屏蔽類:import java.util.{ArrayList =>,}
- 導入包的絕對路徑:new root.java.util.HashMap
- Scala 中的三個默認導入的包
import java.lang._
import scala._
import scala.Predef._
1.4包訪問權限
- Scala 中屬性和方法的默認訪問權限為 public,但 Scala 中無 public 關鍵字。
- private 為私有權限,只在類的內(nèi)部和伴生對象中可用。
- protected 為受保護權限,Scala 中受保護權限比 Java 中更嚴格,同類、子類可以訪問,同包無法訪問。
- private[包名]增加包訪問權限,包名下的其他類也可以使用
package com.scala
package chapter06
class Person {
private var name: String = "bobo"
protected var age: Int = 18
private[chapter06] var sex: String = "男"
def say(): Unit = {
println(name)
}
}
object Person {
def main(args: Array[String]): Unit = {
val person = new Person
person.say()
println(person.name)
println(person.age)
}
}
class Teacher extends Person {
def test(): Unit = {
this.age
this.sex
}
}
class Animal {
def test: Unit = {
new Person().sex
}
}
2 類和對象
2.1 類
- 語法
[修飾符] class 類名 {
類體
}
- Scala 語法中,類并不聲明為 public,所有這些類都具有公有可見性(即默認就是public)
- 一個 Scala 源文件可以包含多個類
2.1 屬性
- 語法
[修飾符] var|val 屬性名稱 [:類型] = 屬性值
var name: String = "bobo"
- Bean 屬性(@BeanPropetry),可以自動生成規(guī)范的 setXxx/getXxx 方法
package com.scala
package chapter06
import scala.beans.BeanProperty
class Person {
//Bean 屬性(@BeanProperty)
@BeanProperty var sex: String = "男"
}
object Person {
def main(args: Array[String]): Unit = {
var person = new Person()
person.setSex("女")
println(person.getSex)
}
}
- _表示給屬性一個默認值
package com.scala
package chapter06
import scala.beans.BeanProperty
class Person {
var age: Int = _ // _表示給屬性一個默認值
}
object Person {
def main(args: Array[String]): Unit = {
var person = new Person()
println(person.age)
}
}
- val 修飾的屬性不能賦默認值,必須顯示指定
//val school: Int = _ // _表示給屬性一個默認值
2.3 方法
def 方法名(參數(shù)列表) [:返回值類型] = {
方法體
}
2.4 創(chuàng)建對象
- 語法
val | var 對象名 [:類型] = new 類型()
- val 修飾對象,不能改變對象的引用(即:內(nèi)存地址),可以改變對象屬性的值。
- var 修飾對象,可以修改對象的引用和修改對象的屬性值
- 自動推導變量類型不能多態(tài),所以多態(tài)需要顯示聲明
- 案例
class Person {
var name: String = "canglaoshi"
}
object Person {
def main(args: Array[String]): Unit = {
//val 修飾對象,不能改變對象的引用(即:內(nèi)存地址),可以改變對象屬 性的值。
val person = new Person()
person.name = "bobo"
// person = new Person()// 錯誤的
println(person.name)
}
}
2.5 構造器
- Scala 類的構造器包括:主構造器和輔助構造器
- 語法
class 類名(形參列表) { // 主構造器
// 類體
def this(形參列表) { // 輔助構造器
}
def this(形參列表) { //輔助構造器可以有多個...
}
}
- 輔助構造器,函數(shù)的名稱 this,可以有多個,編譯器通過參數(shù)的個數(shù)及類型來區(qū)分。
- 輔助構造方法不能直接構建對象,必須直接或者間接調(diào)用主構造方法。
- 構造器調(diào)用其他另外的構造器,要求被調(diào)用構造器必須提前聲明。
- 如果主構造器無參數(shù),小括號可省略,構建對象時調(diào)用的構造方法的小括號也可 以省略。
- 案例
class Person {
var name: String = _
var age: Int = _
def this(age: Int) {
this()
this.age = age
println("輔助構造器")
}
def this(age: Int, name: String) {
this(age)
this.name = name
}
println("主構造器")
}
object Person {
def main(args: Array[String]): Unit = {
val person2 = new Person(18)
}
}
2.6 構造器參數(shù)
??Scala 類的主構造器函數(shù)的形參包括三種類型:未用任何修飾、var 修飾、val 修飾
- 未用任何修飾符修飾,這個參數(shù)就是一個局部變量
- var 修飾參數(shù),作為類的成員屬性使用,可以修改
- val 修飾參數(shù),作為類只讀屬性使用,不能修改
class Person(name: String, var age: Int, val sex: String) {
}
object Test {
def main(args: Array[String]): Unit = {
var person = new Person("bobo", 18, "男")
// (1)未用任何修飾符修飾,這個參數(shù)就是一個局部變量
//printf(person.name)
// (2)var 修飾參數(shù),作為類的成員屬性使用,可以修改
person.age = 19
println(person.age)
// (3)val 修飾參數(shù),作為類的只讀屬性使用,不能修改
// person.sex = "女"
println(person.sex)
}
}
3 封裝
??封裝就是把抽象出的數(shù)據(jù)和對數(shù)據(jù)的操作封裝在一起,數(shù)據(jù)被保護在內(nèi)部,程序的其它 部分只有通過被授權的操作(成員方法),才能對數(shù)據(jù)進行操作。
??Scala 中的 public 屬性,底層實際為 private,并通過 get 方法(obj.field())和 set 方法 (obj.field_=(value))對其進行操作。所以 Scala 并不推薦將屬性設為 private,再為其設置 public 的 get 和 set 方法的做法。但由于很多 Java 框架都利用反射調(diào)用 getXXX 和 setXXX 方 法,有時候為了和這些框架兼容,也會為 Scala 的屬性設置 getXXX 和 setXXX 方法(通過 @BeanProperty 注解實現(xiàn))。
4 繼承&多態(tài)
- 語法
class 子類名 extends 父類名 { 類體 }
- 子類繼承父類的屬性和方法
- scala 是單繼承
- 繼承的調(diào)用順序:父類構造器->子類構造器
class Person(nameParam: String) {
var name = nameParam
var age: Int = _
def this(nameParam: String, ageParam: Int) {
this(nameParam)
this.age = ageParam
println("父類輔助構造器")
}
println("父類主構造器")
}
class Emp(nameParam: String, ageParam: Int) extends
Person(nameParam, ageParam) {
var empNo: Int = _
def this(nameParam: String, ageParam: Int, empNoParam: Int) {
this(nameParam, ageParam)
this.empNo = empNoParam
println("子類的輔助構造器")
}
println("子類主構造器")
}
object Person{
def main(args: Array[String]): Unit = {
new Emp("z3", 11, 1001)
}
}
5. 動態(tài)綁定:Scala 中屬性和方法都是動態(tài)綁定,而 Java 中只有方法為動態(tài)綁定。
class Person {
val name: String = "person"
def hello(): Unit = {
println("hello person")
}
}
class Teacher extends Person {
override val name: String = "teacher"
override def hello(): Unit = {
println("hello teacher")
}
}
object Test {
def main(args: Array[String]): Unit = {
val teacher: Teacher = new Teacher()
println(teacher.name)
teacher.hello()
println("----------------------------------------")
val teacher1:Person = new Teacher
println(teacher1.name)
teacher1.hello()
}
}
5 抽象類
5.1 語法
- 定義抽象類
abstract class Person{} //通過 abstract 關鍵字標記抽象類
- 定義抽象屬性
val|var name:String //一個屬性沒有初始化,就是抽象屬性
- 定義抽象方法
def hello():String //只聲明而沒有實現(xiàn)的方法,就是抽象方法
abstract class Person {
val name: String
def hello(): Unit
}
class Teacher extends Person {
val name: String = "teacher"
def hello(): Unit = {
println("hello teacher")
}
}
5.2 繼承&重寫
- 如果父類為抽象類,那么子類需要將抽象的屬性和方法實現(xiàn),否則子類也需聲明為抽象類
- 重寫非抽象方法需要用 override 修飾,重寫抽象方法則可以不加 override。
- 子類中調(diào)用父類的方法使用 super 關鍵字
- 子類對抽象屬性進行實現(xiàn),父類抽象屬性可以用 var 修飾;子類對非抽象屬性重寫,父類非抽象屬性只支持 val 類型,而不支持 var。因為 var 修飾的為可變變量,子類繼承之后就可以直接使用,沒有必要重寫
5.3 匿名子類
??和 Java 一樣,可以通過包含帶有定義或重寫的代碼塊的方式創(chuàng)建一個匿名的子類。
abstract class Person {
val name: String
def hello(): Unit
}
object Test {
def main(args: Array[String]): Unit = {
val person = new Person {
override val name: String = "teacher"
override def hello(): Unit = println("hello teacher")
}
}
}
6 單例對象(伴生對象)
6.1 概述
??Scala語言是完全面向?qū)ο蟮恼Z言,所以并沒有靜態(tài)的操作(即在Scala中沒有靜態(tài)的概 念)。但是為了能夠和Java語言交互(因為Java中有靜態(tài)概念),就產(chǎn)生了一種特殊的對象 來模擬類對象,該對象為單例對象。若單例對象名與類名一致,則稱該單例對象這個類的伴生對象,這個類的所有“靜態(tài)”內(nèi)容都可以放置在它的伴生對象中聲明
6.2 語法
object Person{ val country:String="China" }
- 單例對象采用 object 關鍵字聲明
- 單例對象對應的類稱之為伴生類,伴生對象的名稱應該和伴生類名一致。
- 單例對象中的屬性和方法都可以通過伴生對象名(類名)直接調(diào)用訪問。
//(1)伴生對象采用 object 關鍵字聲明
object Person {
var country: String = "China"
}
//(2)伴生對象對應的類稱之為伴生類,伴生對象的名稱應該和伴生類名一致。
class Person {
var name: String = "bobo"
}
object Test {
def main(args: Array[String]): Unit = {
//(3)伴生對象中的屬性和方法都可以通過伴生對象名(類名)直接調(diào)用訪 問。
println(Person.country)
}
}
6.3 apply 方法
- 通過伴生對象的 apply 方法,實現(xiàn)不使用 new 方法創(chuàng)建對象。
- 如果想讓主構造器變成私有的,可以在()之前加上 private。
- apply 方法可以重載。
- Scala 中 obj(arg)的語句實際是在調(diào)用該對象的 apply 方法,即 obj.apply(arg)。用以統(tǒng)一面向?qū)ο缶幊毯秃瘮?shù)式編程的風格。
- 當使用 new 關鍵字構建對象時,調(diào)用的其實是類的構造方法,當直接使用類名構建對象時,調(diào)用的其實時伴生對象的 apply 方法
object Test {
def main(args: Array[String]): Unit = {
//(1)通過伴生對象的 apply 方法,實現(xiàn)不使用 new 關鍵字創(chuàng)建對象。
val p1 = Person()
println("p1.name=" + p1.name)
val p2 = Person("bobo")
println("p2.name=" + p2.name)
}
}
//(2)如果想讓主構造器變成私有的,可以在()之前加上 private
class Person private(cName: String) {
var name: String = cName
}
object Person {
def apply(): Person = {
println("apply 空參被調(diào)用")
new Person("xx")
}
def apply(name: String): Person = {
println("apply 有參被調(diào)用")
new Person(name)
}
}
7 特質(zhì)
7.1 概述
?? Scala 語言中,采用特質(zhì) trait(特征)來代替接口的概念,也就是說,多個類具有相同的特質(zhì)(特征)時,就可以將這個特質(zhì)(特征)獨立出來,采用關鍵字 trait 聲明。
??Scala 中的 trait 中即可以有抽象屬性和方法,也可以有具體的屬性和方法,一個類可以混入(mixin)多個特質(zhì)。這種感覺類似于 Java 中的抽象類。
??Scala 引入 trait 特征,第一可以替代 Java 的接口,第二個也是對單繼承機制的一種補充。
7.2 語法&說明
- 聲明
trait 特質(zhì)名 {
trait 主體
}
trait PersonTrait {
// 聲明屬性
var name:String = _
// 聲明方法
def eat():Unit={
}
// 抽象屬性
var age:Int
// 抽象方法
def say():Unit
}
- 一個類具有某種特質(zhì)(特征),就意味著這個類滿足了這個特質(zhì)(特征)的所有要素, 所以在使用時,也采用了 extends 關鍵字,如果有多個特質(zhì)或存在父類,那么需要采用 with 關鍵字連接。
- 類和特質(zhì)的關系:使用繼承的關系。
- 當一個類去繼承特質(zhì)時,第一個連接詞是 extends,后面是 with。
- 如果一個類在同時繼承特質(zhì)和父類時,應當把父類寫在 extends 后。
沒有父類:class 類名 extends 特質(zhì) 1 with 特質(zhì) 2 with 特質(zhì) 3 …
有父類:class 類名 extends 父類 with 特質(zhì) 1 with 特質(zhì) 2 with 特質(zhì) 3…
- 特質(zhì)可以同時擁有抽象方法和具體方法
- 一個類可以混入(mixin)多個特質(zhì)
- 所有的 Java 接口都可以當做 Scala 特質(zhì)使用
- 動態(tài)混入:可靈活的擴展類的功能
動態(tài)混入:創(chuàng)建對象時混入 trait,而無需使類混入該 trait
如果混入的 trait 中有未實現(xiàn)的方法,則需要實現(xiàn)
package com.scala
package chapter07
trait PersonTrait {
//(1)特質(zhì)可以同時擁有抽象方法和具體方法
// 聲明屬性
var name: String = _
// 抽象屬性
var age: Int
// 聲明方法
def eat(): Unit = {
println("eat")
}
// 抽象方法
def say(): Unit
}
trait SexTrait {
var sex: String
}
//(2)一個類可以實現(xiàn)/繼承多個特質(zhì)
//(3)所有的 Java 接口都可以當做 Scala 特質(zhì)使用
class Teacher extends PersonTrait with java.io.Serializable {
override def say(): Unit = {
println("say")
}
override var age: Int = _
}
object TestTrait {
def main(args: Array[String]): Unit = {
val teacher = new Teacher
teacher.say()
teacher.eat()
//(4)動態(tài)混入:可靈活的擴展類的功能
val t2 = new Teacher with SexTrait {
override var sex: String = "男"
}
//調(diào)用混入 trait 的屬性
println(t2.sex)
}
}
7.3 特質(zhì)疊加
??由于一個類可以混入(mixin)多個 trait,且 trait 中可以有具體的屬性和方法,若混入的特質(zhì)中具有相同的方法(方法名,參數(shù)列表,返回值均相同),必然會出現(xiàn)繼承沖突問題。沖突分為以下兩種
-
一個類(Sub)混入的兩個 trait(TraitA,TraitB)中具有相同的具體方法,且兩個 trait 之間沒有任何關系,解決這類沖突問題,直接在類(Sub)中重寫沖突方法。
-
一個類(Sub)混入的兩個 trait(TraitA,TraitB)中具有相同的具體方法,且兩個 trait 繼承自相同的 trait(TraitC),及所謂的“鉆石問題”,解決這類沖突問題,Scala采用了特質(zhì)疊加的策略。
所謂的特質(zhì)疊加,就是將混入的多個 trait 中的沖突方法疊加起來文章來源:http://www.zghlxwxcb.cn/news/detail-824040.html
7.4 特質(zhì)疊加執(zhí)行順序
package com.scala
package chapter07
trait Ball {
def describe(): String = {
"ball"
}
}
trait Color extends Ball {
override def describe(): String = {
"blue-" + super.describe()
}
}
trait Category extends Ball {
override def describe(): String = {
"foot-" + super.describe()
}
}
class MyBall extends Category with Color {
override def describe(): String = {
"my ball is a " + super.describe()
}
}
object TestTrait1 {
def main(args: Array[String]): Unit = {
println(new MyBall().describe())
}
}
- 當一個類混入多個特質(zhì)的時候,scala 會對所有的特質(zhì)及其父特質(zhì)按照一定的順序進行 排序,而此案例中的 super.describe()調(diào)用的實際上是排好序后的下一個特質(zhì)中的 describe() 方法。
- 疊加規(guī)則:
- 案例中的 super,不是表示其父特質(zhì)對象,而是表示上述疊加順序中的下一個特質(zhì), 即,MyClass 中的 super 指代 Color,Color 中的 super 指代 Category,Category 中的 super 指代 Ball。
- )如果想要調(diào)用某個指定的混入特質(zhì)中的方法,可以增加約束:super[],例如super[Category].describe()。
7.5 特質(zhì)喝抽象類的區(qū)別
- 優(yōu)先使用特質(zhì)。一個類擴展多個特質(zhì)是很方便的,但卻只能擴展一個抽象類。
- 如果你需要構造函數(shù)參數(shù),使用抽象類。因為抽象類可以定義帶參數(shù)的構造函數(shù), 而特質(zhì)不行(有無參構造)。
8 擴展
8.1 類型檢查和轉換
- obj.isInstanceOf[T]:判斷 obj 是不是 T 類型。
- obj.asInstanceOf[T]:將 obj 強轉成 T 類型。
- classOf 獲取對象的類名。
package com.scala
package chapter07
class Person {
}
object Person {
def main(args: Array[String]): Unit = {
val person = new Person
//(1)判斷對象是否為某個類型的實例
val bool: Boolean = person.isInstanceOf[Person]
if (bool) {
//(2)將對象轉換為某個類型的實例
val p1: Person = person.asInstanceOf[Person]
println(p1)
}
//(3)獲取類的信息
val pClass: Class[Person] = classOf[Person]
println(pClass)
}
}
8.2 枚舉類和應用類
- 枚舉類:需要繼承 Enumeration
- 應用類:需要繼承 App
package com.scala
package chapter07
object Test {
def main(args: Array[String]): Unit = {
println(Color1.YELLOW)
}
}
// 枚舉類
object Color1 extends Enumeration {
val RED = Value(1, "red")
val YELLOW = Value(2, "yellow")
val BLUE = Value(3, "blue")
}
// 應用類
object Test20 extends App {
println("xxxxxxxxxxx");
}
8.3 Type 定義新類型
??使用 type 關鍵字可以定義新的數(shù)據(jù)數(shù)據(jù)類型名稱,本質(zhì)上就是類型的一個別名文章來源地址http://www.zghlxwxcb.cn/news/detail-824040.html
object Test {
def main(args: Array[String]): Unit = {
type S=String
var v:S="abc"
def test():S="xyz"
}
}
到了這里,關于【Scala】——面向?qū)ο蟮奈恼戮徒榻B完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!