scala-泛型

1.泛型方法

1
2
3
4
5
6
7
8
9
10
11
12
13
// 泛型-意思是指某种具体的数据类型
// 方式1:不采用泛型,即:普通的方法
def getMiddleElement(arr: Array[Int]): Int = arr(arr.length / 2)
// 方式二:采用自定义的泛型方法来实现
// T就是type单词的缩写
def getMiddleElement1[T](arr: Array[T]) = arr(arr.length / 2)

// 泛型-意思是指某种具体的数据类型
// 测试getMiddleElement()方法
println(getMiddleElement(Array(1, 2, 3, 4, 5)))
println(getMiddleElement(Array("hkjcpdd", "hkjmjj", "hkjljj")))
println(getMiddleElement1(Array(1, 2, 3, 4, 5)))
println(getMiddleElement1(Array("hkjcpdd", "hkjmjj", "hkjljj")))

2.泛型类

1
2
3
4
5
6
7
8
9
10
// 泛型类
// 定义一个Pair泛型类,该类包含两个字段,且两个字段的类型不固定
class Pair[T](val message: T) {
println(message)
}

// 泛型类
// 创建不同类型的Pair泛型类对象,并打印
new Pair[Int](1234)
new Pair[String]("hkjcpdd")

3.泛型特质

1
2
3
4
5
6
7
8
9
10
11
12
// 泛型特质
trait Logger[T] {
val a: T
def show() = println(a)
}
object ConsoleLogger extends Logger[String] {
override val a: String = "hkjcpdd"
}


// 泛型特质
ConsoleLogger.show()

4.泛型上下界之上界

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
使用t < 类型名表示给类型添加一个上界,表示泛型参数必须从该列(或本身)继承.
格式:
[T <: 类型]
例如:[T <: Person]的意思是,泛型T的数据类型必须是Person类型或者Person的子类型

// 上界 上界是包子不包父
// 1.定义一个Person类
abstract class Person {
val name: String
val age: Int
}
// 2. 定义一个Student类,继承Person类
class Student extends Person {
override val name: String = "hkjcpdd"
override val age: Int = 12
}
// 3. 定义一个泛型方法demo(),该方法接受一个Array参数
// 4.限定Demo方法的Array元素类型只能是Person或者Person的子类
def demo[T <: Person](array: Array[T]): Unit = println(array)

// 上界
val s1 = new Student()
demo(Array(s1))

5.泛型上下界之下界

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
使用T >: 数据类型 表示给类型添加一个下界,表示泛型参数必须是从类型本身或该类型的父类型.
格式:
[T >: 类型]
注意:
1.例如:[T >: Person]的意思是,泛型T的数据烈性必须是Person类型或者Person的父类型
2.如果泛型既有上界又有下界。下界写在前面,上界写在后面,即:[T >:类型1 < 类型2]
// 下界
// 1.定义一个Person类
abstract class Person1 {
val name: String
val age: Int
}
// 2. 定义一个Policeman类,继承Person类
class Policeman extends Person1 {
override val name: String = "hkjmjj"
override val age: Int = 14
}
// 3.定义一个Superman类,继承Policeman类
class Superman extends Policeman
// 4.定义一个demo泛型方法,该方法接受一个Array参数
def demo1[T >: Policeman](arr: Array[T]) = println(arr)
// 5.测试调用demo,传入不同元素类型的Array

// 下界
demo1(Array(new Policeman))
// 以下就不可以了,因为设置了下界,下界包父不包子
// demo1(Array(new Superman))

6.泛型注意点

[!NOTE]

如果泛型既有上界又有下界。下界写在前面,上界写在后面,即:[T >:类型1 < 类型2]

如果是同一个同事设置了上下界,其实就是直接固定类型,和直接在里面写类型没区别

7.协变、逆变、非变

[!IMPORTANT]

  • 非变:类A和类B之间是父子类关系,但是Pair[A]和Pair[B]之间没有任何关系.
  • 协变:类A和类B之间是父子类关系,Pair[A]和Pair[B]之间也有父子类关系.
  • 逆变:类A和类B之间是父子类关系,但是Pair[A]和Pair[B]之间是子父关系.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 1.定义一个Super类、以及一个Sub类继承自Super类
class Super // 父类
class Sub extends Super
// 2.使用协变、逆变、非变分别定义三个泛型类
// 非变
class Temp1[T]
// 协变
class Temp2[+T]
// 逆变
class Temp3[-T]

// 3. 分别创建泛型类对象来掩饰协、逆变、非变
// 3.1测试非变
val t1: Temp1[Sub] = new Temp1[Sub]
val t2: Temp1[Super] = t1 // 编译报错,因为是非变,super和Sub有父子类关系,但是Temp1[Super]和Temp1[Sub]无关系
// 3.2测试协变
val t3:Temp2[Sub] = new Temp2[Sub]
val t4:Temp2[Super] = t3 // 协变,super和Sub有父子类关系,但是Temp2[Super]和Temp2[Sub]有父子类关系
// 3.3测试逆变
val t5: Temp3[Sub] = new Temp3[Sub]
val t6: Temp3[Super] = t5 // 编译报错,逆变是,super和Sub有父子类关系,但是Temp3[Super]和Temp3[Sub]变成子父类关系
val t7: Temp3[Super] = new Temp3[Super]
val t8: Temp3[Sub] = t7 // 逆变,不会报错,子父类

8.案例:列表去重排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 案例:列表去重排序
// 一直当前项目下的data文件夹有一个1.txt文本文件
// 对上述数据去重排序后,重新写入到data文件夹下的2.txt文本文件中
// 1.定义数据源对象,关联数据源文件
val source = Source.fromFile("J:\\大数据第一代项目\\scalaFlink\\data\\123.txt")
// 2.从指定的文件中读取所有的对象
val list1 = source.mkString.split("\\s+").toList
// 所有的数据 -> 按照空白字符切割,Array("", ""...)
// println(list1)
// 3. 把List[String] -> List[Int]
val list2: List[Int] = list1.map(_.toInt)
// 4. 把List[Int] -> Set[Int], 对列表元素去重
val set1: Set[Int] = list2.toSet
// 5. Set[Int] -> List[Int], 然后升序排列.
val list3: List[Int] = set1.toList.sorted
// 6. 把所有的数据写入到指定的目的地文件中
// 6.1 创建字符缓冲流,用来写入数据到自定的目的地文件中.
val bw = new BufferedWriter(new FileWriter("J:\\大数据第一代项目\\scalaFlink\\data\\123456.txt"))
// 6.2 遍历list3列表,获取每一个数字
for (i <- list3) {
// i 就表示列表中的每一个
// 6.3 将获取到的数字转换成字符串在写入
bw.write(i.toString)
// 6.4 记得加换行
bw.newLine()
}
// 7. 释放资源.
bw.close()