1 泛型

1)如果我们要求函数的参数可以接受任意类型。可以使用泛型,这个类型可以代表任意的数据类型。

2)例如 List,在创建 List 时,可以传入整型、字符串、浮点数等等任意类型。那是因为 List 在 类定义时引用了泛型。比如在Java中:public interface List<E> extends Collection<E>

Scala泛型应用案例1

1)编写一个Message类

2)可以构建Int类型的Message,String类型的Message.

3)要求使用泛型来完成设计,(说明:不能使用Any)

object GenericUse {
def main(args: Array[String]): Unit = {
val mes1 = new StrMessage[String]("10")
println(mes1.get)
val mes2 = new IntMessage[Int](20)
println(mes2.get)
}} // 在 Scala 定义泛型用[T], s 为泛型的引用
abstract class Message[T](s: T) {
def get: T = s
}
// 子类扩展的时候,约定了具体的类型
class StrMessage[String](msg: String) extends Message(msg)
class IntMessage[Int](msg: Int) extends Message(msg)

Scala泛型应用案例2

1)请设计一个EnglishClass (英语班级类),在创建EnglishClass的一个实例时,需要指定[ 班级开班季节(spring,autumn,summer,winter)、班级名称、班级类型]

2)开班季节只能是指定的,班级名称为String, 班级类型是(字符串类型 "高级班", "初级班"..) 或者是 Int 类型(1, 2, 3 等)

3)请使用泛型来完成本案例.

// Scala 枚举类型
object SeasonEm extends Enumeration {
type SeasonEm = Value //自定义SeasonEm,是Value类型,这样才能使用
val spring, summer, winter, autumn = Value
}
object GenericUse2 {
def main(args: Array[String]): Unit = { val class1 = new EnglishClass[SeasonEm, String, String](SeasonEm.spring, "001班", "高级班")
println(class1.classSeason + " " + class1.className + " " + class1.classType) val class2 = new EnglishClass[SeasonEm, String, Int](SeasonEm.spring, "002班", 1)
println(class2.classSeason + " " + class2.className + " " + class2.classType)
}}
// Scala 枚举类型
object SeasonEm extends Enumeration {
type SeasonEm = Value //自定义SeasonEm,是Value类型,这样才能使用
val spring, summer, winter, autumn = Value
}
// 定义一个泛型类
class EnglishClass[A, B, C](val classSeason: A, val className: B, val classType: C)

Scala泛型应用案例3

1)定义一个函数,可以获取各种类型的

2)List 的中间index的值 使用泛型完成

def getMidEle[A](l: List[A])={
l(l.length/2)
}
object GenericUse3 {
def main(args: Array[String]): Unit = {
// 定义一个函数,可以获取各种类型的 List 的中间index的值
val list1 = List("jack",100,"tom")
val list2 = List(1.1,30,30,41) println(getMidEle(list1)) }
// 定义一个方法接收任意类型的 List 集合
def getMidEle[A](l: List[A])={
l(l.length/2)
}
}

2 类型约束-上界(Upper Bounds)/下界(lower bounds)

上界(Upper Bounds)介绍和使用

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

[T <: A]

//或用通配符:

[_ <: A]

scala中上界应用案例-要求

1)编写一个通用的类,可以进行Int之间、Float之间、等实现了Comparable接口的值直接的比较.//java.lang.Integer

2)分别使用传统方法上界的方式来完成,体会上界使用的好处.

class CompareInt(n1: Int, n2: Int) {
def greater = if(n1 > n2) n1 else n2
}
class CompareComm[T <: Comparable[T]](obj1: T, obj2: T) {
def greater = if(obj1.compareTo(obj2) > 0) obj1 else obj2
}
//映射转换 Predef.scala

scala中上界应用案例-代码

object UpperBoundsDemo {
def main(args: Array[String]): Unit = {
//常规方式
/*
val compareInt = new CompareInt(-10, 2)
println("res1=" + compareInt.greater)
val compareFloat = new CompareFloat(-10.0f, -20.0f)
println("res2=" + compareFloat.greater)*/
/*val compareComm1 = new CompareComm(20, 30)
println(compareComm1.greater)*/
val compareComm2 = new CompareComm(Integer.valueOf(20), Integer.valueOf(30))
println(compareComm2.greater)
val compareComm3 =
new CompareComm(java.lang.Float.valueOf(20.1f), java.lang.Float.valueOf(30.1f))
println(compareComm3.greater)
val compareComm4 = new CompareComm[java.lang.Float](201.9f, 30.1f)
println(compareComm4.greater)
}
}
/*class CompareInt(n1: Int, n2: Int) {
def greater = if(n1 > n2) n1 else n2
}
class CompareFloat(n1: Float, n2: Float) {
def greater = if(n1 > n2) n1 else n2
}*/
//使用上界的方式,可以有更好的通用性
class CompareComm[T <: Comparable[T]](obj1: T, obj2: T) {
def greater = if(obj1.compareTo(obj2) > 0) obj1 else obj2
}

下界(Lower Bounds)介绍和使用

在 scala 的下界或下限,使用 >: 关键字,语法如下:

[T >: A]

//或用通配符:

[_ >: A]

scala中下界应用实例

object LowerBoundsDemo {
def main(args: Array[String]): Unit = { biophony(Seq(new Earth, new Earth)).map(_.sound()) biophony(Seq(new Animal, new Animal)).map(_.sound())
biophony(Seq(new Bird, new Bird)).map(_.sound()) val res = biophony(Seq(new Bird)) val res2 = biophony(Seq(new Object))
val res3 = biophony(Seq(new Moon))
println("\nres2=" + res2)
println("\nres3=" + res2) }
def biophony[T >: Animal](things: Seq[T]) = things
}
class Earth { //Earth 类
def sound(){ //方法
println("hello !")
}
}
class Animal extends Earth{
override def sound() ={ //重写了Earth的方法sound()
println("animal sound")
}
}
class Bird extends Animal{
override def sound()={ //将Animal的方法重写
print("bird sounds")
}
}
class Moon {}

scala中下界的使用小结

def biophony[T >: Animal](things: Seq[T]) = things

1)对于下界,可以传入任意类型

2)传入和Animal直系的,是Animal父类的还是父类处理,是Animal子类的按照Animal处理

3)和Animal无关的,一律按照Object处理

4)也就是下界,可以随便传,只是处理是方式不一样

5)不能使用上界的思路来类推下界的含义

3 视图界定(View bounds)

视图界定基本介绍

<% 的意思是“view bounds”(视界),它比<:适用的范围更广,除了所有的子类型,还允许隐式转换类型。

def method [A <% B](arglist): R = ... 等价于:

def method [A](arglist)(implicit viewAB: A => B): R = ... 或等价于:

implicit def conver(a:A): B = …

<% 除了方法使用之外,class 声明类型参数时也可使用: class A[T <% Int]

视图界定应用案例1

object ViewBoundsDemo {
def main(args: Array[String]): Unit = {
//方式1
val compareComm1 = new CompareComm(20, 30)
println(compareComm1.greater)
//同时,也支持前面学习过的上界使用的各种方式,看后面代码
}
}
class CompareComm[T <% Comparable[T]](obj1: T, obj2: T) {
def greater = if(obj1.compareTo(obj2) > 0) obj1 else obj2
}
object ViewBoundsDemo {
def main(args: Array[String]): Unit = {
val compareComm1 = new CompareComm(20, 30) //
println(compareComm1.greater) val compareComm2 = new CompareComm(Integer.valueOf(20), Integer.valueOf(30))
println(compareComm2.greater) val compareComm4 = new CompareComm[java.lang.Float](201.9f, 30.1f)
println(compareComm4.greater)
//上面的小数比较,在视图界定的情况下,就可以这样写了
val compareComm5 =
new CompareComm(201.9f, 310.1f)
println(compareComm5.greater)
}
} /**
* <% 视图界定 view bounds
* 会发生隐式转换
*/
class CompareComm[T <% Comparable[T]](obj1: T, obj2: T) {
def greater = if(obj1.compareTo(obj2) > 0) obj1 else obj2
}

视图界定应用案例2

说明: 使用视图界定的方式,比较两个Person对象的年龄大小。

val p1 = new Person("tom", 10)
val p2 = new Person("jack", 20)
val compareComm2 = new CompareComm2(p1, p2)
println(compareComm2.getter) class Person(val name: String, val age: Int) extends Ordered[Person] {
override def compare(that: Person): Int = this.age - that.age
override def toString: String = this.name + "\t" + this.age}
class CompareComm2[T <% Ordered[T]](obj1: T, obj2: T) {
def getter = if (obj1 > obj2) obj1 else obj2
def geatter2 = if (obj1.compareTo(obj2) > 0) obj1 else obj2
}

视图界定应用案例3

说明: 自己写隐式转换结合视图界定的方式,比较两个Person对象的年龄大小。

 // 隐式将Student -> Ordered[Person2]//放在object MyImplicit 中
implicit def person22OrderedPerson2(person: Person2) = new Ordered[Person2]{
override def compare(that: Person2): Int = person.age - that.age
} val p1 = new Person2("tom", 110)
val p2 = new Person2("jack", 20)
import MyImplicit._
val compareComm3 = new CompareComm2(p1, p2)
println(compareComm3.geatter) class Person2(val name: String, val age: Int) {
override def toString = this.name + "\t" + this.age
}
class CompareComm3[T <% Ordered[T]](obj1: T, obj2: T) {
def geater = if (obj1 > obj2) obj1 else obj2
}

4 上下文界定(Context bounds)

与 view bounds 一样 context bounds(上下文界定)也是隐式参数的语法糖。为语法上的方便, 引入了”上下文界定”这个概念

object ContextBoundsDemo {
implicit val personComparetor = new Ordering[Person] {
override def compare(p1: Person, p2: Person): Int =
p1.age - p2.age
} def main(args: Array[String]): Unit = {
val p1 = new Person("mary", 30)
val p2 = new Person("smith", 35)
val compareComm4 = new CompareComm4(p1,p2)
println(compareComm4.geatter)
val compareComm5 = new CompareComm5(p1,p2)
println(compareComm5.geatter)
val compareComm6 = new CompareComm6(p1,p2)
println(compareComm6.geatter)
}}
//方式1
class CompareComm4[T: Ordering](obj1: T, obj2: T)(implicit comparetor: Ordering[T]) {
def geatter = if (comparetor.compare(obj1, obj2) > 0) obj1 else obj2
}
//方式2,将隐式参数放到方法内
class CompareComm5[T: Ordering](o1: T, o2: T) {
def geatter = {
def f1(implicit cmptor: Ordering[T]) = cmptor.compare(o1, o2)
if (f1 > 0) o1 else o2
}}
//方式3,使用implicitly语法糖,最简单(推荐使用)
class CompareComm6[T: Ordering](o1: T, o2: T) {
def geatter = {
//这句话就是会发生隐式转换,获取到隐式值 personComparetor
val comparetor = implicitly[Ordering[T]]
println("CompareComm6 comparetor" + comparetor.hashCode())
if(comparetor.compare(o1, o2) > 0) o1 else o2
}}
//一个普通的Person类
class Person(val name: String, val age: Int) {
override def toString = this.name + "\t" + this.age
}

5 协变、逆变和不变

1)Scala的协变(+),逆变(-),协变covariant、逆变contravariant、不可变invariant

2)对于一个带类型参数的类型,比如 List[T],如果对A及其子类型B,满足 List[B]也符合List[A]的子类型,那么就称为covariance(协变) ,如果 List[A]是 List[B]的子类型,

即与原来的父子关系正反,则称为contravariance(逆变)。如果一个类型支持协变或逆变,则称这个类型为variance(翻译为可变的或变型),否则称为invariance(不可变的)

3)在Java里,泛型类型都是invariant,比如 List<String> 并不是 List<Object> 的子类型。而scala支持,可以在定义类型时声明(用加号表示为协变,减号表示逆变),

如: trait List[+T] // 在类型定义时声明为协变这样会把List[String]作为List[Any]的子类型。

应用实例

在这里引入关于这个符号的说明,在声明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]没有从属关系。称为不变.

val t: Temp[Super] = new Temp[Sub]("hello world1")
class Temp3[A](title: String) { //Temp3[+A] //Temp[-A]
override def toString: String = {
title
}}
//支持协变
class Super
class Sub extends Super

Scala 基础(十六):泛型、类型约束-上界(Upper Bounds)/下界(lower bounds)、视图界定(View bounds)、上下文界定(Context bounds)、协变、逆变和不变的更多相关文章

  1. Bootstrap<基础十六> 导航元素

    Bootstrap 提供的用于定义导航元素的一些选项.它们使用相同的标记和基类 .nav.Bootstrap 也提供了一个用于共享标记和状态的帮助器类.改变修饰的 class,可以在不同的样式间进行切 ...

  2. 解读经典《C#高级编程》最全泛型协变逆变解读 页127-131.章4

    前言 本篇继续讲解泛型.上一篇讲解了泛型类的定义细节.本篇继续讲解泛型接口. 泛型接口 使用泛型可定义接口,即在接口中定义的方法可以带泛型参数.然后由继承接口的类实现泛型方法.用法和继承泛型类基本没有 ...

  3. Scala学习十八——高级类型

    一.本章要点 单例类型可用于方法串接和带对象参数的方法 类型投影对所有外部类的对象都包含了其他内部类的实例 类型别名给类型指定一个短小的名称 结构类型等效于”鸭子类型“ 存在类型为泛型的通配参数提供了 ...

  4. Programming In Scala笔记-第十九章、类型参数,协变逆变,上界下界

    本章主要讲Scala中的类型参数化.本章主要分成三个部分,第一部分实现一个函数式队列的数据结构,第二部分实现该结构的内部细节,最后一个部分解释其中的关键知识点.接下来的实例中将该函数式队列命名为Que ...

  5. Scala学习十六——XML处理

    一.本章要点 XML字面量<like>this</like>的类型为NodeSeq 可以在XML字面量中内嵌Scala代码 Node的child属性产出后代节点 Node的at ...

  6. java基础(十六)----- equals()与hashCode()方法详解 —— 面试必问

    本文将详解 equals()与hashCode()方法 概述 java.lang.Object类中有两个非常重要的方法: public boolean equals(Object obj) publi ...

  7. WDA基础十六:ALV的颜色

    这里介绍三种类型的颜色:列的背景色,单元格的背景色,单元格文本的颜色. 1.给ALV结构添加颜色控制字段: 三个字段都是同一类型:WDY_UIE_LIBRARY_ENUM_TYPE COL_BACKG ...

  8. C++学习基础十六-- 函数学习笔记

    C++ Primer 第七章-函数学习笔记 一步一个脚印.循序渐进的学习. 一.参数传递 每次调用函数时,都会重新创建函数所有的形参,此时所传递的实参将会初始化对应的形参. 「如果形参是非引用类型,则 ...

  9. 十六, Oracle约束

    前言 数据的完整性用于确保数据库数据遵从一定的商业和逻辑规则,在oracle中,数据完整性可以使用约束.触发器.应用程序(过程.函数)三种方法来实现,在这三种方法中,因为约束易于维护,并且具有最好的性 ...

随机推荐

  1. jreble备注

    版本:2019.1.4 激活URL:http://jrebel.pyjuan.com/36931214-7bb6-42d4-afd7-26eb5628e004

  2. Vim配合Shell自动上传ftp

    shell代码: #!/bin/bash #网站配置 a1=('本地目录;主机;yonghuming;mima;远程目录' '本地目录;主机;user;pwd;远程目录') #选取的网站配置 web= ...

  3. [AHOI2017/HNOI2017]单旋

    题目   点这里看题目. 分析   最妙的地方在于,这道题其实是用一种数据结构模拟另一种数据结构!   我们需要维护深度和树的结构,以下对于每个操作进行分别讨论. 插入一个新节点   可以发现,这个新 ...

  4. Com训练_1

    初次接触Com大概是2001年,离现在多年了,那时认识比较肤浅,再次接触学习下. //ComPort + D7, 稍后将训练ComPort6 + D10.3.2环境 //MSComm + D7,D10 ...

  5. (一)maven搭建和idea的配置

    一.下载安装 前往 https://maven.apache.org/download.cgi 下载最新版的Maven程序.解压到任意目录 (要养成不起中文路径的好习惯,否则有时间出问题真的很难找) ...

  6. pycharm 配置 git 方法

    1.打开pycharm ,点击 file——Default-setting——version control 2.配置github账号密码 3.Path to Git executable中填写git ...

  7. Dubbo——SPI及自适应扩展原理

    文章目录 引言 正文 一.什么是SPI? 1. Java SPI的实现 2. Dubbo SPI实现原理 由配置文件得到的猜想 SPI源码 二.自适应扩展机制 三.Dubbo IOC 总结 引言 Du ...

  8. 11.实战交付一套dubbo微服务到k8s集群(3)之dubbo微服务底包镜像制作

    1.下载jre镜像并推送到harbor [root@hdss7- ~]# docker pull registry.cn-hangzhou.aliyuncs.com/yfhub/jre8:8u112 ...

  9. 深入了解C#(TPL)之Parallel.ForEach异步

    前言 最近在做项目过程中使用到了如题并行方法,当时还是有点犹豫不决,因为平常使用不多, 于是借助周末时间稍微深入了下,发现我用错了,故此做一详细记录,希望对也不是很了解的童鞋在看到本文此文后不要再犯和 ...

  10. SpringMVC 学习笔记(三)数据的校验

    34. 尚硅谷_佟刚_SpringMVC_数据绑定流程分析.avi 例如:在jsp中输入一个String字符串类型,需要转换成Date类型的流程如下 convertservice对传入的数据进行转换 ...