1、什么是泛型类
和Java或者C++一样,类和特质可以带类型参数。在Scala中,使用方括号来定义类型参数
测试程序:
2、什么是泛型函数
函数和方法也可以带类型参数。和泛型类一样,我们需要把类型参数放在方法名之后。
注意:这里的ClassTag是必须的,表示运行时的一些信息,比如类型。
3、Upper Bounds 与 Lower Bounds
类型的上界和下界,是用来定义类型变量的范围。它们的含义如下:
S <: T
这是类型上界的定义。也就是S必须是类型T的子类(或本身,自己也可以认为是自己的子类。
U >: T
这是类型下界的定义。也就是U必须是类型T的父类(或本身,自己也可以认为是自己的父类)。
示例1:
示例2(上界):
/**
* 演示类型变量的上界: S <: T
* S和T代表类型
* 含义是:S必须是T的子类或者本事,则T就叫S的上界
*/
//定义父类:Vehicle代表所有的交通工具
class Vehicle{
//方法:驾驶
def drive() ={println("Driving")}
}
//定义Vehicle的两个子类:Car和Bicycle
class Car extends Vehicle{
override def drive() ={println("Car Driving")}
}
class Bicycle extends Vehicle{
override def drive() ={println("Bicycle Driving")}
}
//测试
object ScalaUpperBounds {
//定义方法
def takeVehicle[T <: Vehicle](v:T) = {v.drive()}
def main(args: Array[String]) {
//定义一个交通工具的对象
var v:Vehicle = new Vehicle
takeVehicle(v)
var c:Car = new Car
takeVehicle(c)
}
}
示例3:
4、视图界定(View bounds)
它比 <:
适用的范围更广,除了所有的子类型,还允许隐式转换过去的类型。用 <%
表示。尽量使用视图界定,来取代泛型的上界,因为适用的范围更加广泛。
示例:
(1)上面写过的一个列子。这里由于T的上界是String,当我们传递100和200的时候,就会出现类型不匹配。
(2)但是100和200是可以转成字符串的,所以我们可以使用视图界定让addTwoString方法接收更广泛的数据类型,即:字符串及其子类、可以转换成字符串的类型。
注意:使用的是
<%
但实际运行的时候,会出现错误:
这是因为:Scala并没有定义如何将Int转换成String的规则,所以要使用视图界定,我们就必须创建转换的规则。
(3)创建转换规则
(4)运行成功
5、协变和逆变
(1)协变:
Scala的类或特征的范型定义中,如果在类型参数前面加入+
符号,就可以使类或特征变为协变了。
(2)逆变:
在类或特征的定义中,在类型参数之前加上一个-
符号,就可定义逆变范型类和特征了。
//Scala的逆变:泛型变量的值可以是本身或者其父类
package demo2{
//父类:动物
class Animal{}
//子类:鸟
class Bird extends Animal
//麻雀
class Sparrow extends Bird
//吃东西的类
class EatSomething[-T](t:T){}
object DemoClass2 {
def main(args: Array[String]) {
//创建一个Bird吃东西的对象
var c1:EatSomething[Bird] = new EatSomething[Bird](new Bird)
//创建一个麻雀吃东西的对象
//问题:能否将c1付给c2?
//原因:尽管Bird是Sparrow的父类,但是EatSomething[Bird]不是EatSomething[Sparrow]的父类
var c2:EatSomething[Sparrow] = c1
}
}
}
6、隐式转换函数
所谓隐式转换函数指的是以implicit
关键字申明的带有单个参数
的函数。
(1)前面讲视图界定时候的一个例子:
(2)再举一个例子:我们把Fruit对象转换成了Monkey对象
//Scala的隐式转换
//水果
class Fruit(name:String){
def getFruitName():String = {name}
}
//猴子Monkey
class Monkey(f:Fruit){
def say() = {println("Monkey like " + f.getFruitName())}
}
object ImplicitDemo {
implicit def fruitToMonkey(f:Fruit):Monkey = {new Monkey(f)}
def main(args: Array[String]) {
//创建一个Fruit的对象
var f:Fruit = new Fruit("香蕉")
//问题:能否调用f.say() 方法呢?解决方法:将Fruit的对象转换为Monkey的对象
f.say()
}
}
7、隐式参数
使用implicit
申明的函数参数叫做隐式参数。我们也可以使用隐式参数实现隐式的转换
8、隐式类
所谓隐式类: 就是对类增加implicit 限定的类,其作用主要是对类的功能加强
!
/**
* Scala的隐式类
*/
object ImplicitClass {
//隐式类
implicit class Calc(x:Int){
def add(a:Int):Int = a + x
}
def main(args: Array[String]) {
println("两个数字的和:" + 1.add(2))
}
/*
隐式类执行的过程:
1. 当1.add(2),scala的编译器不会立即报错;在当前域当中查找,有没有implicit修饰的,同时可以将Int作为参数的构造器,
并且具有add方法的类。通过查找,找到了Calc
2. 利用隐式类Calc来执行add方法
*/
}
转载:https://blog.csdn.net/weixin_43520450/article/details/105991494