所谓类型参数,其实就是java中的泛型。
scala中的泛型和java中的泛型高度相似,也可以定义在类,方法上,成员变量上的泛型也需要沿用类的声明,定义的是一般也是用一个大写字母,但是泛型定义时需要使用[]包裹。
1. 泛型类
class XxxDao[T] {
def insert(t: T): Unit = {
}
}
trait XxxService[T] {
def save(t: T): Unit
}
class XxxServiceImpl extends XxxService[User] {
val dao = new XxxDao[User]()
override def save(t: User): Unit = {
dao.insert(t)
}
}
class XxxController {
val service = new XxxServiceImpl
def register(t: User): Unit = {
service.save(t)
}
}
class User(name:String, age:Int) {
}
2.泛型上限,视图界定
//scala版本的方法泛型
object _02Genericops {
def main(args: Array[String]): Unit = {
val arr = Array[Integer](3, -1, 0, 5, -5, 7, 6)
println("排序前的数组:" + arr.mkString("[", ", ", "]"))
insertSort(arr)
println("排序后的数组:" + arr.mkString("[", ", ", "]"))
}
/*
scala中的泛型的限定语法格式
T <: 类型
java中的泛型限定语法格式
T extends 类型
*/
def insertSort[T <: Comparable[T]](array: Array[T]): Unit = {
for(x <- 1 until array.length) {
for(y <- 1 to x reverse) {
if(array(y).compareto(array(y - 1)) < 0) {
swap(array, y, y - 1)
}
}
}
}
private def swap[T](arr: Array[T], y: Int, x: Int): Unit = {
val temp = arr(y)
arr(y) = arr(x)
arr(x) = temp
}
}
我们将java的版本修正为scala的版本,传入Integer类型的数组,完美解决问题,但是如果传递的是一个Int类型的数组,编译就会报错:
这个错误说的是Int类型,不具备比较性
确实没有体现出Comparable的特性,所以是不能直接进行比较,但是Int类型的数据,在scala中确确实实可以进行加减乘除等等运算,比较也是可以的,所以我们想要让上述代码也能执行成功,就需要将泛型定义的修改为:
[T <: Comparable[T]] ==> [T <%: Comparable[T]]
3.泛型的协变和逆变
当然默认情况下,scala也只能支持=左右两侧泛型是一致的,但是为了程序更加的灵活和通用,scala也支持泛型出现继承关系,所谓协变和逆变。
object _03Genericops {
def main(args: Array[String]): Unit = {
val myList1:MyList[Person] = new MyList[Person]()
val myList2:MyList[Person] = new MyList[Student]()//泛型的协变
val myList3:MyList1[Student] = new MyList1[Person]()//泛型的逆变
}
}
class MyList[+T] {//泛型协变的定义
}
class MyList1[-T] {//泛型逆变的定义
}
class Person {}
class Student extends Person{}
4. 隐式转换
scala提供的能够将一种类型根据需要,自动转化成其他类型的操作方式,进而可以让原有的类型具备其没有的功能,丰富现有api,而不会对原有的代码造成过多的污染。
这一点是scala程序非常优秀的一点设计,是java等其它语言所不具备的能力。其实在前面的视图界定案例中,视图界定就采用的是隐式转换将Int类型转化成为了RichInt,而RichInt扩展了Comparable接口,自然可以进行比较了。
通过隐式转换函数实现
implicit def double2Int(d:Double):Int = d.toInt
val a:Int = 3.5
println("a=" + a)
5.利用隐士转换丰富现有类库的功能
利用隐士转换丰富现有类库的功能,举例说明,通过java.io.File来读取一个文件中的内容,但是File没有read的功能,如何能做到让File也具备流的读写功能?
def main(args: Array[String]): Unit = {
val file = new File("E:/data/hello.txt")
file.read().foreach(println)
}
implicit def file2RichFile(file:File):RichFile = new RichFile(file)
//将file最后要转化为RichFile,才能具备read的功能
class RichFile(file:File) {
def read() = Source.fromFile(file).getLines()
}
6.引入隐士转换
最简单的其实就是,只要在要转换的变量的作用域内能够访问的到,即可进行自动转换,不需要人工干预。
在同一个文件中定义的隐式转换,不需要做任何的干预,但是如果要导入其它类中定义的隐式转换,要想在本类中使用,就必须要像导包一样导入。只要在其作用域到导入,即可。同时这个导入的隐式转换因为和导包一样,也不存在对原有类的结构发生入侵。
我们在导入的时候,我们倾向于导入到最靠近变量的部分。越靠近变量,其作用域范围越小,影响越小。
object _03ImplicitOps {
def main(args: Array[String]): Unit = {
import _02ImplicitOps._
val file = new File("E:/data/hello.txt")
file.read().foreach(println)
}
}
7.隐式转换参数
一个函数的参数被implicit修饰,称该参数为隐式转换参数,这个隐式转换参数在传递的时候,可以传,有时候也可以不用传。
def main(args: Array[String]): Unit = {
val list = List(3, -3, 0, -8, 45, 4)
list.foreach(println)
println("---------------")
implicit val ord = new Ordering[Int](){
override def compare(x: Int, y: Int) = {
y.compareto(x)
}
}
//显示的传递隐式转换参数
list.sorted(ord).foreach(println)
println("-------隐式传递---------")
//隐式传递隐式转换参数
list.sorted.foreach(println)
}
说明:隐式转换参数,可以显示的指定,也可以隐式的指定,如果是隐式指定,就需要让该变量在其作用域内访问到被implicit关键字修饰的相关变量,自动进行赋值。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。