泛型
泛型相关类
ClassTag
这个类就是泛型类的类型。
泛型类在实例化的时候一定要具体指名泛型类型,泛型在编译的时候信息是抹去的,就会存在以下问题:
def mkArray[T](elem:T*) = Array[T](elem:_*)//编译阶段会报错
上面这句在编译的时候是报错的,因为Array[T]没有指定类型,但是我们有时候要这么写代码怎么办呢?这时候就要用到ClassTag,ClassTag会在编译阶段将泛型的信息保存下来:
def mkArray[
T
:ClassTag](elem:
T*) =
Array[
T](elem:_*)
以上这样定义就没有问题
Manifest
这个类很少用。现在知道的用法和上面的相似
|
>: 和 <:
以上两个符号用来界定泛类型的上下界:
//定义了泛类型的上界(父类)
class Pair[ T <: Comparable[ T]]( val first: T, val second: T){ def bigger = if(first.compareTo(second) > 0) first else second } class Pair_Lower_Bound[ T]( val first: T, val second: T){ //定义了泛类型的下界(子类) def replaceFirst[ R >: T](newFirst: R) = new Pair_Lower_Bound[ R](newFirst,second) } object Type_Variables_Bounds { def main(args: Array[ String]) { val pair = new Pair( "Spark", "Hadoop") println(pair.bigger) }
}
|
<% 和 >%
以上两个符号称作视图界定
//class Pair_NotPerfect[T <: Comparable[T]](val first:T,val second:T){
// def bigger = if(first.compareTo(second) > 0) first else second //} class Pair_NotPerfect[ T <% Comparable[ T]]( val first: T, val second: T){ def bigger = if(first.compareTo(second) > 0) first else second } object View_Bounds {
def main(args: Array[String]) {
val pair = new Pair_NotPerfect(2,3) //Int -> RichInt
println(pair.bigger)
}
}
注意:要是黄底的部分没有注释掉,使用黄底部分的定义的话,下面黄底的部分是会报错的。因为Int类型并没有实现Comparable,但是使用<%后就会正确了,因为使用试图界定会将隐式转换传进来,如果隐式转换有几成Comparable就行了,就像这里的Int转成RichInt了。
|
<:<
以下两段代码的作用基本相同:
def
rocky[T](i:T)(implicit en:T<:<java.io.Serializable): Unit ={
println( "aaaaa!!!!") } def rocky[T<:java.io.Serializable](i:T): Unit ={ println( "aaaaa!!!!")
}
|
+T 和 -T
协变和逆变,
协变:就是E是T的子类型那么A[E]是A[T]的子类型
逆变:就是E是T的子类型那么A[T]是A[E]的子类型
class Person
class Student extends Person class C[ +T]( val arg: T) trait Friend[ -T]{ def makeFriend(somebody: T) } object Vaniance { def makeFriendWithYou(s:Student,f:Friend[Student]): Unit ={ f.makeFriend(s) } def main(args: Array[ String]) { val value :C[Person] = new C[Student](new Student)
}
}
注意一下:java不能再泛型定义的时候界定协变和逆变,但是可以在使用的时候界定:
// List<? extends Object> list = new ArrayList<String>()
val list:
List[_<:Any] =
List[
String]()
注销掉的是java的代码,和下面没有注释的scala代码同义
|
单例类型v.type:
this.type的使用:
注意以下区别:
class Animal {def breathe = this}
class Cat extends Animal {def eat = this}
object Singleton_Types {
def main(args: Array[ String]) {
val cat = new Cat
cat.breathe .eat //这里报错了,因为breathe返回的类型是Animal,Animal中没有定义eat
}
class Cat extends Animal {def eat = this}
object Singleton_Types {
def main(args: Array[ String]) {
val cat = new Cat
cat.breathe .eat //这里报错了,因为breathe返回的类型是Animal,Animal中没有定义eat
}
}
解决以上问题,使用以下代码:
class Animal {def breathe:this.type = this}
class Cat extends Animal {def eat:this.type = this}
object Singleton_Types {
def main(args: Array[ String]) {
val cat = new Cat
cat.breathe. eat
}
class Cat extends Animal {def eat:this.type = this}
object Singleton_Types {
def main(args: Array[ String]) {
val cat = new Cat
cat.breathe. eat
}
}
类型投影:
类型投影就是类中的类:
class Outer {
private val x = 10
class Inner {
private val y = x + 10
}
private val x = 10
class Inner {
private val y = x + 10
}
}
投影类型会有一个路径问题,还是使用上面定义的代码:
val outer1 =
new Outer
val outer2 = new Outer
var inner = new outer1.Inner
val outer2 = new Outer
var inner = new outer1.Inner
inner = new outer2.Inner //outer1.Inner和outer2.Inner不是同一个类型
标红的地方报错,因为outer1.Inner和outer2.Inner由于路径不同,并不是同一个类型。可以用Outer#Inner解决这个问题。
val o1 =
new Outer
val o2 = new Outer
val o2 = new Outer
var i: Outer#Inner = new o1.Inner //前面用的Outer#Inner表示任何Outer的Inner
i =
new o2.Inner
结构类型:
type关键字:
用法一:
type
str =
String
var a: str = _ a = "aaaa"
就是个类型加一个别名。
|
用法二:
class Structuralclass {
def open() =
println(
"A class instance Opened!!!")}
object Structural_Type { def main(args: Array[ String]) { type X = { def open():Unit} def init(rec: X) = rec.open() //带open()方法的class init( new Structuralclass) //带open()方法的object object A { def open() = println( "A single object Opened!!")} init(A) //使用匿名类 init( new { def open() = println( "Opened again!!!")}) }
}
这个用法的好处就是,我可以将所有含有open()方法的类型都传给init(),各个类型之间不需要有任何继承关系
|
中置类型:
带两个值得泛型类可以使用中置表达式:
例子:
class Infix_Type[
A,
B]
val infix: Int Infix_Type String = null
val infix: Int Infix_Type String = null
val infix1: Infix_Type[Int, String] = null
上面2,3两行代码的作用是相同的,可以看到黄底的地方使用了中值表达式。
自身类型:
这里有两种用法
设置this的别名:
class Self {
self => //这一行的意思是定义self为this的别名 val tmp= "Scala" def foo = self. tmp + this. tmp
}
这么做在使用内部类调用外部类的时候就会很方便:
class Outer { outer =>
val v1 = "Spark" class Inner { println(outer. v1) }
}
|
限制类型可以混入的特质:
看以下代码:
trait Logged{
def log(msg: String) } trait LoggedException extends Logged{ this: Exception=> //只能混入Exception的子类 def logException(){ log(getMessage()) //这里使用到的getMessage()方法是Exception中的方法 }
}
这个时候我们需要混入LoggedException特质,如果使用以下代码会报错:
val ex =
new JFrame(
"ClassNotFoundException")
with
LoggedException{
override def log(msg: String): Unit = println(msg)
}
因为JFrame不是Exception的子类,不能混入LoggedException,只有Exception的子类才能混入,例如下面这样:
Exception的子类
val ex =
new ClassNotFoundException(
"ClassNotFoundException")
with LoggedException{
override def log(msg: String): Unit = println(msg) } |