目錄
-
類和對象
scala是支持面向對象的,也有類和對象的概念。我們依然可以基於scala語言來開發面向對象的應用程序。
-
創建類和對象
使用class來定義一個類 new來創建對象
例:
object demo01 {
//創建類
class user{}
def main(args: Array[String]): Unit = {
//創建對象
var u = new user()
println("hello word")
}
}
-
定義和訪問成員變量
一個類會有自己的屬性,例如:人這樣一個類,有自己的姓名和年齡。在類中定義、和訪問成員變量
例:
object demo01 {
//創建類
class user{
// 定義成員變量
val id = "123"
var name = ""
var age = 0
}
def main(args: Array[String]): Unit = {
//創建對象
var u = new user()
u.name = "zhangsan"
u.age = 20
//獲取變量值
println(u.id)
println(u.name)
println(u.age)
}
}
-
使用下劃線初始化成員變量
1.在定義var類型的成員變量時,可以使用_來初始化成員變量
2.使用下劃線初始化,成員變量必須爲var(變量),並且要指定數據類型
例:
object demo01 {
//創建類
class user{
// 定義成員變量 使用下劃線進行初始化
var id:String = _
var name:String = _
var age:Int = _
}
def main(args: Array[String]): Unit = {
//創建對象
var u = new user()
u.name = "zhangsan"
u.age = 20
//獲取變量值
println(u.id)
println(u.name)
println(u.age)
}
}
-
定義成員方法
類可以有自己的行爲,scala中也可以通過定義成員方法來定義類的行爲。使用def來定義成員方法
例:
object demo01 {
//創建類
class user{
// 定義成員變量 使用下劃線進行初始化
var id:String = _
var name:String = _
var age:Int = _
//定義成員方法
def prints (msg:String): Unit = {
println(msg + " hello")
}
}
def main(args: Array[String]): Unit = {
//創建對象
var u = new user()
u.name = "zhangsan"
u.age = 20
//輸出成員方法
u.prints("zhangsan")
}
}
-
訪問修飾符
1.和Java一樣,scala也可以通過訪問修飾符,來控制成員變量和成員方法是否可以被訪問。
2.可以在成員前面添加private/protected(私有的/受保護的)關鍵字來控制成員的可見性。
3.scala中,沒有public關鍵字,任何沒有被標爲private或protected的成員都是公共的
例:
object demo02 {
class Persion {
//定義成變量
private var name: String = ""
private var age: Int = 0
//定義成員方法
def getName() = {
this.name
}
def setName(name: String): Unit = {
this.name = name
}
def getAge() = {
this.age
}
def setAge(age: Int): Unit = {
this.age = age
}
private def getNameAndAge() = {
this.getName() + " " + this.getAge()
}
}
def main(args: Array[String]): Unit = {
//實例化對象
var persion = new Persion();
//調用方法
persion.setName("zhangsan")
persion.setAge(200)
println(persion.getName())
println(persion.getAge())
}
}
-
類的構造器
1.當創建類對象的時候,會自動調用類的構造器。之前使用的都是默認構造器
2.Scala的構造器分爲主構造器與輔助構造器
3.主構造器:直接在class括號內添加屬性
4.輔助構造器:除了主構造器之外的都是輔助構造器
主構造器
1.主構造器的參數列表是直接定義在類名後面,添加了val/var表示直接通過主構造器定義成員變量
2.構造器參數列表可以指定默認值
3.創建實例,調用構造器可以指定字段進行初始化
4.整個class中除了字段定義和方法定義的代碼都是構造代碼
格式:
class 類名(var/val 參數名:類型 = 默認值, var/val 參數名:類型 = 默認值){
// 構造代碼塊
}
例:
object demo03 {
//創建構造器
class Person(var name:String = "",var age:Int = 0){
}
def main(args: Array[String]): Unit = {
var p = new Person("zhangsan",17)
println(p.name)
println(p.age)
}
}
輔助構造器
1.除了主構造器之外的構造器稱爲輔助構造器。
2.定義輔助構造器與定義方法一樣,也使用def關鍵字來定義
3.這個方法的名字爲this
4.輔助構造器的第一行代碼,必須要調用主構造器或者其他輔助構造器
格式:
def this(參數名:類型, 參數名:類型) {
// 第一行需要調用主構造器或者其他構造器
// 構造器代碼
}
例:
object demo03 {
//創建構造器
class Person(var name:String = "",var address:String = ""){
//創建輔助構造器
def this(arr:Array[String]){
this(arr(0),arr(1))
}
}
def main(args: Array[String]): Unit = {
//實例化對象
var p = new Person(Array("zhangsan","北京"))
println(p.name)
println(p.address)
}
}
-
單例對象
1.scala中沒有Java中的靜態成員,若想要定義類似於Java的static變量、static方法,就要使用到scala中的單例對象——object.
2.單例對象表示全局僅有一個對象(類似於Java static概念)
3.定義單例對象和定義類很像,就是把class換成object
4.在object中定義的成員變量類似於Java的靜態變量
5.可以使用object直接引用成員變量
例:
object demo04 {
//創建單例對象
object Person {
var name: String = "zhangsan"
}
def main(args: Array[String]): Unit = {
println(Person.name)
}
}
在單例對象中定義成員方法
1.在object中定義的成員方法類似於Java的靜態方法
例:
object demo04 {
//創建單例對象
object Person {
var name: String = "zhangsan"
//定義成員方法
def show() = {
println("show")
}
}
def main(args: Array[String]): Unit = {
println(Person.name)
//調用方法
Person.show()
}
}
-
main方法
scala和Java一樣,如果要運行一個程序,必須有一個main方法。在Java中main方法是靜態的,而在scala中沒有靜態方法。在scala中,這個main方法必須放在一個單例對象中。
格式:
def main(args:Array[String]):Unit = {
// 方法體
}
實現App Trait來定義入口
創建一個object,繼承自App Trait(特質),然後將需要編寫在main方法中的代碼,寫在object的構造方法體內。
格式:
object 單例對象名 extends App {
// 方法體
}
例:
object demo05 extends App {
println("holle")
}
-
伴生對象
1.一個class和object具有同樣的名字。這個object稱爲伴生對象,這個class稱爲伴生類
2.伴生對象必須要和伴生類一樣的名字
3.伴生對象和伴生類在同一個scala源文件中
4.伴生對象和伴生類可以互相訪問private屬性
例:
object demo06 {
class Person{
private val id:String = "123"
//可以互相訪問私有數據
println(Person.name)
}
object Person{
private var name:String = "zhangsan"
//可以互相訪問私有數據
println(new Person().id)
}
def main(args: Array[String]): Unit = {
}
}
private[this]訪問權限
如果某個成員的權限設置爲private[this],表示只能在當前類中訪問。伴生對象也不可以訪問
例:
object demo06 {
class Person{
private[this] val id:String = "123"
//可以互相訪問私有數據
println(Person.name)
}
object Person{
private var name:String = "zhangsan"
//被private[this]修飾 不能訪問 報錯
//println(new Person().id)
}
def main(args: Array[String]): Unit = {
}
}
-
繼承
1.scala語言是支持面向對象編程的, 可以使用scala來實現繼承,通過繼承來減少重複代碼
2.使用extends關鍵字來實現繼承
3.可以在子類中定義父類中沒有的字段和方法,或者重寫父類的方法
4.類和單例對象都可以從某個父類繼承
格式:
class/object 子類 extends 父類 {
..
}
例:
//父類
class Person {
var name:String = "zhangsan"
def getName(): Unit ={
this.name
}
}
object demo07 {
//子類
class Stu extends Person{
}
def main(args: Array[String]): Unit = {
var stu = new Stu();
//調用父類的方法
println(stu.name)
}
}
-
override和super
1.類似於Java語言, 在子類中使用override需要來重寫父類的成員,可以使用super來引用父類
2.子類要覆蓋父類中的一個方法,必須要使用override關鍵字
3.使用override來重寫一個val字段
4.使用super關鍵字來訪問父類的成員方法
例:
//父類
class Person {
val name = "super"
def getName = name
}
object demo07 {
class Student extends Person {
// 重寫val字段
override val name: String = "child"
// 重寫getName方法
override def getName: String = "hello, " + super.getName
}
def main(args: Array[String]): Unit = {
var stu = new Student();
println(stu.name)
println(stu.getName)
}
}
-
類型判斷
有時候,我們設計的程序,要根據變量的類型來執行對應的邏輯
isInstanceOf/asInstanceOf
1.isInstanceOf判斷對象是否爲指定類以及其子類的對象
2.asInstanceOf將對象轉換爲指定類型
格式:
// 判斷對象是否爲指定類型
val trueOrFalse:Boolean = 對象.isInstanceOf[類型]
// 將對象轉換爲指定類型
val 變量 = 對象.asInstanceOf[類型]
例:
//父類
class Person {
val name = "super"
def getName = name
}
object demo07 {
//子類
class Student extends Person {
// 重寫val字段
override val name: String = "child"
// 重寫getName方法
override def getName: String = "hello, " + super.getName
}
def main(args: Array[String]): Unit = {
var stu1 = new Student();
var stu2:Person = new Student();
//判斷對象是否爲指定類型 true
println(stu1.isInstanceOf[Student])
//將對象轉換爲指定類型 將Person類型轉爲Student類型
if (stu2.isInstanceOf[Student]){
val s2 = stu2.asInstanceOf[Student]
println(s2)
}
}
}
getClass/classOf
1.isInstanceOf 只能判斷對象是否爲指定類以及其子類的對象,而不能精確的判斷出,對象就是指定類的對象。如果要求精確地判斷出對象就是指定類的對象,那麼就只能使用 getClass 和 classOf 。
2.p.getClass可以精確獲取對象的類型(不是父類)
3.classOf[x] 可以指定精確類型
4.使用==操作符可以直接比較類型
例:
class Person {
val name = "super"
def getName = name
}
object demo07 {
class Student extends Person {
// 重寫val字段
override val name: String = "child"
// 重寫getName方法
override def getName: String = "hello, " + super.getName
}
def main(args: Array[String]): Unit = {
var stu = new Student();
//true
println(stu.getClass() == classOf[Student])
//false//抽象類
abstract class Shape {
//抽象字段
var r:Double
//抽象方法
def area(): Double
}
//子類1 正方形
class Square(edge: Double) extends Shape {
//實現字段
override var r: Double = edge;
//實現方法
override def area(): Double = {
r * r
}
}
//子類2 圓形
class Roundness(radius: Double) extends Shape {
//實現字段
override var r: Double = radius
//實現方法
override def area(): Double = {
r * r * 3.14
}
}
def main(args: Array[String]): Unit = {
//正方形
var square = new Square(10);
println(square.area())
//圓形
var roundness = new Roundness(10);
println(roundness.area())
}
println(stu.getClass() == classOf[Person])
}
}
-
抽象類
1.如果類的某個成員在當前類中的定義是不包含完整的,它就是一個抽象類
2.不完整定義有兩種情況:
a.方法沒有方法體(抽象方法)
b.變量沒有初始化(抽象字段)
3.定義抽象類和Java一樣,在類前面加上abstract關鍵字
4.在抽象類中不抽象的字段或方法不用重寫
格式:
// 定義抽象類
abstract class 抽象類名 {
// 定義抽象字段
val 抽象字段名:類型
// 定義抽象方法
def 方法名(參數:參數類型,參數:參數類型...):返回類型
}
例:
//抽象類
abstract class Person {
//抽象字段
var name: String
//抽象方法
def Say(msg:String):String
}
//抽象類
abstract class Shape {
//抽象字段
var r:Double
//抽象方法
def area(): Double
}
//子類1 正方形
class Square(edge: Double) extends Shape {
//實現字段
override var r: Double = edge;
//實現方法
override def area(): Double = {
r * r
}
}
//子類2 圓形
class Roundness(radius: Double) extends Shape {
//實現字段
override var r: Double = radius
//實現方法
override def area(): Double = {
r * r * 3.14
}
}
//main方法
def main(args: Array[String]): Unit = {
//正方形
var square = new Square(10);
println(square.area())
//圓形
var roundness = new Roundness(10);
println(roundness.area())
}
-
匿名內部類
匿名內部類是沒有名稱的子類,直接用來創建實例對象。Spark的源代碼中有大量使用到匿名內部類。scala中的匿名內部類使用與Java一致。
格式:
val/var 變量名 = new 類/抽象類 {
// 重寫方法
}
例:
//抽象類
abstract class Shape {
//抽象字段
var r: Double
//抽象方法
def area(): Double
}
//main方法
def main(args: Array[String]): Unit = {
//匿名內部類
var dd = new Shape {
//重寫字段
override var r: Double = 10
//重寫方法
override def area(): Double = {
r
}
}
//打印
println(dd.area)
}
}
-
特質(trait)
1.scala中沒有Java中的接口(interface),替代的概念是特質
2.特質是scala中代碼複用的基礎單元
3.它可以將方法和字段定義封裝起來,然後添加到類中
4.與類繼承不一樣的是,類繼承要求每個類都只能繼承一個超類,而一個類可以添加任意數量的特質。
5.特質的定義和抽象類的定義很像,但它是使用trait關鍵字
6.使用extends來繼承trait(scala不論是類還是特質,都是使用extends關鍵字)
7.如果要繼承多個trait,則使用with關鍵字
8.在trait中可以定義具體字段和抽象字段
9.scala中可以將trait混入到對象中,就是將trait中定義的方法、字段添加到一個對象中
10.trait也可以繼承class的。特質會將class中的成員都繼承下來
格式:
//定義特質
trait 名稱 {
// 抽象字段
// 抽象方法
}
//繼承特質
class 類 extends 特質1 with 特質2 {
// 字段實現
// 方法實現
}
繼承單個特質
例:
//特質
trait Person {
//完整字段 不需要被繼承
var id: String = "123456"
//抽象字段
var name: String
//完整方法 不需要被繼承
def SayHello(msg: String) = {
println(msg)
}
//抽象方法
def Say(): String
}
//子類
class Stuent extends Person {
//實現父類字段
override var name: String = "張三"
//實現父類方法
override def Say(): String = {
name
}
}
繼承多個特質
例:
//特質1
trait Person1 {
//完整字段 不需要被繼承
var id: String = "123456"
//抽象字段
var name: String
//完整方法 不需要被繼承
def SayHello(msg: String) = {
println(msg)
}
//抽象方法
def Say(): String
}
//特質2
trait Person2 {
//抽象方法
def doing(): String
}
//子類 繼承Person1 Person2兩個特質
class Student extends Person1 with Person2 {
//實現父類Person1字段
override var name: String = "張三"
//實現父類Person1方法
override def Say(): String = {
name
}
//實現父類Person2方法
override def doing(): String = {
name
}
}
object繼承trait
例:
//特質
trait Sum2 {
//抽象方法
def sum(num1: Int, num2: Int): Unit
}
//子object
object Sums extends Sum2 {
//重寫方法
override def sum(num1: Int, num2: Int): Unit = {
println(num1 + num2)
}
}
//main方法
def main(args: Array[String]): Unit = {
//調用方法
Sums.sum(10,10)
}
使用trait實現模板模式
在一個特質中,具體方法依賴於抽象方法,而抽象方法可以放到繼承trait的子類中實現,這種設計方式也稱爲模板模式
例:
//特質
trait Logger {
//抽象方法
def log(msg: String): Unit
//創建具體方法並調用抽象方法
def info(msg: String) = log("Info" + msg)
def warn(msg: String) = log("Warn" + msg)
def error(msg: String) = log("Error" + msg)
}
//繼承特質
class ConsoleLogger extends Logger {
//現抽象方法
override def log(msg: String): Unit = {
println(msg)
}
}
def main(args: Array[String]): Unit = {
var log = new ConsoleLogger();
//調用方法
log.info("信息日誌")
log.warn("警告日誌")
log.error("錯誤日誌")
}
對象混入trait
scala中可以將trait混入到對象中,就是將trait中定義的方法、字段添加到一個對象中
格式:
val/var 對象名 = new 類 with
例:
//特質
trait Do {
def say(msg: String): String = {
println(msg + "1")
msg
}
def say1():String
}
//類
class Student
//main方法
def main(args: Array[String]): Unit = {
//創建對象 混入trait
var stu = new Student() with Do {
//實現抽象方法
override def say1(): String = {
"lisi"
}
}
//調用方法
stu.say("zhangsan")
println( stu.say1())
}
trait實現調用鏈模式
類繼承了多個trait後,可以依次調用多個trait中的同一個方法,只要讓多個trait中的同一個方法在最後都依次執行super關鍵字即可。類中調用多個tait中都有這個方法時,首先會從最右邊的trait方法開始執行,然後依次往左執行,形成一個調用鏈條。
例:
//特質1
trait HandlerTrait {
def handler(msg: String) = {
println("第四步:打印數據" + msg)
}
}
//特質2 繼承特質1
trait DataValidHandlerTrait extends HandlerTrait {
//重寫方法
override def handler(msg: String): Unit = {
println("第三步:驗證數據" + msg)
//調用父類方法
super.handler(msg)
}
}
//特質3 繼承特質1
trait SignatureValidHandlerTrait extends HandlerTrait {
//重寫方法
override def handler(msg: String): Unit = {
println("第二步:檢查簽名" + msg)
//調用父類方法
super.handler(msg)
}
}
//子類 繼承特質1 特質2
class PaymentService extends DataValidHandlerTrait with SignatureValidHandlerTrait {
def pay(msg: String) = {
println("第一步:準備支付" + msg)
super.handler(msg)
}
}
//main方法
def main(args: Array[String]): Unit = {
var paymentService = new PaymentService();
paymentService.pay("牛奶")
}
trait繼承class
trait也可以繼承class的。特質會將class中的成員都繼承下來
//父類
class MyUtils {
def printMsg(msg: String) = {
println(msg)
}
}
//子特質
trait Logger extends MyUtils {
def log(msg: String) = printMsg(msg)
}
//特質的子類
class Person extends Logger {
def Say(msg: String) = log(msg)
}
//main方法
def main(args: Array[String]): Unit = {
var person = new Person();
//調用方法 Person子類可以調用父類所有方法
person.Say("zhangsan");
person.log("lisi")
person.printMsg("wangwu")
}
-
樣例類
樣例類是一種特殊類,它可以用來快速定義一個用於保存數據的類(類似於Java POJO類),在後續要學習併發編程和spark、flink這些框架也都會經常使用它。
格式:
case class 樣例類名([var/val] 成員變量名1:類型1, 成員變量名2:類型2, 成員變量名3:類型3)
例:
//樣例類 默認的字段爲常量
case class Student(var name: String, age: Int) {
}
//main方法
def main(args: Array[String]): Unit = {
//創建樣例類對象 不需要new
var student = Student("張三", 17)
//重賦值數據 如果數據爲變量(var)則可以重新賦值
student.name = "李四"
//打印數據
println(student.name)
println(student.age)
}
常用方法
apply:apply方法可以讓我們快速地使用類名來創建對象
toString:toString返回樣例類名稱(成員變量1, 成員變量2, 成員變量3....)
equals:樣例類自動實現了equals方法,可以直接使用==比較兩個樣例類是否相等,即所有的成員變量是否相等
hashCode:樣例類自動實現了hashCode方法,如果所有成員變量的值相同,則hash值相同,只要有一個不一樣,則hash值不一樣。
copy:樣例類實現了copy方法,可以快速創建一個相同的實例對象,可以使用帶名參數指定給成員進行重新賦值
-
樣例對象
1.定義枚舉
2.作爲沒有任何參數的消息傳遞
格式:
case object 樣例對象名
例:
object Test02 {
//特質
trait sex
//定義特質的枚舉
case object Boy extends sex
case object Girl extends sex
//創建對象 對象的一個屬性設置爲枚舉
case class Person(name: String, sex: sex)
def main(args: Array[String]): Unit = {
//創建對象
var person = Person("張三", Boy)
}
}