2015-12-10 27 views
8

Tôi đã cố gắng trả lời câu hỏi this, như tôi nghĩ tôi biết câu trả lời. Hóa ra, tôi không biết khá đủ:/Tại sao `.asInstanceOf` đôi khi ném, và đôi khi không?

Dưới đây là một thử nghiệm tôi đã thực hiện:

class Inst[T] { 
    def is(x: Any) = scala.util.Try { as(x) }.isSuccess 
    def as(x: Any): T = x.asInstanceOf[T] 
} 

scala> new Inst[String].is(3) 
res17: Boolean = true 

scala> new Inst[String].as(3) 
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String 
... 33 elided 

gì đang xảy ra ở đây? Tại sao chỉ cuộc gọi thứ hai đến số as ném, nhưng không phải cuộc gọi đầu tiên?

Trả lời

10

Điều này là do lớp học-cast-exception chỉ được ném khi bạn làm điều gì đó với giá trị, gọi một phương thức trên nó sau khi diễn viên. Trong ví dụ REPL, bạn sẽ có một cuộc gọi toString trong trường hợp thứ hai. Lưu ý:

new Inst[String].as(3);()   // nothing happens 
new Inst[String].as(3).toString;() // exception 

Lý do tại sao điều này có bước thêm là Inst[T] là generic với kiểu tham số T được xoá hoàn toàn trong thời gian chạy; chỉ khi trang web gọi (có kiến ​​thức tĩnh về loại T) cố gọi phương thức trên kết quả, kiểm tra loại thực tế xảy ra.


Đối với câu hỏi tiếp theo của bạn, toString được định nghĩa trên bất kỳ đối tượng và kể từ T là chung chung bạn có một số nguyên đóng hộp (<: AnyRef) và toStringprintln thành công trong phương pháp is. Vì vậy, một ví dụ khác nơi Try sẽ thất bại là thế này:

class Inst[T] { 
    def foo(x: Any)(implicit ev: T <:< String) = scala.util.Try { 
    ev(as(x)).reverse 
    }.isSuccess 
} 

new Inst[String].foo(3) // false! 
+0

Không, đây dường như không để giải thích nhiều: tôi đã thay đổi định nghĩa 'is' thành:' def là (x: Any) = scala.util.Try {as (x) .toString} .isSuccess', và nó vẫn trả về 'true' (nghĩa là, cast không ném). Thậm chí này 'def là (x: Bất kỳ) = scala.util.Try {println (như (x) ToString)} .isSuccess;' hạnh phúc in ra "3" và trả về true: -/ – Dima

+0

Xin xem chỉnh sửa của tôi –

+0

Ah, bây giờ nó có ý nghĩa, cảm ơn! 'is' không biết' T' là gì, vì vậy nó xử lý đối số là 'Bất kỳ'. Tôi đã thử điều này: 'trait Foo {def foo = ??? } lớp Inst [T <: Foo] {def là (x: Any) = scala.util.Thử {as (x) .foo} .isSuccess; def as (x: Any): T = x.asInstanceOf [T]; } '. Bây giờ 'mới Inst [Foo] .is (3)' trả về 'false' như mong đợi. – Dima

2

Trong khi @ 0 __ 's câu trả lời giải thích lý do tại sao nó không hoạt động, đây là cách để làm cho nó làm việc:

class Inst[T](implicit tag: scala.reflect.ClassTag[T]) { 
    def is(x: Any) = tag.runtimeClass.isInstance(x) 
    // scala.util.Try { as(x) }.isSuccess will work as well 
    def as(x: Any): T = tag.runtimeClass.cast(x).asInstanceOf[T] 
} 

object Main extends App { 
    println(new Inst[String].is(3)) 
    println(new Inst[String].as(3)) 
} 


false 
java.lang.ClassCastException: Cannot cast java.lang.Integer to java.lang.String 
    at java.lang.Class.cast(Class.java:3369) 
... 
Các vấn đề liên quan