文章目录

  • ​​泛型​​
  • ​​类型约束上下界​​
  • ​​上界​​
  • ​​下界​​
  • ​​视图界定​​
  • ​​上下文界定​​
  • ​​协变、逆变和不变​​

泛型

使用示例

def test={
//应用1
val msg = new IntMessage(1)
println(msg)
val msg2 = new StringMessage[String]("class")
println(msg2)
//应用2
val class01 = new EnglishClass[String,String,String]("春季","大数据","初级")
val class02 = new EnglishClass[String,String,Int]("春季","大数据",1)
//应用3
val list1 = List("hello","tom");
println(midList[String](list1))
val list2 = List(1,2);
println(midList[Int](list2))
}

//应用案例1
abstract class Message[T](s:T){
def get():T ={
s
}
}
class IntMessage[Int](s:Int) extends Message{
}
class StringMessage[String](s:String) extends Message{
}
//应用案例2
class EnglishClass[A,B,C](val season:A,val name:B,val cType:C){}

//应用案例3
def midList[E](l:List[E]):E={
l(l.length/2)
}

类型约束上下界

上界

java中泛型表示某个类型是A的子类型,使用extends关键字,这种形式成为上界,语法如下:

<T extends A>或<? extends A>

scala 中 泛型表示某个类型是A的子类型,使用 <: 语法如下:

[T<:A]  或 [_<:A]

上界的应用
编写通用类可以进行Int之间 Float之间等实现了Comparable接口的值的直接比较
代码如下

def test={
//传统方式
val comparaInt = new ComparaInt(10,20)
println(comparaInt.greater)

//上限 方式
//这种方式直接报错,因为 scala 的 Int 类型没有实现 Comparable
// val commonCompare1 = new CommonCompare(10,20)
// println(commonCompare1.greater)
//传入 Integer 得到正常结果 20
val commonCompare2 = new CommonCompare(Integer.valueOf(10),Integer.valueOf(20))
println(commonCompare2.greater)
//传入 Int 得到正常结果 20
//这是因为 predef 中定义了隐式转换,这里声明了 需要 java.lang.Integer 传入了 Int 编译器自动转换
val commonCompare3 = new CommonCompare[java.lang.Integer](10,20)
println(commonCompare3.greater)

//使用 视图的时候 可以自动进行 隐式转换 而不必 声明需要 java.lang.Integer
val commonCompare4 = new CommonCompare2(10,20)
println(commonCompare4.greater)

}
//传统方法
class ComparaInt(n1:Int,n2:Int){
def greater = if(n1>n2) n1 else n2
}
//泛型方法
class CommonCompare[T <:Comparable[T]](obj1:T,obj2:T){
def greater = if(obj1.compareTo(obj2)>0)obj1 else obj2
}

//泛型方法 视图 方式
class CommonCompare2[T <%Comparable[T]](obj1:T,obj2:T){
def greater = if(obj1.compareTo(obj2)>0)obj1 else obj2
}

下界

在java泛型中标识某个类是A类型的父类型,使用 super关键字 ,如下:

<T super A> 或<? super A>

在 Scala 中下界或下限使用 >: 关键字 如下:

[T >:A]或[_>:A]

示例

def test={
//满足下界的约束 Hello Earth
sound(Seq(new Earth ,new Earth)).map(_.sound())
//满足下界的约束 Hello Animal
sound(Seq(new Animal,new Animal)).map(_.sound())
//满足下界的约束 Hello Bird 这里虽然不是 Animal的父类也可以满足下界的约束 实际上是将 Bird 转换成了Animal类型
sound(Seq(new Bird,new Bird)).map(_.sound())

//如下代码编译执行都没有问题 因此不能用上界的思路去推导,是否满足
sound(Seq(new Moon,new Moon))
}
def sound[T>:Animal](things:Seq[T])=things

class Earth{
def sound(){
println("Hello Earth")
}
}
class Animal extends Earth {
override def sound(){
println("Hello Animal")
}
}
class Bird extends Animal {
override def sound(){
println("Hello Bird")
}
}
class Moon{
def sound(){
println("Hello Moon")
}
}

下界使用总结
对于下界可以传入任意类型,如果传入的是 T 的子类,按照T类型处理,和T无关的类一律按照object处理。
也就是说下界可以随便传参数,只不过处理方式不同而已

视图界定

就是说视图界定会自动采用隐式转换 转换为目标类型,单纯下界的方式不会自动使用隐式转换,但是视图界定可以
语法:[T<%A] 或 <?<%A> :表示如果 定义了传入参数类型和 A 类型的隐式转换那么 会自动调用隐式转换将传入参数转换为A类型
示例:自己写隐式转换结合视图界定的方式比较Person对象的年龄大小

//创建隐式转换,自动将 person 对象转换为Ordered的对象
implicit def personToOrderedPerson(p:Person3) = new Ordered[Person3]{
override def compare(that: Person3): Int = {
p.age-that.age
}
}

def test={
val p1 = new Person3("jim",10)
val p2 = new Person3("tom",12);

import impli.MyImplicit._
//创建时自动
val compareComm3 = new CompareComm(p1,p2)
println(compareComm3.getter2)

}
class Person3(val name:String,val age:Int){
override def toString: String = this.name+" "+this.age
}


class CompareComm[T<% Ordered[T]](obj1:T,obj2:T){ //这种写法可以使用隐式转换
def getter2 = if(obj1.compareTo(obj2)>0) obj1 else obj2
}

// class CompareComm2[T<: Ordered[T]](obj1:T,obj2:T){ //这种写法不能使用隐式转换
// def getter2 = if(obj1.compareTo(obj2)>0) obj1 else obj2
// }

上下文界定

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

示例:使用上下文界定+隐式参数的方式,比较两个Person 的年龄大小

//定义隐式值
implicit val personComp= new Ordering[Person4]{
override def compare(x: Person4, y: Person4): Int = {
x.age-y.age
}
}
class Person4(val name:String,val age:Int){
override def toString: String = this.name+" "+this.age
}
//类构造函数的参数可以放在 两个括号中
//class TT (val name:String)(val age:Int){}
//方式一 构造参数中使用隐式转换
//构造函数的参数可以放在两个括号中
// class CompareComm[T:Ordering](obj1:T,obj2:T)(implicit comparator:Ordering[T]){
class CompareComm[T:Ordering](obj1:T,obj2:T)(implicit comparator:Ordering[T]){
def greater = if(comparator.compare(obj1,obj2)>0)obj1 else obj2;
}
//方式二 将隐式转换放在方法内
class CompareComm2[T:Ordering](obj1:T,obj2:T){
def greater ={
def f1 (implicit comparator:Ordering[T]) ={
comparator.compare(obj1,obj2)
}
if(f1> 0) obj1 else obj2
}
}
//方式三 使用 implicitly 最简单
class CompareComm3[T:Ordering](obj1:T,obj2:T){
def greater ={
//这句话本身就是隐式转换,获取到personComp
implicit val comparator =implicitly[Ordering[T]]
if(comparator.compare(obj1,obj2)> 0) obj1 else obj2
}
}

def test={
val p1 = new Person4("jim",10)
val p2 = new Person4("tom",12);
//方式一
val comp = new CompareComm[Person4](p1,p2)
println(comp.greater)

//方式二
val comp2 = new CompareComm2[Person4](p1,p2)
println(comp2.greater)

//方式三
val comp3 = new CompareComm3[Person4](p1,p2)
println(comp3.greater)
}

协变、逆变和不变

对于一个带泛型参数的类型,比如 List[T],如果对A及其子类型B ,满足List[B]也是List[A]的子类型,那么称之为协变(covariant)
对于一个带泛型参数的类型,比如 List[T],如果对A及其子类型B ,满足List[A]是List[B]的子类型,那么称之为逆变(contravariant)。
如果既不是协变又不是逆变那么就是不变(invariant)。如 List[T],如果对A及其子类型B ,满足List[A]和List[B]没有任何父子关系
在java中所有的泛型都是 invariant ,即List 和 List 并没有任何父子关系。
而Scala中可以在定义类型时,通过语法定义声明为协变或逆变,如果不做声明默认就是不变
如:
List[+T] 在类型声明时定义为协变 这样 List[String] 就是 List[Any]的子类
List[-T] 在类型声明时定义为逆变 这样 List[Any] 就是 List[String]的子类
示例

def test={
//协变
//由于 协变 Tclass[Super] 是Tclass[Sub] 的父类 所以 可以直接赋值不报错
val t2:Tclass[Super] = new Tclass[Sub](new Sub())
//同理该行报错 父类型变量不能赋值给子类型
// val t3:Tclass[Sub] = new Tclass[Super](new Super())

//逆变
//由于 协变 Tclass[Super] 是Tclass[Sub] 的子类类 父类不能赋值给子类 所以该行报错
// val t4:Tclass2[Super] = new Tclass2[Sub](new Sub())
//同理该行不报错
val t5:Tclass2[Sub] = new Tclass2[Super](new Super())
//不变
//由于 不变 Tclass[Super] 是Tclass[Sub] 没有父子关系 因此 类型不匹配不能相互赋值 所以两行都报错
// val t6:Tclass2[Super] = new Tclass2[Sub](new Sub())
//val t7:Tclass3[Sub] = new Tclass3[Super](new Super())
}
//定义两个有父子关系的类 Super 和 Sub
class Super
class Sub extends Super
//定义协变类
class Tclass[+T](param:T){}
//定义逆变类
class Tclass2[-T](param:T){}
//定义不变类
class Tclass3[T](param:T){}