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.Autowired
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.RequestMapping
import resti.domain.HttpApi
import resti.service.HttpApiRepository
import org.springframework.security.core.userdetails.UserDetails
import 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
posted @ 2017-08-24 18:26  dy9776  阅读(2052)  评论(0编辑  收藏  举报