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. (六)logback.xml 配置详解

    原文链接:https://www.cnblogs.com/taiyonghai/p/9290641.html,https://blog.csdn.net/A615883576/article/deta ...

  2. (十三)exec-maven-plugin配置及使用

    原文链接:https://www.cnblogs.com/lianshan/p/7358966.html 背景: 如果你想在项maven生命周期内,运行一段java代码,或者一段独立的程序,或者说我们 ...

  3. node实现文件属性批量修改(时间属性)

    前言 在默认情况下,一个文件的创建时间和修改时间是系统自己设定的,我们不能修改该的.但我们有时为了某种特殊需要,为了不让别人一眼看出文件已经给修改了,我们又需要修改文件的创建时间和修改时间.那么如何修 ...

  4. Java内存溢出OutOfMemoryError的产生与排查

    在java的虚拟机异常中,有两个异常是大家比较关心的,一个是StackOverflowError,另一个是OutOfMemoryError.今天我们就来看看OutOfMemoryError是怎么产生的 ...

  5. Python的多继承问题-MRO和C3算法

    大部分内容转载自C3 线性化算法与 MRO 理解Python中的多继承 Python 中的方法解析顺序(Method Resolution Order, MRO)定义了多继承存在时 Python 解释 ...

  6. Golang简易入门教程——面向对象篇

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是golang专题的第9篇文章,我们一起来看看golang当中的面向对象的部分. 在现在高级语言当中,面向对象几乎是不可或缺也是一门语言 ...

  7. 手写spring事务框架-蚂蚁课堂

    1.视频参加C:\Users\Administrator\Desktop\蚂蚁3期\[www.zxit8.com] 0017-(每特教育&每特学院&蚂蚁课堂)-3期-源码分析-手写Sp ...

  8. npm -v 报错:Error: EPERM: operation not permitted, mkdir 'C:\soft\nodejs'

    npm -v 报错:Error: EPERM: operation not permitted, mkdir 'C:\soft\nodejs' 起因:原本安装node在C盘soft文件夹下,按node ...

  9. python的一些基础知识

    一.函数介绍 二.模块与包 三.面向对象介绍 四.网络编程基础应用了解 五.基于MySQL对数据库的理解及基础操作 六.粗浅学习的前端知识整理

  10. java基础-循环标签

    outer: for innter: for break outer//跳出整个循环: continue outer//结束本次外循环的循环 break inner; continute inner; ...