Scala day04
伴生类和伴生对象的用法:静态工厂
package com.gc.scala1015day04
/**
* Author guochao
* Date 2021/5/8
*/
object Factory1 {
def main(args: Array[String]): Unit = {
println(Human.getHuman("黑色"))
println(Human.getHuman("黑色"))
}
}
object Human{
val map = mutable.Map[String, Human](
"黑色" -> new Human("黑色")
)
def getHuman(color: String) = map.getOrElseUpdate(color, new Human(color))
}
class Human private (color: String){
println(s"$color.....")
override def toString: String = s"人种: $color"
}
/*
1.伴生类和伴生对象可以互相访问对方的私有成员
2.编译成字节码之后, 伴生对象中的成员就是java中的静态成员, 伴生类中的成员, 就是java中的普通成员
*/
特质(trait)
特质声明
trait 特质名 {
trait体
}
特质基本语法
一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素,所以在使用时,也采用了extends关键字,如果有多个特质或存在父类,那么需要采用with关键字连接。
- 基本语法:
没有父类:class 类名 extends 特质1 with 特质2 with 特质3 …
有父类:class 类名 extends 父类 with 特质1 with 特质2 with 特质3… - 说明
(1)类和特质的关系:使用继承的关系。
(2)当一个类去继承特质时,第一个连接词是extends,后面是with。
(3)如果一个类在继承特质和父类时,应当把父类写在extends后。 - (1)类和特质的关系:使用继承的关系。
(2)当一个类去继承特质时,第一个连接词是extends,后面是with。
(3)如果一个类在继承特质和父类时,应当把父类写在extends后。 - 案例实操
(1)特质可以同时拥有抽象方法和具体方法
(2)一个类可以混入(mixin)多个特质
(3)所有的Java接口都可以当做Scala特质使用
(4)动态混入:可灵活的扩展类的功能
(4.1)动态混入:创建对象时混入trait,而无需使类混入该trait
(4.2)如果混入的trait中有未实现的方法,则需要实现
trait PersonTrait {
//(1)特质可以同时拥有抽象方法和具体方法
// 声明属性
var name: String = _
// 抽象属性
var age: Int
// 声明方法
def eat(): Unit = {
println("eat")
}
// 抽象方法
def say(): Unit
}
trait SexTrait {
var sex: String
}
//(2)一个类可以实现/继承多个特质
//(3)所有的Java接口都可以当做Scala特质使用
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)动态混入:可灵活的扩展类的功能
val t2 = new Teacher with SexTrait {
override var sex: String = "男"
}
//调用混入trait的属性
println(t2.sex)
}
}
package com.gc.scala1015day04
/**
* Author guochao
* Date 2021/5/8
*/
object Trait1 {
def main(args: Array[String]): Unit = {
val usb: Logger = new HuaweiUsb
usb.insert
usb.work
usb.print()
}
}
class Logger{
println("logger 类的构造器")
def print() = {
println("开始打印日志...")
}
}
trait Usb{
println("USB的构造器 第一个混入的")
// 抽象字段
val name: String
def insert: Unit
def work: Unit
def pop: Unit
def init()= {
println(s" $name 开始初始化...")
}
}
trait MyException{
println("MyException 的构造器 第二个混入的")
def thowExec: Exception// 抽象字段
}
class HuaweiUsb extends Logger with MyException with Usb {
println("HuaweiUSB类的构造器 子类")
override val name: String = "huawei"
override def insert: Unit = {
println("华为 usb开始插入...")
init()
}
override def work: Unit =
println("华为 usb开始工作...")
override def pop: Unit =
println("华为 usb退出工作...")
override def thowExec: Exception = new RuntimeException("华为的usb在抛异常")
}
package com.gc.scala1015day04
/**
* Author guochao
* Date 2021/5/8
*/
object Trait2 {
def main(args: Array[String]): Unit = {
/*val abc = new ABC
abc.foo()*/
val my:A = new My with A with B with C
my.foo()
}
}
class ABC extends A with B with C{
override def foo() = {
super.foo() //
println("ABC ...")
}
}
trait A{
def foo() = {
println("A ...")
}
}
trait B extends A{
override def foo() = {
println("B ...")
}
}
trait C extends A{
override def foo() = {
super[A].foo()
println("C ...")
}
}
/*
1.如果一个类混入的特质中有相同的实现好的方法, 则会产生成员冲突
2.可以使用菱形的继承结构解决冲突问题, 冲突解决之后, 方法谁最后混入的那个
3.super[A] super具体指代
4.动态混入(叠加)
*/
package com.gc.scala1015day04
/**
* Author guochao
* Date 2021/5/8
*/
object Trait3 {
def main(args: Array[String]): Unit = {
val sub = new Sub
sub.f()
sub.foo()
}
}
class Father {
def f() = println("father... f")
}
class My1 extends Father
//trait F extends Exception
trait F {
// 自身类型 self 是一个变量名, 可以通过这个名字取调用father中方法
self: Father => // trait F extends Father
def foo() = {
// self.f()
this.f()
}
}
//如果要成功, 则My要么是Exception, 要么是Exception的子类
class Sub extends My1 with F
扩展
类型转换
-
说明
(1)obj.isInstanceOf[T]:判断obj是不是T类型。
(2)obj.asInstanceOf[T]:将obj强转成T类型。
(3)classOf获取对象的类名。 -
案例实操
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)
}
}
枚举类和应用类
-
说明
枚举类:需要继承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");
}
隐式
-
隐式转换函数
implicit def double2Int(d: Double) = d.toInt
不看函数名, 只看参数和返回值类型将来可以给已有的类增加功能!
-
隐式类
implicit class RichFile(file: File) {
def readContent: String = {
Source.fromFile(file, “utf-8”).mkString
}
}- 不能顶级
- 柱构造必须有参数
2.10新增的, 是对隐式转换函数的一个封装. 简化隐式转换函数的使用.
spark里面, 其实还是隐式转换函数用的比较多可以把隐式当做一个普通的类使用!!!
-
隐式参数和隐式值
隐式参数是指的给函数的参数添加隐式关键字implicit val aa = 100
def foo(implicit a: Int)
当调用函数的时候, 如果不传参数, 并且省略括号, 就会找隐式值!(只看类型,不看名字)
如果定义了隐式参数, 则整个参数列表中所有的参数都是隐式参数
package com.gc.scala1015day04
/**
* Author guochao
* Date 2021/5/8
*/
import java.time.LocalDate
object Implicit3 {
def main(args: Array[String]): Unit = {
implicit def int2RichDate(day: Int) = new RichDate(day)
// 2 days ago 计算2天前是哪一天
val ago = "ago"
val later = "later"
// val r = 2 days ago
val r = 100.days(later)
println(r) // 2020-03-04
// 4 days later 计算4天后是哪一天
}
}
class RichDate(day: Int) {
def days(when: String) = {
if("ago"==when)
LocalDate.now().plusDays(-day).toString
LocalDate.now().minusDays(day)
else{
LocalDate.now().plusDays(day).toString
}
}
}
定长数组
package com.gc.scala1015day04
/**
* Author guochao
* Date 2021/5/8
*/
object Array1 {
def main(args: Array[String]): Unit = {
val arr: Array[Int] = Array[Int](1, 2, 3, 4)
println(arr(0))
arr(0) = 100
println(arr.mkString(", "))
// 遍历数组 for while
val arr1: Array[Int] = arr :+ 100 // arr.:+(100)
val arr1 = 100 +: arr // ==== arr.+:(100)
val arr1 = arr.+:(100)
println(arr1.mkString(", "))
val arr1 = Array(30, 50, 70, 60, 10, 20)
val arr2 = Array(3, 5, 7, 6, 1, 2)
val arr3: Array[Int] = arr1 ++ arr2 // === arr1.++(arr2)
myPrint(arr3)
val arr1 = Array(30, 50, 70, 60, 10, 20)
}
def myPrint(any: Traversable[_]): Unit = {
println(any.mkString(", "))
}
}
/*
<> : 给xml, scala语言级别的支持xml
[]:给了泛型
(index): 访问指定索引的元素
scala没有自己定义数组, 底层就是java的数组
定长数组
创建数组;
直接通过给数组初始化元素的方式创建数组
:+ 一般用于给不可变的集合添加单个元素在末尾 (+)
+: 一般用于给不可变的集合加单个元素到头部 (+)
++ 合并连个集合
运算符的结合性:
1 + 2 左结合
+2 右集合
a = 3 右集合
只要运算符是以: 结尾就是右结合运算符
*/