1. 程式人生 > >Scala入門到精通——第十六節 泛型與註解

Scala入門到精通——第十六節 泛型與註解

本節主要內容

  1. 泛型(Generic Type)簡介
  2. 註解(Annotation)簡介
  3. 註解常用場景

1. 泛型(Generic Type)簡介

泛型用於指定方法或類可以接受任意型別引數,引數在實際使用時才被確定,泛型可以有效地增強程式的適用性,使用泛型可以使得類或方法具有更強的通用性。泛型的典型應用場景是集合及集合中的方法引數,可以說同java一樣,scala中泛型無處不在,具體可以檢視scala的api

1 泛型類

//單個泛型引數的使用情況
class Person[T](var name:T)

class Student[T](name:T) extends Person
(name)
object GenericDemo { def main(args: Array[String]): Unit = { println(new Student[String]("搖擺少年夢").name) } }

多個泛型引數的使用情況:

class Person[T](var name:T)

class Student[T,S](name:T,var age:S) extends Person(name)

object GenericDemo {
  def main(args: Array[String]): Unit = {
    println(new
Student[String,Int]("搖擺少年夢",18).name) } }
D:\ScalaWorkspace\ScalaChapter16\bin\cn\scala\xtwy>javap -private Person.class
Compiled from "GenericDemo.scala"
public class cn.scala.xtwy.Person<T> {
  private T name;
  public T name();
  public void name_$eq(T);
  public cn.scala.xtwy.Person
(T); } D:\ScalaWorkspace\ScalaChapter16\bin\cn\scala\xtwy>javap -private Student.class Compiled from "GenericDemo.scala" public class cn.scala.xtwy.Student<T, S> extends cn.scala.xtwy.Person<T> { private S age; public S age(); public void age_$eq(S); public cn.scala.xtwy.Student(T, S); }

從上面的程式碼不難看出,scala泛型對應於java中的泛型,掌握了java中的泛型也就掌握了scala中的泛型

2. 註解(Annotation)簡介

Annotation是一種對程式程式碼進行描述的結構化資訊。Annotation可以分佈在程式的任何地方,能夠註解變數、類、方法、引數等多種元素,它的主要功能有以下幾種:
1 自動生成scala文件

scala.collection.immutable.HashMap類對應部分原始碼:

/** This class implements immutable maps using a hash trie.
 *
 *  '''Note:''' The builder of this hash map may return specialized representations for small maps.
 *
 *  @tparam A      the type of the keys contained in this hash map.
 *  @tparam B      the type of the values associated with the keys.
 *
 *  @author  Martin Odersky
 *  @author  Tiark Rompf
 *  @version 2.8
 *  @since   2.3
 *  @see [[http://docs.scala-lang.org/overviews/collections/concrete-immutable-collection-classes.html#hash_tries "Scala's Collection Library overview"]]
 *  section on `Hash Tries` for more information.
 *  @define Coll `immutable.HashMap`
 *  @define coll immutable hash map
 *  @define mayNotTerminateInf
 *  @define willNotTerminateInf
 */
@SerialVersionUID(2L)
class HashMap[A, +B] extends AbstractMap[A, B]
                        with Map[A, B]
                        with MapLike[A, B, HashMap[A, B]]
                        with Serializable
                        with CustomParallelizable[(A, B), ParHashMap[A, B]]
{

上述annotation生成的文件內容如下:
這裡寫圖片描述

2 檢查程式中可能出現的語法問題

//當程式使用該API時,給出相應提示,屬於語法檢查範疇
 @deprecated("Use the `merged` method instead.", "2.10.0")
  def merge[B1 >: B](that: HashMap[A, B1], mergef: MergeFunction[A, B1] = null): HashMap[A, B1] = merge0(that, 0, liftMerger(mergef))

3 規定程式行為

//@BeanProperty,要求程式生成相應getter,setter方法,與java命名規範一致
class Student[T,S](name:T,var age:S) extends Person(name)
{
  @BeanProperty var studentNo:String=null
}

當然,annotation還有其它功能,上面三種只是平時在編寫程式時最為常用的功能

annotation具有如下語法格式:

class A
class B extends A{
  //同java一樣,採用@+註解關鍵字對方法、變數
  //類等進行註解標識
  //下面的註解用於標識getName方法在未來會被丟棄
  //不推薦使用
  @deprecated def getName()="Class B"
}

object AnnotationDemo{
  def main(args: Array[String]): Unit = {
    var b=new B()
    //在呼叫的時候,編譯器出給出相應提示
    b.getName()
  }
}

3. 註解常用場景

註解的常用場景包括volatile,transient,native,SerialVersionUID,serializable5個,用於對變數或方法進行註解,其中volatile用於標識變數可能會被多個執行緒同時修改,它不是執行緒安全的;transient用於標識變數是瞬時的,它不會被持久化;native用於標識演算法來自C或C++程式碼實現



abstract class A
{ 
  //native用於標記 cplusplusMethod為c或c++中實現的本地方法
  @native def cplusplusMethod()
}

//標記B可被序列化
//註解宣告序列化版本
@SerialVersionUID(1000330L)
@serializable
class B extends A{
  //volatile註解標記變數name非執行緒安全
  @volatile var name:String="B"
  //transient註解用於標記變數age不被序列化
  @transient var age:Int=40

}

下面舉下物件序列化的例子:

//下面的程式碼編譯時不會出問題,但執行時會丟擲異常
class Person{
  var name:String="zzh"
  var age:Int=0
  override def toString()="name="+name+" age="+age
}

object Serialize {
  def main(args: Array[String]): Unit = {
     val file = new File("person.out")

        val oout = new ObjectOutputStream(new FileOutputStream(file)) 
        val person = new Person 
        oout.writeObject(person)  
        oout.close()

        val oin = new ObjectInputStream(new FileInputStream(file)) 
        val newPerson = oin.readObject()
        oin.close();  
        println(newPerson)
  }
}

Exception in thread "main" java.io.NotSerializableException: cn.scala.xtwy.serialize.Person
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at cn.scala.xtwy.serialize.Serialize$.main(Serialize.scala:22)
    at cn.scala.xtwy.serialize.Serialize.main(Serialize.scala)

此時在Person類前加@serializable則可以對物件進行正常序列化

//宣告物件可序列化
@serializable
class Person{
  var name:String="zzh"
  var age:Int=0
  override def toString()="name="+name+" age="+age
}

object Serialize {
  def main(args: Array[String]): Unit = {
     val file = new File("person.out")

        val oout = new ObjectOutputStream(new FileOutputStream(file)) 
        val person = new Person 
        oout.writeObject(person)  
        oout.close()

        val oin = new ObjectInputStream(new FileInputStream(file)) 
        val newPerson = oin.readObject()
        oin.close();  
        println(newPerson)
  }
}
//反序列化後的輸出結果為:
//name=zzh age=0

如果給成員變數加@transient註解的話,則相應的成員變數不會被序列化,此時如果進行反序列化的話,對應成員變數為null,如:

package cn.scala.xtwy.serialize

import java.io.File
import java.io.ObjectOutputStream
import java.io.FileOutputStream
import java.io.ObjectInputStream
import java.io.FileInputStream

@serializable
class Person{
  //@transient註解聲明後,成員變數不會被充列化
  @transient var name:String="zzh"
  var age:Int=0
  override def toString()="name="+name+" age="+age
}

object Serialize {
  def main(args: Array[String]): Unit = {
     val file = new File("person.out")

        val oout = new ObjectOutputStream(new FileOutputStream(file)) 
        val person = new Person 
        oout.writeObject(person)  
        oout.close()

        val oin = new ObjectInputStream(new FileInputStream(file)) 
        val newPerson = oin.readObject()
        oin.close();  
        println(newPerson)
  }
}
//反序列化後的輸出
//name=null age=0

新增公眾微訊號,可以瞭解更多最新Spark、Scala相關技術資訊
這裡寫圖片描述