在effective java 2nd中第28条,有对java范型PECS的介绍。
首先,我们看一个在java中经常被我们使用的方法addAll():
为什么在addAll的时候Collection的类型要通过继承范型E来进行限定? 有什么特殊的吗?接着我们再来看一看普通的add方法:
有没有觉得很奇怪?使用add方法的时候又不需要限定类型。
下面我们自己来写一个List进行以下测试,看看如果不限定类型的话会发生什么:
可以看到,编译报错:
Error:(24, 41) java: 不兼容的类型: java.util.List<java.lang.Integer>无法转换为java.util.Collection<java.lang.Number>
但是,单个add方法却不会报错。虽然Integer是Number的子类,但Collection<Integer>却不是Collection<Number>的子类,原因在此。
关于与addAllForTest对应的popAll方法,各位可以自己试一下。
PECS表示producer-extends、consumer-super,在上面的例子中,producer即addAllForTest,consumer是需要你实现的popAll,而extends与super则是针对这两个方法中参数的范型而言的。
下面介绍scala中的协变逆变:
进行声明时,用[+T]表示协变,[-T]表示逆变。
协变:如果String是AnyRef的子类,那么List[String]也是List[AnyRef]的子类。
逆变:如果String是AnyRef的子类,那么List[String]则是List[AnyRef]的父类。
协变点:方法返回值的位置称为协变点(covariant position)。
逆变点:方法参数的位置称为做逆变点(contravariant position)。
下面给一段代码加上注释来进行说明:
// 声明协变,但会报错 // covariant type A occurs in contravariant position in type A of value x // 协变类型A不允许出现在逆变点 class Person[+A]{ /** 假设该方法通过编译,那么pAnyref = pString之后,继续调用pAnyref.test(123)便会报错 * 因为pString.test的参数为String类型,但pAnyref的test方法参数类型为Anyref类型 * 这样一来,pAnyref = pString之后执行pAnyref.test(123)会报错,因为实际运行时是pString在运行 */ def test(x: A) = println(x) } var pAnyref = new Person[AnyRef] var pString = new Person[String] pAnyref = pString
这个例子会在def test(x: A) 处报错,无法进行编译。下面是逆变的例子:
// 声明逆变,下面这行代码会编译出错 // contravariant type A occurs in covariant position in type A of value test // 逆变类型A不允许出现在协变点上 class Person[-A] { /** 假设该方法通过编译,那么pString = pAnyref之后,继续调用pString.test便会报错 * 因为pAnyref.test返回Anyref,而pString作为父类,返回值为String * 在pString = pAnyref之后,调用pString.test的话,返回的其实是Anyref,与pString.test应有的返回值String不匹配,发生报错 */ def test: A = null.asInstanceOf[A] } var pAnyref = new Person[AnyRef] var pString = new Person[String] pString = pAnyref
对于scala中协变逆变的使用,是可以同java中的PECS互相参考的,这样学习起来变回容易很多,毕竟大家对java还是比较熟悉的。
相关推荐
Master the fundamentals of Scala and understand its emphasis on functional programming that sets it apart from Java. This book will help you translate what you already know in Java to Scala to start ...
赠送jar包:scala-java8-compat_2.11-0.7.0.jar; 赠送原API文档:scala-java8-compat_2.11-0.7.0-javadoc.jar; 赠送源代码:scala-java8-compat_2.11-0.7.0-sources.jar; 赠送Maven依赖信息文件:scala-java8-...
可以用scala ,也可以用java,我主要的目的是用来判断汉字是否为繁体,
在目标目录中scala-to-java.jar将创建scala-to-java.jar 使用java -jar target/scala-to-java.jar --slim运行应用程序。 可选的--slim标志可从输出中删除一些样板 输入任何scala代码,例如println("hello, world")...
Scala集合(二)Java开发Java经验技巧共10页.pdf.zip
博客配套文件,详细演示了在maven中如何混合编译java和scala共存的代码。
SpringBoot + SpringData Jpa + Scala + Mysql(java+Scala混编)
scala-js-java-time, 在JDK8中,java.time的Scala.js 实现 scalajs-java-time scalajs-java-time 是用于的java.time API的bsd许可 reimplementation,它支持在 Scala.js 项目中使用这里 API 。用法只需将以
本书循序渐进地介绍了Scala的函数式编程基础,虽然篇幅短小,却切中要害。读者可以学会使用Scala静态语言的强大功能创建简洁、可扩展、高度可并行的代码。对于多核时代JVM上的并发编程,Scala是绝好的工具,而本书是...
资源名称:Scala程序设计:Java虚拟机多核编程实战资源截图: 资源太大,传百度网盘了,链接在附件中,有需要的同学自取。
Martin Odersky 用他定义的匹萨语言给了 Java世界一个很大的冲击。尽管匹萨本身没有流行 但它展现了当把面向对象和函数型语言两种风格,技术地且很有品地混搭在一起时,就形成了 自然和强有力的组合。匹萨的设计成为...
SCALA程序设计-JAVA虚拟机多核编程实战
赠送jar包:scala-java8-compat_2.11-0.7.0.jar; 赠送原API文档:scala-java8-compat_2.11-0.7.0-javadoc.jar; 赠送源代码:scala-java8-compat_2.11-0.7.0-sources.jar; 赠送Maven依赖信息文件:scala-java8-...
Scala概述.pptx 变量.pptx 运算符.pptx 程序流程控制.pptx 函数式编程基础.pptx 面向对象编程(基础部分).pptx ...泛型 上下界 视图界定 上下文界定 协变逆变不变.pptx AKKA.pptx 韩顺平_Scala语言核心编程.pdf
面向Java开发人员的Scala指南 面向Java开发人员的Scala指南
- Java源文件:9个,用于展示Java与Scala在Spark中的协同工作; - .gitignore文件:1个,用于Git版本控制时忽略不必要的文件; - .iml工程文件:1个,为IntelliJ IDEA项目配置文件。 本源码基于Spark进行全面精讲,...
该demo是基于maven的scala(版本2.11.8)与java相互调用可以运行的最基本的例子。该demo可以导出可运行的jar文件。希望能对大家有帮助。
由于Scala运行于JVM之上,因此它可以访问任何Java类库并且与Java框架进行互操作。《快学Scala》从实用角度出发,给出了一份快速的、基于代码的入门指南。Horstmann以“博客文章大小”的篇幅介绍了Scala的概念,让你...
Scala for Java Developers. Scala for Java Developers
4 多态的具体化,尤其是协变的意义所在 5 各种重载的符号使用 之前读过 programming in scala,对语言的整体还停留在: 1 scala用起来比java更灵活 2 强大的collection,可以更加方便的处理collection类的数据 ...