Scala泛型和上下界

发布时间:2022-06-21 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Scala泛型和上下界脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

[toc]

## Scala泛型和上下界

### 1. Scala泛型

> 1. 如果我们要求函数的参数可以接受任意类型。可以使用`泛型`,这个类型可以代表任意的数据类型。 > 2. 例如 List,在创建 List 时,可以传入整型、字符串、浮点数等等任意类型。那是因为 List 在 类定义时引用了泛型。`比如在Java中:public interface List<E> extends Collection<E>`

#### Scala泛型案例一

> 1. 编写一个Message类> 2. 可以构建Int类型的Message,也可以构建String类型的Message。> 3. 要求使用泛型来完成设计(说明:不能使用Any)

```scala/** * @Date 2021/4/5 18:25 * @Version 10.21 * @Author DuanChaojie */object GenericDemo01 { def main(args: Array[String]): Unit = { val message1 = new Message[Int](10) val message2 = new Message[String]("str") println(message1.toString()) println(message2.toString()) }}

class Message[T](inMes: T) { var mes = inMes override def toString = { "重写的toString方法...." + mes }}```

#### Scala泛型案例二

> 1. 请设计一个`EnglishClass` (英语班级类),在创建EnglishClass的一个实例时,需要指定`[ 班级开班季节(spring,autumn,summer,winter)、班级名称、班级类型]`> 2. 开班季节只能是指定的,班级名称为String,班级类型是(字符串类型 "高级班", "中级班", "初级班") 或者是 Int 类型(1, 2, 3 等)> 3. 请使用泛型来完成本案例> 4. [Scala枚举详解...](https://pedrorijo.com/blog/scala-enums/)

~~~~scalapackage com.atguigu.chapter16

import com.atguigu.chapter16.SeasonEnum.SeasonEnum

/** * @Date 2021/4/5 18:32 * @Version 10.21 * @Author DuanChaojie */object GenericDemo02 { def main(args: Array[String]): Unit = { val scalaClass = new EnglishClass[String, Int, String]("春天", 4, "Scala班") println(scalaClass.toString())

val javaClass = new EnglishClass[SeasonEnum, String, String](SeasonEnum.spring, "Java", "5班") println(javaClass.toString) }}

class EnglishClass[A, B, C](inSeason: A, inClassName: B, inClassType: C) { var season: A = inSeason var className: B = inClassName var classType: C = inClassType

override def toString: String = { s"season = $seasonnclassType = $classTypenclassName = $className 班" }}

/** * 枚举类SeasonEnum */object SeasonEnum extends Enumeration { type SeasonEnum = Value val spring, summer, autumn, winter = Value}~~~~

#### Scala泛型案例三

> 1. 定义一个函数,可以获取各种类型的 List 的中间index的值> 2. 使用泛型完成

~~~~scala/** * @Date 2021/4/5 19:21 * @Version 10.21 * @Author DuanChaojie */object GenericDemo03 { def main(args: Array[String]): Unit = { val list1 = List[String]("dd", "ai", "mm") val list2 = List[Int](1, 2, 3) println(midValue(list1)) println(midValue(list2)) }

def midValue[T](list: List[T]): T = { list(list.length / 2) }}~~~~

### 2. Scala类型约束

#### 测试上下界用到的公共类

~~~~scalapackage com.atguigu.chapter16

/** * @Date 2021/4/5 20:03 * @Version 10.21 * @Author DuanChaojie */object BoundsCommonClass { // Scala上界和下界测试用到的类}

/** * Earth 类 */class Earth { def sound() { println("hello Earth !") }}

/** * Animal类 */class Animal extends Earth { //重写了Earth的方法sound() override def sound() = { println("animal sound") }}

/** * Bird类 */class Bird extends Animal { // 将Animal的方法重写 override def sound() = { println("bird sounds") }}

class Moon{ def sound() = { println("Moon Moon ~") }}

class MyCat(val name: String, val age: Int) { override def toString: String = { s"name = $name nage = $age" }}~~~~

#### 上界(Upper Bounds)

> ==Java中上界:==在 Java 泛型里表示某个类型是 A 类型的子类型,使用 extends 关键字,这种形式叫 `upper bounds(上限或上界)`,语法如下:

~~~~java<T extends A>//或用通配符的形式:<? extends A>~~~~

> ==Scala中上界:==在 Scala 里表示某个类型是 A 类型的子类型,也称上界或上限,使用 `<: 关键字`,语法如下:

~~~scala[T <: A]//或用通配符:[_ <: A]~~~

> Scala上界应用案例:>> 1. 编写一个通用的类,可以进行Int之间、Float之间、等实现了Comparable接口的值直接的比较。> 2. 分别使用传统方法和上界的方式来完成,体会上界使用的好处。> 1. 传统方法:`class MyCompare1(inX: Int, inY: Int){...}`> 2. 使用上界:`class MyCompare2[T <: Comparable[T]](inX: T, inY: T) {...}`

~~~~scalapackage com.atguigu.chapter16

/** * @Date 2021/4/5 19:27 * @Version 10.21 * @Author DuanChaojie */object UpperBoundsDemo01 { def main(args: Array[String]): Unit = { val myCompare1 = new MyCompare1(8, 9) println(myCompare1.max)

/** * 注意Scala中Int不是Comparable的子类 */ val myCompare2 = new MyCompare2[Integer](8, 9) println(myCompare2.max) val myCompare22 = new MyCompare2[java.lang.Float](8.4f, 8.6f) println(myCompare22.max) }}

/** * 传统方式解决 * * @param inX * @param inY */class MyCompare1(inX: Int, inY: Int) { var x = inX var y = inY

def max = if (x > y) x else y}

/** * 使用Scala上界来完成 * 1. [T <: Comparable[T]] 表示T类型是Comparable 子类型 * 2. 即你传入的T类要继承Comparable接口 * 3. 这样就可以使用compareTo方法 * 4. 这样的写法(使用上界的写法)通用性比传统的好 */class MyCompare2[T <: Comparable[T]](inX: T, inY: T) { var x = inX var y = inY

/** * x.compareTo(y) 将此对象与指定对象进行比较。 * 负数---> x < y * 0 ---> x == y * 正数---> x > y */ def max = if (x.compareTo(y) > 0) x else y}~~~~

> Scala中上界课程测试题(理解上界含义)>> - `案例中使用到的类,见BoundsCommonClass.scala`

~~~~scalapackage com.atguigu.chapter16

/** * @Date 2021/4/5 19:49 * @Version 10.21 * @Author DuanChaojie */object UpperBoundsDemo02 { def main(args: Array[String]): Unit = { getSound(Seq(new Bird,new Bird)) println("-----------") getSound(Seq(new Animal,new Animal)) println("-----------") getSound(Seq(new Bird,new Animal)) println("-----------") //getSound(Seq(new Earth,new Earth)) 报错,因为Earth不是Animal的子类 //getSound(Seq(new Moon)) 报错 }

def getSound[T <: Animal](seq: Seq[T]) = { seq.map(_.sound()) }}~~~~

#### 下界(lower bounds)

> ==Java中下界:==在 Java 泛型里表示某个类型是 A类型的父类型,使用 `super 关键字`,语法如下:

~~~~java<T super A>//或用通配符的形式:<? super A>~~~~

> ==Scala中下界:==在 Scala 的下界或下限,使用 `>: 关键字`,语法如下:

~~~~scala[T >: A]//或用通配符:[_ >: A]~~~~

> Scala中下界应用实例

~~~~scala/** * @Date 2021/4/5 20:01 * @Version 10.21 * @Author DuanChaojie */object LowerBoundsDemo01 { def main(args: Array[String]): Unit = { getSound(Seq(new Earth,new Earth)).map(_.sound()) println("-------------------") getSound(Seq(new Animal,new Animal)).map(_.sound()) println("-------------------") // 可以使用,而且打印的是bird sounds,原因见小结 getSound(Seq(new Bird,new Bird)).map(_.sound()) println("-------------------") val seq = getSound(Seq(new Moon)) // seq是Object类型的 // val moon = seq.asInstanceOf[Moon] 报错 // moon.sound() }

def getSound[T >: Animal](seq: Seq[T]) = seq}~~~~

> Scala中下界的使用小结:>> 1. 对于下界,可以传入任意类型。> 2. `传入和Animal直系的,是Animal父类的还是父类处理,是Animal子类的按照Animal处理。`> 3. `和Animal无关的,一律按照Object处理。`> 4. 也就是下界,可以随便传,只是处理是方式不一样。> 5. 不能使用上界的思路来类推下界的含义。

#### 视图界定

> 1. `<% 的意思是“view bounds”(视界),它比<:适用的范围更广,除了所有的子类型,还允许隐式转换类型。`> 2. 视图界定应用案例:> 3. 使用视图界定的方式,比较两个Person对象的年龄大小。

~~~scala/** * @Date 2021/4/5 20:16 * @Version 10.21 * @Author DuanChaojie */object ViewBoundsDemo01 {

// 隐士函数 implicit def MyImplicit(cat: MyCat) = new Ordered[MyCat] { override def compare(that: MyCat) = { cat.age - that.age } }

def main(args: Array[String]): Unit = { val tom = new MyCat("tom", 18) val jack = new MyCat("jack", 2)

val myCompare3 = new MyCompare3(tom, jack) println(myCompare3.max) }}

 

/** * Ordered和Ordering的区别? * Ordering中的方法:def compare(x: T, y: T): Int * Orderd中有这个方法: def compareTo(that: A): Int = compare(that) * 1. T <% Ordered[T] 表示T是Ordered子类型 java.lang.Comparable * 2. 这里调用的compareTo方法是 T这个类型的方法 */class MyCompare3[T <% Ordered[T]](x: T, y: T) { def max = if (x.compareTo(y) > 0) x else y}~~~

#### 上下文界定

> 1. 与 view bounds 一样 context bounds(上下文界定)也是隐式参数的语法糖。为语法上的方便, 引入了”上下文界定”这个概念。> 2. 上下文界定应用实例> 1. 使用上下文界定+隐式参数的方式,比较两个Person对象的年龄大小> 2. 使用Ordering实现比较。

~~~~scalapackage com.atguigu.chapter16

/** * @Date 2021/4/5 20:53 * @Version 10.21 * @Author DuanChaojie */object ContextBoundsDemo01 { /** * 这里我定义一个隐式值 Ordering[MyCat]类型 */ implicit val catComparetor = new Ordering[MyCat] { override def compare(cat1: MyCat, cat2: MyCat): Int = cat1.age - cat2.age }

def main(args: Array[String]): Unit = { val tom = new MyCat("tom", 18) val jack = new MyCat("jack", 2) val myCompare4 = new MyCompare4(tom, jack) println(myCompare4.max)

println("-----------------") val myCompare5 = new MyCompare5(tom, jack) println(myCompare5.max) println("-----------------") val myCompare6 = new MyCompare6(tom, jack) println(myCompare6.max) }}

/** * 方式1 * 1. [T: Ordering] 泛型 * 2. o1: T, o2: T 接受T类型的对象 * 3. implicit comparetor: Ordering[T] 是一个隐式参数 */class MyCompare4[T: Ordering](o1: T, o2: T)(implicit comparetor: Ordering[T]) { def max = if (comparetor.compare(o1, o2) > 0) o1 else o2}

/** * 方式2,将隐式参数放到方法内 */class MyCompare5[T: Ordering](o1: T, o2: T) { def max = { //返回一个数字 def fun(implicit comparetor: Ordering[T]) = comparetor.compare(o1, o2) //如果f1返回的值>0,就返回o1,否则返回o2 if (fun > 0) o1 else o2 }

def lowwer = { def f1(implicit cmptor: Ordering[T]) = cmptor.compare(o1, o2) //返回一个数字 //如果f1返回的值>0,就返回o1,否则返回o2 if (f1 > 0) o2 else o1 }}

/** * 方式3,使用implicitly语法糖,最简单(推荐使用) */class MyCompare6[T: Ordering](o1: T, o2: T) { def max = { /** * 这句话就是会发生隐式转换,获取到隐式值 personComparetor * 底层仍然使用编译器来完成绑定(赋值的)工作 */ val comparetor = implicitly[Ordering[T]] //println("comparetor hashcode=" + comparetor.hashCode()) if (comparetor.compare(o1, o2) > 0) o1 else o2 }}~~~~

### 3. Scala协变、逆变和不变

> 1. `Scala的covariant协变(+),contravariant逆变(-),不可变invariant。`> 2. 在Java里,泛型类型都是invariant,比如 List<String> 并不是 List<Object> 的子类型。而Scala支持,可以在定义类型时声明(用加号表示为协变,减号表示逆变),如: trait List[+T] // 在类型定义时声明为协变这样会把List[String]作为List[Any]的子类型。

#### 应用实例

> 在这里引入关于这个符号的说明,在声明Scala的泛型类型时,`“+”表示协变,而“-”表示逆变` >> 1. `C[+T]:如果A是B的子类,那么C[A]是C[B]的子类,称为协变` > 2. `C[-T]:如果A是B的子类,那么C[B]是C[A]的子类,称为逆变` > 3. `C[T]:无论A和B是什么关系,C[A]和C[B]没有从属关系。称为不变。`

~~~~scalapackage com.atguigu.chapter16

/** * @Date 2021/4/5 21:13 * @Version 10.21 * @Author DuanChaojie */object LastDemo01 { /** * C[+T]:如果A是B的子类,那么C[A]是C[B]的子类,称为协变  * C[-T]:如果A是B的子类,那么C[B]是C[A]的子类,称为逆变  * C[T]:无论A和B是什么关系,C[A]和C[B]没有从属关系。称为不变 */ def main(args: Array[String]): Unit = {

val t4: Temp4[Super] = new Temp4[Sub]("hello"); //协变

val t5: Temp5[Sub] = new Temp5[Super]("hello"); //逆变

val t6: Temp6[Sub] = new Temp6[Sub]("hello"); //不变

}}

//协变class Temp4[+A](title: String) { override def toString: String = { title }}

//逆变class Temp5[-A](title: String) { override def toString: String = { title }}

//不变class Temp6[A](title: String) { override def toString: String = { title }}

// 支持协变class Super

//Sub是Super的子类class Sub extends Super~~~~

## ☆

脚本宝典总结

以上是脚本宝典为你收集整理的Scala泛型和上下界全部内容,希望文章能够帮你解决Scala泛型和上下界所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: