Scala语言编码高级特性
1、泛型
案例1,代码实现:
package org.apache.scala.day07
/**
* 时间: 2021/07/25 15:00
* 描述: 泛型
*
* 泛型简单测试
*/
object Demo010_GenericType01 {
def main(args: Array[String]): Unit = {
println(new Student11[String, Int]("黄渤", 33).name)
println(new Person11[String]("徐峥").name)
val array = new Array[String](10)
array(0) = "huangbo"
// array(1) = 11
}
}
class Person11[T](var name: T) {}
class Student11[T, S](var name: T, var age: S) {}
打印输出:
案例2,代码实现:
package org.apache.scala.day07
class Person[T, S](var name: T, var age: S)
class Student(var name: String, var age: Int) extends Comparable[Student] {
override def compareTo(o: Student): Int = {
return o.age - this.age
}
}
/**
* 泛型类
*/
class MrRight1[T <: Comparable[T]] {
//定义一个选择方法,实现选择的功能
def choose(first: T, second: T): T = {
if (first.compareTo(second) > 0) first else second
}
}
/**
* 泛型方法
*/
class MrRight2 {
def choose[T <: Comparable[T]](first: T, second: T): T = {
if (first.compareTo(second) > 0) first else second
}
}
/**
* 描述: 泛型的基本测试
*
* 泛型类 和 泛型方法的测试
*/
object Demo010_GenericType02 {
def main(args: Array[String]): Unit = {
println(new Person[String, Int]("黄渤", 33).name)
// 如果是类上定义的泛型,通过下面的方式调用
val right1 = new MrRight1[Student]
val hadoop1 = new Student("java", 77)
val spark1 = new Student("scala", 88)
val student1 = right1.choose(hadoop1, spark1)
println(student1.name)
//如果是在方法上定义的泛型,可以使用下面的方式:
var right2 = new MrRight2
val hadoop2 = new Student("hadoop", 99)
val spark2 = new Student("spark", 88)
val student2: Student = right2.choose[Student](hadoop2, spark2)
println(student2.name)
}
}
打印输出:
2、类型界定
代码实现:
package org.apache.scala.day07
/**
* 描述: 类型界定
*/
class Demo011_GenericType02 {
// def compare[T](first:T,second:T)={
def compare[T <: Comparable[T]](first: T, second: T) = {
if (first.compareTo(second) > 0)
first
else
second
}
}
object Demo011_GenericType02 {
def main(args: Array[String]): Unit = {
val tvb = new Demo011_GenericType02
println(tvb.compare("A", "B"))
}
}
打印输出:
3、视图界定
代码实现:
package org.apache.scala.day07
/**
* 视图界定
*/
case class Student1234[T, S <% Comparable[S]](var name: T, var height: S)
object GenericTypeTest3 {
def main(args: Array[String]): Unit = {
// 这是合法的语句
val s = Student1234("john", "170")
println(s.name, s.height)
//下面这条语句不合法,这是因为Int类型没有实现Comparable接口
//使用视图界定即可
val s2 = Student1234("john", 170)
println(s2.name, s2.height.isInstanceOf[Int])
}
}
打印输出:
4、类型通配符
代码实现:
package org.apache.scala.day07
class Person77(val name: String) {
override def toString() = name
}
class Student77(name: String) extends Person77(name)
class Teacher77(name: String) extends Person77(name)
class Pair[T](val first: T, val second: T) {
override def toString() = "first:" + first + " second: " + second;
}
/**
* 类型通配符
*/
object TypeWildcard {
def main(args: Array[String]): Unit = {
makeFriends(new Pair(new Student77("黄渤学生"), new Teacher77("徐峥老师")))
makeFriends(new Pair(new Student77("黄渤学生"), new Student77("徐峥学生")))
makeFriends(new Pair(new Teacher77("黄渤老师"), new Student77("徐峥学生")))
makeFriends(new Pair(new Teacher77("黄渤老师"), new Teacher77("徐峥老师")))
}
// Pair的类型参数限定为[_<:Person],即输入的类为Person及其子类
// 类型通配符和一般的泛型定义不一样,泛型在类定义时使用,而类型能配符号在使用类时使用
def makeFriends(p: Pair[_ <: Person77]) = {
println(p.first + " is making friend with " + p.second)
}
}
打印输出:
5、上下界、视图边界实现方式
代码实现:
package org.apache.scala.day07
class GranderFather
class Father extends GranderFather
class Me extends Father
class Son extends Me
class Tongzhuo
/**
* 下界、视图边界实现方式
*/
object Demo013_GenericType_XiaJie {
// 定义下界
def getIDCard1[R >: Me](person: R): Unit = {
println("好吧,他的身份证就交给你保管了");
}
// 定义上界
def getIDCard2[R <: Me](person: R): Unit = {
println("好吧,他的身份证就交给你保管了");
}
// 定义视图边界
def getIDCard3[R <% Me](person: R): Unit = {
println("好吧,他的身份证就交给你保管了");
}
def main(args: Array[String]): Unit = {
getIDCard1[GranderFather](new GranderFather)
getIDCard2[Son](new Son)
getIDCard3[Me](new Me)
// 这句代码会报错
// getIDCard[Tongzhuo](new Tongzhuo)
implicit def tongzhuo2Me(tz: Tongzhuo): Me = new Me
getIDCard3[Tongzhuo](new Tongzhuo)
}
}
打印输出:
6、函数用泛型表示
将函数也用泛型表示,因为是协变的,输入的类型必须是T的超类,这样返回值类型 MyList[U] 就是 MyList[T] 的超类。符合协变的性质。
案例1,代码实现:
package org.apache.scala.day07
/**
* 函数用泛型表示
*/
object XieBianTest {
def main(args: Array[String]): Unit = {
val list1: MyList[Any] = new MyList[AnyRef]("黄", null)
val list2: MyList[Any] = new MyList[String]("黄", new MyList[String]("黄", null))
val list3: MyList[String] = new MyList[String]("黄", null)
val list4: MyList[Any] = new MyList[Object]("黄", list3)
val abc: Any = "huangbo"
list1.prepend[Any]("huangbo")
println(list1)
}
}
class MyList[+T](val head: T, val tail: MyList[T]) {
/**
* 将函数也用泛型表示
* 因为是协变的,输入的类型必须是T的超类
* 这样返回值类型 MyList[U] 就是 MyList[T] 的超类。符合协变的性质
*/
def prepend[U >: T](newHead: U): MyList[U] = new MyList(newHead, this)
// def prepend[T](newHead: T): MyList[T] = new MyList(newHead, this)
}
打印输出:
案例2,代码实现:
package org.apache.scala.day07
object XieBianTest2 {
def main(args: Array[String]): Unit = {
val list: List[Any] = new List[String]("光环国际", null)
println(list)
}
}
class List[+T](val head: T, val tail: List[T]) {
def prepend[U >: T](newHead: U): List[U] = new List(newHead, this)
override def toString = "" + head
}
打印输出:
7、逆变测试
原因:对于Person3[Any] 和 Person3[String] 这两个父子类型来说
def test(x:Any){}
def test(x:String){}
由于+A协变,所以Person3[Any]是Person3[String]的父类,因此
val pAny = new Person3[AnyRef]
val pString = new Person3[String]
pAny.test(123) 合法
pAny = pString 合法
但是, pAny.test(123) 不合法
代码实现:
package org.apache.scala.day07
/**
* 逆变测试
*/
object NibianTest {
def main(args: Array[String]): Unit = {
}
}
//声明逆变,不报错
class Person2[-A] {
def test(x: A) {}
}
//声明协变,但会报错
/*class Person3[+A] {
def test(x: A) {}
}*/
class Person4[+A] {
def test[R >: A](x: R) {}
}
在Scala中,我们知道T是泛型,不确定是什么类型,所以不能确定T类型中,是否一定包含compareTo方法, 所以编译报错。
Comparable 接口 compareTo
T <: Comparable[T] 语法结构:
表示将来传入进行的泛型的类型:T 必须是Comparable继承体系中的任何一员
T <: Comparable[T] 只认T是Comparable的子类
T <% Comparable[T] 除了会认识子类之外,还认识由其他的类隐式转换够来的类
- 如果要从集合中读取类型T的数据,并且不能写入:
可以使用 ? extends 通配符;(Producer Extends)
- 如果要从集合中写入类型T的数据,并且不需要读取
可以使用 ? super 通配符;(Consumer Super)
- 如果既要存又要取
那么就不要使用任何通配符
代码实现:
package org.apache.java.day04;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class GenericTypeTest5 {
public static void main(String[] args) {
// 带有extends子类型限定的通配符可以向泛型对象读取。
List<? extends Season> seasonList = new LinkedList<>();
// seasonList.add(new Spring());
// seasonList.add(new Summer());
Season season = seasonList.get(0);
Spring spring = (Spring) seasonList.get(1);
// 带有super超类型限定的通配符可以向泛型对象中写入
List<? super D> seasonList2 = new ArrayList<>();
// seasonList2.add(new A());
// seasonList2.add(new B());
// seasonList2.add(new C());
}
}
class A {
}
class B extends A {
}
class C extends B {
}
class D extends C {
}
class Season {
}
class Spring extends Season {
}
class Summer extends Season {
}
class Demo<E> {
public void extendsTest(List<? extends E> list) {
System.out.println("extendsTest ok");
}
public void superTest(List<? super E> list) {
System.out.println("superTest ok");
}
}
打印输出: