泛型 泛型定義 Scala的泛型和Java中的泛型表達的含義都是一樣的,對處理的數據類型進行約束,但是Scala提供了更加強大的功能 scala中的泛型採用中括弧 scala中的泛型是不可變的 泛型和類型不是一個層面的東西 所以scala中泛型和類型無法聯合使用 泛型語法 如果能將類型和泛型當成一個 ...
泛型
泛型定義
Scala的泛型和Java中的泛型表達的含義都是一樣的,對處理的數據類型進行約束,但是Scala提供了更加強大的功能
-
scala中的泛型採用中括弧
-
scala中的泛型是不可變的
-
泛型和類型不是一個層面的東西
所以scala中泛型和類型無法聯合使用
泛型語法
如果能將類型和泛型當成一個整體來使用的話,那不就方便了嗎?
-
如果將類型和泛型聯合使用,那麼類型相同時,如果泛型存在父子類關係,那麼聯合的類型也就存在父子類關係,這個操作其實就是一種變化,稱之為協變, +T
-
如果類型相同,泛型之間存在父子關係,那麼讓聯合後的類型存在子父關係。這個操作其實也是一種變化,稱之為逆變, -T
val message1 : Message[Child] = new Message[Child]()
val message2 : Message[Child] = new Message[Parent]()
//val message3 : Message[Child] = new Message[SubChild]() -- 不符合新的父子關係
// Child(父) -> child -> SubChild(子)
// MessageChild(子) MessageSubChild(父)
// Child(子) Parent(父)
// MessageChild(父) MessageParent(子)
class Message[-T] {}
class Parent {}
class Child extends Parent {}
class SubChild extends Child {}
泛型和類型的區別
- 所謂的類型,其實就是對外部的數據做約束
- 所謂的泛型,其實就是對內部的數據做約束
泛型特征
-
泛型和類型的層次不一樣。不能作為整體來考慮
-
泛型在某些場合中,其實就是類型參數,用於向類中傳遞參數
Test<User> userTest = new Test<User>(); final User t = userTest.t; Test userTest1 = new Test(); final Object t1 = userTest1.t;
-
泛型其實只在編譯時有效, 將這個操作稱之為"泛型擦除"
Test<User> userTest = new Test<User>(); userTest.t = new Emp(); //--> error System.out.println(userTest);
-
泛型主要目的是為了約束內部數據的類型
List list = new ArrayList(); list.add(new Emp()); List<User> userList = list; // System.out.println(userList); for ( User user : userList ) {}
-
泛型和類型不是一個層次,泛型沒有所謂的父子關係
public static void main(String[] args) { List<String> stringList = new ArrayList<String>(); test(stringList); //--> error List<Object> stringList1 = new ArrayList<Object>(); test(stringList1); } public static void test( Collection<Object> list ) { System.out.println(list); }
-
泛型的不可變
public static void main(String[] args) { // TODO 6. 泛型的不可變 List<Child> childList = new ArrayList<Child>(); //--> error List<Child> childList1 = new ArrayList<Parent>(); //--> error List<Child> childList2 = new ArrayList<SubChild>(); } } class Parent { } class Child extends Parent { } class SubChild extends Child { }
-
為了使用方便,可以定義泛型的邊界
public static void main(String[] args) { Producer<Child> p = new Producer<Child>(); p.produce(new Message<Child>()); p.produce(new Message<Parent>()); p.produce(new Message<SubChild>()); //--> error Consumer<Child> c = new Consumer<Child>(); final Message<? extends Child> message = c.getMessage(); final Child data = message.data; } class Message<T> { public T data; } // 分別給消費者和生產者設置上限與下限 class Producer<A> { public void produce( Message<? super A> message ) { } } class Consumer<B> { public Message<? extends B> getMessage() { return null; } }
泛型的上限與下限
Scala的泛型可以根據功能設定類樹的邊界
這裡的上限和下限採用的是顏文字
def main(args: Array[String]): Unit = {
val p = new Producer[Child]
p.produce(new Message[Child])
p.produce(new Message[Parent])
p.produce(new Message[SubChild]) // --> error
val c = new Consumer[Child]
val m: Message[_ <: Child] = c.consume()
val data: Child = m.data
}
class Message[T] {
var data : T = _
}
class Parent {}
class Child extends Parent {}
class SubChild extends Child {}
// 設置上限與下限
class Producer[T] {
def produce( message : Message[_ >: T] ): Unit = {
}
}
class Consumer[T] {
def consume(): Message[_ <: T] = {
null
}
}
集合的泛型
使用時需甄別源碼 看是否有上限下限
def main(args: Array[String]): Unit = {
val list : List[Child] = List(
new Child(), new Child(), new Child()
)
// 集合中函數要遵守繼承
list.fold[Parent](new Parent)(
(x,y) => x
)
// 但left不需要考慮繼承
list.foldLeft[SubChild](new SubChild)((x, y) => x)
}
class Parent {}
class Child extends Parent {}
class SubChild extends Child {}
上下文限定
上下文限定是將泛型和隱式轉換的結合產物,以下兩者功能相同,使用上下文限定[A : Ordering]之後,方法內無法使用隱式參數名調用隱式參數,需要通過implicitly[Ordering[A]]獲取隱式變數,如果此時無法查找到對應類型的隱式變數,會發生出錯誤。
object ScalaGeneric {
def main(args: Array[String]): Unit = {
def f[A : Test](a: A) = println(a)
implicit val test : Test[User] = new Test[User]
f( new User() )
}
class Test[T] {
}
class Parent {
}
class User extends Parent{
}
class SubUser extends User {
}
}