生活随笔
收集整理的這篇文章主要介紹了
第四课 尚硅谷Scala语言学习-面向对象
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
第四課 尚硅谷Scala語言學習-面向對象
文章目錄
- 第四課 尚硅谷Scala語言學習-面向對象
- 第一節 Scala 包
- 1.1 包基本語法
- 1.2 包說明
- 1.3 包對象
- 1.4 導包說明
- 第二節 類和對象
- 2.1 定義類
- 2.2 封裝
- 2.3 繼承
- 2.4 多態
- 第三節 抽象類和伴生對象
- 3.1 抽象屬性和抽象方法
- 3.2 匿名子類
- 3.3 伴生對象
- 3.4 伴生對象應用單例模式
- 第四節 特質
- 4.1 特質聲明
- 4.2 特質疊加
- 4.3 特質自身類型
- 第五節 拓展
- 5.1 類型檢查和轉換
- 5.2 枚舉類和應用類
- 5.3 Type 定義新類型
第一節 Scala 包
1.1 包基本語法
Scala 的面向對象思想和 Java 的面向對象思想和概念是一致的。Scala 中語法和 Java 不同,補充了更多的功能。Scala 包的三大作用(和 Java 一樣) - 區分相同名字的類
- 當類很多時,可以很好的管理類
- 控制訪問范圍
包的命名。 - 命名規則:只能包含數字、字母、下劃線、小圓點.,但不能用數字開頭,也不要使用關鍵字。
- 命名規范:一般是小寫字母+小圓點com.公司名.項目名.業務模塊名
com.atguigu.oa.model
com.atguigu.oa.controller
com.sohu.bank.order
1.2 包說明
Scala 有兩種包的管理風格,一種方式和 Java 的包管理風格相同,每個源文件一個包(包名和源文件所在路徑不要求必須一致),包名用“.”進行分隔以表示包的層級關系,如com.atguigu.scala。另一種風格,通過嵌套的風格表示層級關系。第二種風格有以下特點: - 一個源文件中可以聲明多個 package
- 子包中的類可以直接訪問父包中的內容,而無需導包
package com{package atguigu{package scala{}}
}
實例介紹
package com{import com.atguigu.scala.Inner
object Outer
{var out
: String = "out"def main
(args
: Array
[String]): Unit = {println
(Inner
.in
)}}package atguigu{package scala{object Inner
{var in
: String = "in"def main
(args
: Array
[String]): Unit = {println
(Outer
.out
)Outer
.out
= "outer"println
(Outer
.out
)}}}}
}
package aaa{package bbb{object Test01_Package
{def main
(args
: Array
[String]): Unit = {import com.atguigu.scala.Innerprintln
(Inner
.in
)}}}
}
1.3 包對象
在 Scala 中可以為每個包定義一個同名的包對象,定義在包對象中的成員,作為其對應包下所有 class 和 object 的共享變量,可以被直接訪問。
package object chapter06
{val commonValue
= "尚硅谷"def commonMethod
() = {println
(s"我們在${commonValue}學習")}
}
若使用 Java 的包管理風格,則包對象一般定義在其對應包下的package.scala文件中,包對象名與包名保持一致。
package chapter06{object Test02_PackageObject
{def main
(args
: Array
[String]): Unit = {commonMethod
()println
(commonValue
)}}
}
如采用嵌套方式管理包,則包對象可與包定義在同一文件中,但是要保證包對象與包聲明在同一作用域中。
package ccc{package ddd{object Test02_PackageObject
{def main
(args
: Array
[String]): Unit = {println
(school
)}}}
}
package object ccc
{val school
: String = "atguigu"
}
1.4 導包說明
和 Java 一樣,可以在頂部使用 import 導入,在這個文件中的所有類都可以使用。局部導入:什么時候使用,什么時候導入。在其作用范圍內都可以使用通配符導入:import java.util._給類起名:import java.util.{ArrayList=>JL}導入相同包的多個類:import java.util.{HashSet, ArrayList}屏蔽類:import java.util.{ArrayList =>_,_}導入包的絕對路徑:new _root_.java.util.HashMapScala 中的三個默認導入分別是 - import java.lang._
- import scala._
- import scala.Predef._
第二節 類和對象
2.1 定義類
類:可以看成一個模板對象:表示具體的事物Java 中的類, 如果類是 public 的,則必須和文件名一致。一般,一個.java 有一個 public 類注意:Scala 中沒有 public,一個.scala 中可以寫多個類。, 基本語法
[修飾符
] class 類名
{類體
}
說明 - Scala 語法中,類并不聲明為 public,所有這些類都具有公有可見性(即默認就是public)
- 一個 Scala 源文件可以包含多個類
屬性是類的一個組成部分, 注:Bean 屬性(@BeanPropetry),可以自動生成規范的 setXxx/getXxx 方法
[修飾符
] var|val 屬性名稱
[:類型
] = 屬性值
案例實操
package chapter06import scala.beans.BeanProperty
object Test03_Class
{def main
(args
: Array
[String]): Unit = {val student
= new Student
()
println
(student
.age
)println
(student
.sex
)student
.sex
= "female"println
(student
.sex
)}
}
class Student
{private var name
: String = "alice"@BeanPropertyvar age
: Int = _
var sex
: String = _
}
2.2 封裝
封裝就是把抽象出的數據和對數據的操作封裝在一起,數據被保護在內部,程序的其它部分只有通過被授權的操作(成員方法),才能對數據進行操作。Java 封裝操作如下, - 將屬性進行私有化
- 提供一個公共的 set 方法,用于對屬性賦值
- 提供一個公共的 get 方法,用于獲取屬性的值
Scala 中的 public 屬性,底層實際為 private,并通過 get 方法(obj.field())和 set 方法(obj.field_=(value))對其進行操作。所以 Scala 并不推薦將屬性設為 private,再為其設置public 的 get 和 set 方法的做法。但由于很多 Java 框架都利用反射調用 getXXX 和 setXXX 方法,有時候為了和這些框架兼容,也會為 Scala 的屬性設置 getXXX 和 setXXX 方法(通過@BeanProperty 注解實現)。
2.2.1 訪問權限
在 Java 中,訪問權限分為:public,private,protected 和默認。在 Scala 中,你可以通過類似的修飾符達到同樣的效果。但是使用上有區別。 - Scala 中屬性和方法的默認訪問權限為 public,但 Scala 中無 public 關鍵字。
- private 為私有權限,只在類的內部和伴生對象中可用。
- protected 為受保護權限,Scala 中受保護權限比 Java 中更嚴格,同類、子類可以訪問,同包無法訪問。
- private[包名]增加包訪問權限,包名下的其他類也可以使用
package chapter06object Test04_ClassForAccess
{}
class Person
{private var idCard
: String = "3523566"protected var name
: String = "alice"var sex
: String = "female"private[chapter06
] var age
: Int = 18def printInfo
(): Unit = {println
(s"Person: $idCard $name $sex $age")}
}
創建對象 - val 修飾對象,不能改變對象的引用(即:內存地址),可以改變對象屬性的值。
- var 修飾對象,可以修改對象的引用和修改對象的屬性值
- 自動推導變量類型不能多態,所以多態需要顯示聲明
val | var 對象名
[:類型
] = new 類型
()
子類繼承
package chapter06object Test04_Access
{def main
(args
: Array
[String]): Unit = {val person
: Person
= new Person
()
println
(person
.age
)println
(person
.sex
)person
.printInfo
()var worker
: Worker
= new Worker
()
worker
.printInfo
()}
}
class Worker
extends Person
{override def printInfo
(): Unit = {
name
= "bob"age
= 25sex
= "male"println
(s"Worker: $name $sex $age")}
}
2.2.2 構造器
和 Java 一樣,Scala 構造對象也需要調用構造方法,并且可以有任意多個構造方法。Scala 類的構造器包括:主構造器和輔助構造器基本語法 - 輔助構造器,函數的名稱 this,可以有多個,編譯器通過參數的個數及類型來區分。
- 輔助構造方法不能直接構建對象,必須直接或者間接調用主構造方法。
- 構造器調用其他另外的構造器,要求被調用構造器必須提前聲明。
class 類名
(形參列表
) { def this(形參列表
) { }def this(形參列表
) { }}
案例實操 - 如果主構造器無參數,小括號可省略,構建對象時調用的構造方法的小括號也可以省略。
package chapter06object Test05_Constructor
{def main
(args
: Array
[String]): Unit = {val student1
= new Student1student1
.Student1
()val student2
= new Student1
("alice")val student3
= new Student1
("bob", 25)}
}
class Student1
() {var name
: String = _
var age
: Int = _println
("1. 主構造方法被調用")def this(name
: String) {this() println
("2. 輔助構造方法一被調用")this.name
= nameprintln
(s"name: $name age: $age")}def this(name
: String, age
: Int){this(name
)println
("3. 輔助構造方法二被調用")this.age
= ageprintln
(s"name: $name age: $age")}def Student1
(): Unit = {println
("一般方法被調用")}
}
構造器參數, Scala 類的主構造器函數的形參包括三種類型:未用任何修飾、var 修飾、val 修飾 - 未用任何修飾符修飾,這個參數就是一個局部變量
- var 修飾參數,作為類的成員屬性使用,可以修改
- val 修飾參數,作為類只讀屬性使用,不能修改
package chapter06object Test06_ConstructorParams
{def main
(args
: Array
[String]): Unit = {val student2
= new Student2student2
.name
= "alice"student2
.age
= 18println
(s"student2: name = ${student2.name}, age = ${student2.age}")val student3
= new Student3
("bob", 20)println
(s"student3: name = ${student3.name}, age = ${student3.age}")val student4
= new Student4
("cary", 25)
student4
.printInfo
()val student5
= new Student5
("bob", 20)println
(s"student3: name = ${student5.name}, age = ${student5.age}")student3
.age
= 21val student6
= new Student6
("cary", 25, "atguigu")println
(s"student6: name = ${student6.name}, age = ${student6.age}")student6
.printInfo
()}
}
class Student2
{var name
: String = _
var age
: Int = _
}
class Student3
(var name
: String, var age
: Int)
class Student4
(name
: String, age
: Int){def printInfo
(){println
(s"student4: name = ${name}, age = $age")}
}
class Student5
(val name
: String, val age
: Int)class Student6
(var name
: String, var age
: Int){var school
: String = _
def this(name
: String, age
: Int, school
: String){this(name
, age
)this.school
= school
}def printInfo
(){println
(s"student6: name = ${name}, age = $age, school = $school")}
}
2.3 繼承
基本語法
class 子類名
extends 父類名
{ 類體
}
案例實操 - 子類繼承父類的屬性和方法
- 繼承的調用順序:父類構造器->子類構造器
package chapter06object Test07_Inherit
{def main
(args
: Array
[String]): Unit = {val student1
: Student7
= new Student7
("alice", 18)val student2
= new Student7
("bob", 20, "std001")student1
.printInfo
()student2
.printInfo
()val teacher
= new Teacherteacher
.printInfo
()def personInfo
(person
: Person7
): Unit = {person
.printInfo
()}println
("=========================")val person
= new Person7personInfo
(student1
)personInfo
(teacher
)personInfo
(person
)}
}
class Person7
() {var name
: String = _
var age
: Int = _println
("1. 父類的主構造器調用")def this(name
: String, age
: Int){this()println
("2. 父類的輔助構造器調用")this.name
= name
this.age
= age
}def printInfo
(): Unit = {println
(s"Person: $name $age")}
}
class Student7
(name
: String, age
: Int) extends Person7
(name
, age
) {var stdNo
: String = _println
("3. 子類的主構造器調用")def this(name
: String, age
: Int, stdNo
: String){this(name
, age
)println
("4. 子類的輔助構造器調用")this.stdNo
= stdNo
}override def printInfo
(): Unit = {println
(s"Student: $name $age $stdNo")}
}class Teacher
extends Person7
{override def printInfo
(): Unit = {println
(s"Teacher")}
}
2.4 多態
動態綁定, 編譯期間便綁定死是靜態綁定。運行時才去判斷實例是動態綁定。 - Scala 中屬性和方法都是動態綁定,而 Java 中只有方法為動態綁定,屬性是靜態綁定。
package chapter06object Test08_DynamicBind
{def main
(args
: Array
[String]): Unit = {val student
: Person8
= new Student8println
(student
.name
)student
.hello
()}
}class Person8
{val name
: String = "person"def hello
(): Unit = {println
("hello person")}
}class Student8
extends Person8
{override val name
: String = "student"override def hello
(): Unit = {println
("hello student")}
}
public class TestDynamicBind {public static void main(String[] args
) {Worker worker
= new Worker();System.out
.println(worker
.name
);worker
.hello();worker
.hi();System.out
.println("===================");Person person
= new Worker();System.out
.println(person
.name
); person
.hello();
}
}class Person {String name
= "person";public void hello() {System.out
.println("hello person");}
}class Worker extends Person {String name
= "worker";public void hello() {System.out
.println("hello worker");}public void hi() {System.out
.println("hi worker");}
}
第三節 抽象類和伴生對象
3.1 抽象屬性和抽象方法
基本語法 - 定義抽象類:abstract class Person{} //通過 abstract 關鍵字標記抽象類
- 定義抽象屬性:val|var name:String //一個屬性沒有初始化,就是抽象屬性
- 定義抽象方法:def hello():String //只聲明而沒有實現的方法,就是抽象方法
繼承&重寫 - 如果父類為抽象類,那么子類需要將抽象的屬性和方法實現,否則子類也需聲明為抽象類
- 重寫非抽象方法需要用 override 修飾,重寫抽象方法則可以不加 override。
- 子類中調用父類的方法使用 super 關鍵字
- 子類對抽象屬性進行實現,父類抽象屬性可以用 var 修飾;
- 子類對非抽象屬性重寫,父類非抽象屬性只支持 val 類型,而不支持 var。 因為 var 修飾的為可變變量,子類繼承之后就可以直接使用,沒有必要重寫
案例實操
package chapter06object Test09_AbstractClass
{def main
(args
: Array
[String]): Unit = {val student
= new Student9student
.eat
()student
.sleep
()}
}
abstract class Person9
{var name
: String = "person"var age
: Intdef eat
(): Unit = {println
("person eat")}def sleep
(): Unit
}
class Student9
extends Person9
{var age
: Int = 18def sleep
(): Unit = {println
("student sleep")}
name
= "student"override def eat
(): Unit = {super.eat
()println
("student eat")}
}
3.2 匿名子類
和 Java 一樣,可以通過包含帶有定義或重寫的代碼塊的方式創建一個匿名的子類。
package chapter06object Test10_AnnoymousClass
{def main
(args
: Array
[String]): Unit = {val person
: Person10
= new Person10
{override var name
: String = "alice"override def eat
(): Unit = println
("person eat")}println
(person
.name
)person
.eat
()}
}
abstract class Person10
{var name
: Stringdef eat
(): Unit
}
3.3 伴生對象
Scala語言是完全面向對象的語言,所以并沒有靜態的操作(即在Scala中沒有靜態的概念)。但是為了能夠和Java語言交互(因為Java中有靜態概念),就產生了一種特殊的對象來模擬類對象,該對象為單例對象。若單例對象名與類名一致,則稱該單例對象這個類的伴生對象,這個類的所有“靜態”內容都可以放置在它的伴生對象中聲明。單例對象語法 - 單例對象采用object關鍵字聲明
- 單例對象對應的類稱之為伴生類,伴生對象的名稱應該和伴生類名一致。
- 單例對象中的屬性和方法都可以通過伴生對象名(類名)直接調用訪問。即使是私有屬性和方法也可以相互訪問。
apply 方法 - 通過伴生對象的 apply 方法,實現不使用 new 方法創建對象。
- 如果想讓主構造器變成私有的,可以在()之前加上 private。
- apply 方法可以重載。
- Scala 中 obj(arg)的語句實際是在調用該對象的 apply 方法,即 obj.apply(arg)。用以統一面向對象編程和函數式編程的風格。
- 當使用 new 關鍵字構建對象時,調用的其實是類的構造方法,當直接使用類名構建對象時,調用的其實時伴生對象的 apply 方法。
package chapter06object Test11_Object
{def main
(args
: Array
[String]): Unit = {
val student1
= Student11
.newStudent
("alice", 18)student1
.printInfo
()val student2
= Student11
.apply
("bob", 19) student2
.printInfo
()val student3
= Student11
("bob", 19)student3
.printInfo
()}
}
class Student11
private(val name
: String, val age
: Int){def printInfo
(){println
(s"student: name = ${name}, age = $age, school = ${Student11.school}")}
}
object Student11
{val school
: String = "atguigu"def newStudent
(name
: String, age
: Int): Student11
= new Student11
(name
, age
)def apply
(name
: String, age
: Int): Student11
= new Student11
(name
, age
)
}
3.4 伴生對象應用單例模式
package chapter06object Test12_Singleton
{def main
(args
: Array
[String]): Unit = {val student1
= Student12
.getInstance
()student1
.printInfo
()val student2
= Student12
.getInstance
()student2
.printInfo
()println
(student1
)println
(student2
)}
}class Student12
private(val name
: String, val age
: Int){def printInfo
(){println
(s"student: name = ${name}, age = $age, school = ${Student11.school}")}
}
object Student12
{private var student
: Student12
= _
def getInstance
(): Student12
= {if (student
== null){student
= new Student12
("alice", 18)}student
}
}
第四節 特質
4.1 特質聲明
Scala 語言中,采用特質 trait(特征)來代替接口的概念,也就是說,多個類具有相同的特質(特征)時,就可以將這個特質(特征)獨立出來,采用關鍵字 trait 聲明。Scala 中的 trait 中即可以有抽象屬性和方法,也可以有具體的屬性和方法,一個類可以混入(mixin)多個特質。這種感覺類似于 Java 中的抽象類。Scala 引入 trait 特征,第一可以替代 Java 的接口,第二個也是對單繼承機制的一種補充。一個類具有某種特質(特征),就意味著這個類滿足了這個特質(特征)的所有要素,所以在使用時,也采用了extends關鍵字,如果有多個特質或存在父類,那么需要采用with關鍵字連接?;菊Z法:
class 類名
extends 特質
1 with 特質
2 with 特質
3 …
class 類名
extends 父類
with 特質
1 with 特質
2 with 特質
3…
說明 - 類和特質的關系:使用繼承的關系。
- 當一個類去繼承特質時,第一個連接詞是 extends,后面是 with。
- 如果一個類在同時繼承特質和父類時,應當把父類寫在 extends 后。
案例實操 - 特質可以同時擁有抽象方法和具體方法
- 一個類可以混入(mixin)多個特質
- 所有的 Java 接口都可以當做 Scala 特質使用
- 動態混入:可靈活的擴展類的功能
- 動態混入:創建對象時混入 trait,而無需使類混入該 trait
- 如果混入的 trait 中有未實現的方法,則需要實現
package chapter06object Test13_Trait
{def main
(args
: Array
[String]): Unit = {val student
: Student13
= new Student13student
.sayHello
()student
.study
()student
.dating
()student
.play
()}
}
class Person13
{val name
: String = "person"var age
: Int = 18def sayHello
(): Unit = {println
("hello from: " + name
)}def increase
(): Unit = {println
("person increase")}
}
trait Young
{var age
: Intval name
: String = "young"def play
(): Unit = {println
(s"young people $name is playing")}def dating
(): Unit
}class Student13
extends Person13
with Young
{override val name
: String = "student"def dating
(): Unit = println
(s"student $name is dating")def study
(): Unit = println
(s"student $name is studying")override def sayHello
(): Unit = {super.sayHello
()println
(s"hello from: student $name")}
}
4.2 特質疊加
由于一個類可以混入(mixin)多個 trait,且 trait 中可以有具體的屬性和方法,若混入的特質中具有相同的方法(方法名,參數列表,返回值均相同),必然會出現繼承沖突問題。沖突分為以下兩種: - 第一種,一個類(Sub)混入的兩個 trait(TraitA,TraitB)中具有相同的具體方法,且兩個 trait 之間沒有任何關系,解決這類沖突問題,直接在類(Sub)中重寫沖突方法。默認super使用wiht最后一個的方法的調用。
- 第二種,一個類(Sub)混入的兩個 trait(TraitA,TraitB)中具有相同的具體方法,且兩個 trait 繼承自相同的 trait(TraitC),及所謂的“鉆石問題”,解決這類沖突問題,Scala采用了特質疊加的策略。
所謂的特質疊加,就是將混入的多個 trait 中的沖突方法疊加起來,案例如下。
package chapter06object Test15_TraitOverlying
{def main
(args
: Array
[String]): Unit = {val student
= new Student15student
.increase
()val myFootBall
= new MyFootBallprintln
(myFootBall
.describe
())}
}
trait Ball
{def describe
(): String = "ball"
}
trait ColorBall
extends Ball
{var color
: String = "red"override def describe
(): String = color
+ "-" + super.describe
()
}
trait CategoryBall
extends Ball
{var category
: String = "foot"override def describe
(): String = category
+ "-" + super.describe
()
}
class MyFootBall
extends CategoryBall
with ColorBall
{override def describe
(): String = "my ball is a " + super[CategoryBall
].describe
()
}trait Knowledge15
{var amount
: Int = 0def increase
(): Unit = {println
("knowledge increased")}
}trait Talent15
{def singing
(): Unitdef dancing
(): Unitdef increase
(): Unit = {println
("talent increased")}
}class Student15
extends Person13
with Talent15
with Knowledge15
{override def dancing
(): Unit = println
("dancing")override def singing
(): Unit = println
("singing")override def increase
(): Unit = {super[Person13
].increase
()}
}
當一個類混入多個特質的時候,scala 會對所有的特質及其父特質按照一定的順序進行排序,而此案例中的 super.describe()調用的實際上是排好序后的下一個特質中的 describe() 方法。排序規則如下:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-12r6Yrn9-1665936840172)(.\printscreen\4.1.png)]案例中的 super,不是表示其父特質對象,而是表示上述疊加順序中的下一個特質,即,MyClass 中的 super 指代 Color,Color 中的 super 指代 Category,Category 中的 super指代 Ball。如果想要調用某個指定的混入特質中的方法,可以增加約束: super[],例如super[Category].describe()。
4.3 特質自身類型
自身類型可實現依賴注入的功能
package chapter06object Test16_TraitSelfType
{def main
(args
: Array
[String]): Unit = {val user
= new RegisterUser
("alice", "123456")user
.insert
()}
}
class User
(val name
: String, val password
: String)trait UserDao
{_
: User
=>def insert
(): Unit = {println
(s"insert into db: ${this.name}")}
}
class RegisterUser
(name
: String, password
: String) extends User
(name
, password
) with UserDao
特質和抽象類的區別 - 優先使用特質。一個類擴展多個特質是很方便的,但卻只能擴展一個抽象類。
- 如果你需要構造函數參數,使用抽象類。因為抽象類可以定義帶參數的構造函數,而特質不行(有無參構造)。
第五節 拓展
5.1 類型檢查和轉換
obj.isInstanceOf[T]:判斷 obj 是不是 T 類型。obj.asInstanceOf[T]:將 obj 強轉成 T 類型。classOf 獲取對象的類名。
class Persontest
{}object Person1
{def main
(args
:Array
[String]):Unit= {val person
= new Persontest
val bool
: Boolean = person
.isInstanceOf
[Persontest
]if ( bool
) {val p1
: Persontest
= person
.asInstanceOf
[Persontest
]println
(p1
)}val pClass
: Class
[Persontest
] = classOf
[Persontest
]println
(pClass
)}
}
5.2 枚舉類和應用類
枚舉類:需要繼承 Enumeration應用類:需要繼承 App
object Test
{def main
(args
: Array
[String]): Unit = {println
(Color
.RED
)}
}
object Color
extends Enumeration
{val RED
= Value
(1, "red")val YELLOW
= Value
(2, "yellow")val BLUE
= Value
(3, "blue")
}
object Test20
extends App
{println
("xxxxxxxxxxx");
}
5.3 Type 定義新類型
使用 type 關鍵字可以定義新的數據數據類型名稱,本質上就是類型的一個別名
object Test
{def main
(args
:Array
[String]): Unit = {type S
= Stringvar v
: S
= "abc"def test
(): S
= "xyz"}
}
總結
以上是生活随笔為你收集整理的第四课 尚硅谷Scala语言学习-面向对象的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。