scala object 轉Class Scala強制 類型轉換


scala object 轉Class Scala強制類型轉換

 

asInstanceOf[T]

 

  將對象類型強制轉換為T類型。

  還是由於泛型存在類型擦除的原因,1.asInstanceOf[String]在運行時會拋出ClassCastException異常,而List(1).asInstanceOf[List[String]]將不會。

 

 

package resti.web import org.springframework.beans.factory.annotation.Autowiredimport org.springframework.security.core.context.SecurityContextHolderimport org.springframework.stereotype.Controllerimport org.springframework.ui.Modelimport org.springframework.web.bind.annotation.RequestMappingimport resti.domain.HttpApiimport resti.service.HttpApiRepositoryimport org.springframework.security.core.userdetails.UserDetailsimport org.springframework.web.bind.annotation.RequestMethod @Controller@RequestMapping(Array("/product"))class ProductController @Autowired() (private val httpApiRepository: HttpApiRepository) {   @RequestMapping(method = Array(RequestMethod.GET))  def list(model: Model) = {    // get current user    val userDetails = SecurityContextHolder.getContext().getAuthentication().getPrincipal().asInstanceOf[UserDetails]    model.addAttribute("currentUser", userDetails.getUsername)        model.addAttribute("products", httpApiRepository.findProducts())    "product/list"  } 

 

 

 

 

classOf、isInstanceOf、asInstanceOf三個預定義方法分析

  Scala的三個預定義(predefined)方法,我們經常用到;它們用來感覺很簡單, 但是里面還是隱藏了一些細節東西,不妨花點時間來分析分析。

先上代碼

  PredefineTest.scala

 

Scala代碼  收藏代碼
  1. object PredefineTest{  
  2.   def main(args: Array[String]):Unit = {  
  3.     val c : Char = 97.asInstanceOf[Char]  
  4.     "hello".asInstanceOf[String]  
  5.     1.asInstanceOf[Long]  
  6.     val it: Seq[String] = List("a", "b")  
  7.     it.asInstanceOf[List[String]]  
  8.   
  9.     "hello".isInstanceOf[String]  
  10.   
  11.     classOf[String]  
  12.   }  
  13. }  
 

 

  使用scalac -Xprint:cleanup PredefineTest.scala,Scala編譯器輸出的main方法體內代碼的抽象語法樹(AST)信息如下:

 

Scala代碼  收藏代碼
  1. val c: Char = 97.toChar();  
  2. ("hello": java.lang.String);  
  3. 1.toLong();  
  4. val it: Seq = immutable.this.List.apply(scala.this.Predef.wrapRefArray(Array[java.lang.String]{"a", "b"}.$asInstanceOf[Array[java.lang.Object]]()));  
  5. it.$asInstanceOf[List]();  
  6. "hello".$isInstanceOf[java.lang.String]();  
  7. {  
  8.   classOf[java.lang.String];  
  9.   ()  
  10. }  
 

 

  使用jd反編譯工具查看對應代碼如下:

 

Java代碼  收藏代碼
  1. char c = (char)97;  
  2. "hello";  
  3. 1;  
  4. Seq it = List..MODULE$.apply(Predef..MODULE$.wrapRefArray((Object[])new String[] { "a", "b" }));  
  5. ((List)it);  
  6.   
  7. ("hello" instanceof String);  
  8. String.class;  

 

結合上面源碼來進行分析

classOf[T]

 

  獲取類型T的Class對象

  classOf方法定義在scala.Predef object:

 

Scala代碼  收藏代碼
  1. object Predef extends LowPriorityImplicits {  
  2.         
  3.       def classOf[T]: Class[T] = null  
  4.     ...  

  classOf的注釋翻譯過來的意思是:返回類型的運行時呈現狀態。這是一個存根方法。實際的實現是由編譯器填補(自動生成)

 

  Predef object是默認導入的,所以classOf方法相當於一個全局方法

 

 

isInstanceOf[T]

 

  判斷對象是否為T類型的實例。

 

  isInstanceOf和asInstanceOf 由scala.Any類定義,Scala類層級的根類;其中class scala.AnyRef 繼承自Any,是所有應引用類型的基類;trait scala.AnyVal 也繼承自Any,是所有基本類型的實現的trait。所以所有對象都自動擁有isInstanceOf和asInstanceOf這兩個方法

  特別注意的是 Any 和AnyRef 這兩個類屬於“編譯時類型”(虛擬類型?),不存在於運行時。所以這兩者在Scala中都未提供源碼,其語義由編譯器在編譯時構建。

 

  再看一下例子:

Scala代碼  收藏代碼
  1. scala> 1.isInstanceOf[String]  
  2. res0: false  
  3.   
  4. scala> List(1).isInstanceOf[List[String]]  
  5. res0: true  

 

  由於Scala像Java一樣泛型存在類型擦除的原因,List(1).isInstanceOf[List[String]]及相當於List(1).isInstanceOf[List[_]], List(1) 是List的實例.

 

asInstanceOf[T]

 

  將對象類型強制轉換為T類型。

  還是由於泛型存在類型擦除的原因,1.asInstanceOf[String]在運行時會拋出ClassCastException異常,而List(1).asInstanceOf[List[String]]將不會。

  在scala 討論組里有人問道這樣一個問題

 

”I expect "new AnyRef().isInstanceOf[AnyVal]" to be false, but I get true instead“
scala> new AnyRef().isInstanceOf[AnyVal]
res0: Boolean = true

 

  大家有興趣看以看看后面的解答,不過試了scala 2.9, 這種用法 已經被編譯器禁止了:

 

scala> new AnyRef().isInstanceOf[AnyVal]
<console>:8: error: type AnyVal cannot be used in a type pattern or isInstanceOf test
new AnyRef().isInstanceOf[AnyVal]

 

  還有,值得提一下的一個小細節就是,通過觀察編譯輸出的AST,  知道對於在基本類型如Int等的對象上調用asInstanceOf[T], Scala會將其轉換為調用相應的toT方法, 如 1.asInstanceOf[Char], 就會轉換為 97.toChar, 其中toChar 定義在 scala.Int:

 

Scala代碼  收藏代碼
  1. final class Int extends AnyVal {  
  2.   ...  
  3.   def toChar: Char = sys.error("stub")  
  4.   ...  
  5. }  

 

  而后, Scala編譯器會進一步將其編譯成與“(char)97”相同的字節碼。

 

結論

  總而言之,我們把classOf[T]看成Java里的T.class, obj.isInstanceOf[T]看成 obj instanceof T, obj.asInstanceOf[T]看成(T)obj就對了。scala為我們提供了語法糖,但也免不了類型擦除問題的影響。

 

值得探討的地方

  個人感覺,Scala對Java的類這一塊沒什么增強, 比如像Ruby一樣類文字量也是對象(雖然理解起來有點繞,但是更能體現面向對象一致性),就不用classOf[T]這樣添足的寫法,而是:object.getClass == String 。如此,是不是JVM的限制,還是Scala目前的關注點不在此?

 

原文地址:http://blog.sina.com.cn/s/blog_7d553bb50102wa7h.html

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com