目录
1. 隐式转换
1.1 两个类之间的隐式转换
-
在日常工作中,在引用其他 jar 的时候,可能会出现当前 jar 不能满足当前的业务需求,希望开发一些新的 API 来进行操作,如果是自己公司开发的 jar 还好,但是可能会遇到无法修改的 jar,这时候可以使用 Scala 中的隐式转换。
-
两个类之前的隐式转换,我们可以理解成 简单的类转换成了加强的类,加强的类不仅有简单的类的功能,还可以额外增加一些符合当前业务场景的 API。
-
隐式转换用的好,有利于开发,每个东西都有两面性,隐式转换用的不好,则会导致后期很难维护。
-
需求:
- 定义 Person 、SuperPerson 类,通过隐式转换使 Person 可以使用 SuperPerson里面的方法
-
做法:
- 第一步:先定义两个类:Person、SuperPerson
- 第二步:使用 implicit 关键词,强化 Person 类,使 Person 具有 SuperPerson 类的属性和方法
- 第三步:调用 Person 类
-
ImplicitUtils
package com.xk.bigdata.scala.imp
import com.xk.bigdata.scala.imp.ImplicitClass.{Person, SuperPerson}
object ImplicitUtils {
implicit def person2SuperPerson(person: Person): SuperPerson = new SuperPerson(person.name)
}
- ImplicitClass
package com.xk.bigdata.scala.imp
import com.xk.bigdata.scala.imp.ImplicitUtils._
/**
* 需求:
* 1. 定义 Person 、SuperPerson 类,通过隐式转换使 Person 可以使用 SuperPerson里面的方法
*/
object ImplicitClass {
def main(args: Array[String]): Unit = {
val person = new Person("spark")
person.fly()
}
class Person(val name: String)
class SuperPerson(val name: String) {
def fly(): Unit = {
println(s"$name is fly")
}
}
}
- 需求:定义一个隐式转换的 SuperPerson2 类,直接 new 一个 Person 就可以使用 SuperPerson2 中的方法
package com.xk.bigdata.scala.imp
/**
* 需求:
* 1. 定义 Person 、SuperPerson 类,通过隐式转换使 Person 可以使用 SuperPerson里面的方法
* 2. 定义一个隐式转换的 SuperPerson2 类,直接 new 一个 Person 就可以使用 SuperPerson2 中的方法
*/
object ImplicitClass {
def main(args: Array[String]): Unit = {
val person = new Person("spark")
person.fly()
}
class Person(val name: String)
class SuperPerson(val name: String) {
def fly(): Unit = {
println(s"$name is fly")
}
}
implicit class SuperPerson2(val person: Person) {
def fly(): Unit = {
println(s"${person.name} is fly")
}
}
}
1.2 隐式参数
-
需求:在含参方法中定义一个隐式参数,在调用的时候方法不需要传参数就可以直接使用该方法
-
做法:
- 第一步:定义一个含参数的方法
- 第二步:定义一个隐式常量
- 第三步:调用该方法
package com.xk.bigdata.scala.imp
/**
* 隐式参数
* 需求:在含参方法中定义一个隐式参数,在调用的时候方法不需要传参数就可以直接使用该方法
*/
object ImplicitParams {
def main(args: Array[String]): Unit = {
implicit val x = "spark"
speak
}
def speak(implicit name: String): Unit = {
println(s"$name is speak")
}
}
1.3 隐式转换作用域
- 隐式转换作用在:
- 在调用隐式转换的代码作用域内部,并且要在调用隐式转换的代码之前
- 相关类的伴生对象里面:在本例中相关类就是 Person、SuperPerson
package com.xk.bigdata.scala.imp
/**
* 隐式转换的作用域
*/
object ImplicitScope {
def main(args: Array[String]): Unit = {
val person = new Person("hadoop")
person.fly()
}
}
class Person(val name: String)
class SuperPerson(val person: Person) {
def fly(): Unit = {
println(s"${person.name} is fly")
}
}
object Person {
implicit def richPerson(person: Person): SuperPerson = {
println("隐式转换的作用域")
new SuperPerson(person)
}
}
object SuperPerson {
}
2. 读取文件数据
package com.xk.bigdata.scala.read
import scala.io.Source
/**
* 读取文件数据
*/
object ReadFile {
def main(args: Array[String]): Unit = {
// 读取文件数据
val words = Source.fromFile("data/wc.txt").getLines()
while (words.hasNext){
println(words.next())
}
}
}
3. 读取控制台数据
package com.xk.bigdata.scala.read
import java.io.{BufferedReader, InputStreamReader}
import java.util.Scanner
import scala.io.StdIn
/**
* 读取控制台数据
* 1. Java 读取控制台数据(字节流)
* 2. Java 封装的读取控制台数据
* 3. Scala 读取控制台数据
*/
object ReadConsole {
def main(args: Array[String]): Unit = {
// Java 读取控制台数据(字节流)
val reader = new BufferedReader(new InputStreamReader(System.in))
val data1 = reader.readLine()
println(s"==========>$data1")
// Java 封装的读取控制台数据
val scanner = new Scanner(System.in)
val data2 = scanner.next()
println(s"==========>$data2")
// Scala 读取控制台数据
val data3 = StdIn.readLine()
println(s"==========>$data3")
}
}
4. 泛型
4.1 泛型的介绍
- 泛型用于指定方法或类可以接受任意类型参数,参数在实际使用时才被确定,泛型可以有效地增强程序的适用性,使用泛型可以使得类或方法具有更强的通用性。泛型的典型应用场景是集合及集合中的方法参数,可以说同java一样,scala中泛型无处不在,具体可以查看scala的api。
- 泛型类:指定类可以接受任意类型参数。
- 泛型方法:指定方法可以接受任意类型参数。
4.1.1 定义泛型类
package com.xk.bigdata.scala.generic
/**
* 泛型类
*/
object GenericClass {
def main(args: Array[String]): Unit = {
val message = new Message(11)
message.loginfo()
}
/**
* 定义一个任意类型的 msg ,通过实例化的时候传入
*/
class Message[T](val msg: T) {
def loginfo(): Unit = {
println("=========>" + msg)
}
}
}
4.1.2 定义泛型方法
package com.xk.bigdata.scala.generic
/**
* 定义泛型方法
*/
object GenericFunction {
def main(args: Array[String]): Unit = {
GenericFunctionTest().logingo("111")
GenericFunctionTest().logingo(2222)
GenericFunctionTest().logingo(3333L)
}
class GenericFunctionTest() {
def logingo[T](msg: T): Unit = {
println("=========>" + msg)
}
}
object GenericFunctionTest {
def apply(): GenericFunctionTest = new GenericFunctionTest()
}
}
4.2 上界和下界
4.2.1 介绍
- 在指定泛型类型时,有时需要界定泛型类型的范围,而不是接收任意类型。比如,要求某个泛型类型,必须是某个类的子类,这样在程序中就可以放心的调用父类的方法,程序才能正常的使用与运行。此时,就可以使用上下边界Bounds的特性。
- Scala的上下边界特性允许泛型类型是某个类的子类,或者是某个类的父类。
- S <: T 这是类型上界的定义,也就是S必须是类型T的子类(或本身,自己也可以认为是自己的子类)。
- U >: T 这是类型下界的定义,也就是U必须是类型T的父类(或本身,自己也可以认为是自己的父类)。
4.2.2 上界示例
package com.xk.bigdata.scala.generic
/**
* 上界示例
*/
object GenericUpBound {
def logingo[T <: Student](msg: T): Unit = {
println("=========>" + msg)
}
def main(args: Array[String]): Unit = {
logingo[Student](new Student)
logingo[Children](new Children)
}
class Person
class Student extends Person
class Children extends Student
}
4.2.3 下界示例
package com.xk.bigdata.scala.generic
/**
* 下界示例
*/
object GenericDownBound {
def logingo[T >: Student](msg: T): Unit = {
println("=========>" + msg)
}
def main(args: Array[String]): Unit = {
logingo[Person](new Person)
logingo[Student](new Student)
}
class Person
class Student extends Person
class Children extends Student
}
4.3 协变和逆变
-
对于一个带类型参数的类型,比如 List[T]:
- 如果对A及其子类型B,满足 List[B]也符合 List[A]的子类型,那么就称为covariance(协变)。
- 如果 List[A]是 List[B]的子类型,即与原来的父子关系正相反,则称为contravariance(逆变)。
-
在声明Scala的泛型类型时,“+”表示协变,而“-”表示逆变。
- C[+T]:如果A是B的子类,那么C[A]是C[B]的子类。
- C[-T]:如果A是B的子类,那么C[B]是C[A]的子类。
- C[T]:无论A和B是什么关系,C[A]和C[B]没有从属关系。
4.3.1 协变示例
package com.xk.bigdata.scala.generic
/**
* 协变示例
*/
object GenericCovariant {
def main(args: Array[String]): Unit = {
new Message[Person](new Student).loginfo()
new Message[Person](new Children).loginfo()
}
class Person
class Student extends Person
class Children extends Student
class Message[+T](val msg: T) {
def loginfo(): Unit = {
println("=========>" + msg)
}
}
}
4.3.2 逆变示例
package com.xk.bigdata.scala.generic
/**
* 逆变示例
*/
object GenericInversion {
def main(args: Array[String]): Unit = {
val student: Message1[Student1] = new Message1[Student1]()
val child: Message1[Children1] = student
println(child)
}
class Person1
class Student1 extends Person1
class Children1 extends Student1
class Message1[-T]() {
}
}