Tôi đang cố gắng để hiểu mục đích của reified
từ khóa, rõ ràng nó cho phép chúng tôi phản ánh về khái quát .
Tuy nhiên, khi tôi bỏ nó ra thì nó hoạt động tốt như vậy. Bất cứ ai quan tâm để giải thích khi điều này làm cho một sự khác biệt thực sự ?
Tôi đang cố gắng để hiểu mục đích của reified
từ khóa, rõ ràng nó cho phép chúng tôi phản ánh về khái quát .
Tuy nhiên, khi tôi bỏ nó ra thì nó hoạt động tốt như vậy. Bất cứ ai quan tâm để giải thích khi điều này làm cho một sự khác biệt thực sự ?
Câu trả lời:
reified
tốt chofun <T> myGenericFun(c: Class<T>)
Trong phần thân của một hàm chung như myGenericFun
, bạn không thể truy cập loại T
vì nó chỉ khả dụng khi biên dịch nhưng bị xóa khi chạy. Do đó, nếu bạn muốn sử dụng kiểu chung như một lớp bình thường trong thân hàm, bạn cần phải vượt qua lớp một cách rõ ràng như một tham số như trong hình myGenericFun
.
Nếu bạn tạo một inline
chức năng với một reified T
tuy nhiên, loại T
có thể được truy cập ngay cả trong thời gian chạy và do đó bạn không cần phải vượt qua Class<T>
thêm. Bạn có thể làm việc với T
nó như thể đó là một lớp bình thường, ví dụ bạn có thể muốn kiểm tra xem một biến có phải là một thể hiện hay không T
, điều mà bạn có thể dễ dàng thực hiện sau đó : myVar is T
.
Thật là inline
hàm có reified
kiểu T
như sau:
inline fun <reified T> myGenericFun()
reified
làm việcBạn chỉ có thể sử dụng reified
kết hợp với một inline
chức năng . Hàm này làm cho trình biên dịch sao chép mã byte của hàm đến mọi nơi mà hàm đang được sử dụng (hàm đang được "nội tuyến"). Khi bạn gọi một hàm nội tuyến với kiểu hợp nhất, trình biên dịch sẽ biết loại thực tế được sử dụng làm đối số kiểu và sửa đổi mã byte được tạo để sử dụng trực tiếp lớp tương ứng. Do đó, các cuộc gọi như myVar is T
trở thành myVar is String
(nếu đối số kiểu là String
) trong mã byte và tại thời gian chạy.
Chúng ta hãy xem một ví dụ cho thấy mức độ hữu ích reified
có thể. Chúng tôi muốn tạo một chức năng mở rộng choString
được gọi là toKotlinObject
cố gắng chuyển đổi một chuỗi JSON thành một đối tượng Kotlin đơn giản với một loại được chỉ định bởi loại chung của hàm T
. Chúng ta có thể sử dụng com.fasterxml.jackson.module.kotlin
cho điều này và cách tiếp cận đầu tiên là như sau:
a) Cách tiếp cận đầu tiên mà không có loại thống nhất
fun <T> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
//does not compile!
return mapper.readValue(this, T::class.java)
}
Các readValue
phương pháp có một loại mà nó phải phân tích JsonObject
để. Nếu chúng ta cố gắng để có được Class
tham số loạiT
, trình biên dịch sẽ phàn nàn: "Không thể sử dụng 'T' làm tham số loại hợp nhất. Thay vào đó, hãy sử dụng một lớp."
b) Giải pháp rõ ràng Class
tham số
fun <T: Any> String.toKotlinObject(c: KClass<T>): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, c.java)
}
Như một giải pháp thay thế, Class
of T
có thể được tạo thành một tham số phương thức, sau đó được sử dụng làm đối số choreadValue
. Điều này hoạt động và là một mẫu phổ biến trong mã Java chung. Nó có thể được gọi như sau:
data class MyJsonType(val name: String)
val json = """{"name":"example"}"""
json.toKotlinObject(MyJsonType::class)
c) Cách thức của Kotlin: reified
Sử dụng một inline
hàm với reified
tham số kiểu T
cho phép thực hiện hàm khác nhau:
inline fun <reified T: Any> String.toKotlinObject(): T {
val mapper = jacksonObjectMapper()
return mapper.readValue(this, T::class.java)
}
Không cần để có những Class
số T
thêm vào đó, T
có thể được sử dụng như thể nó là một lớp học bình thường. Đối với khách hàng, mã trông như thế này:
json.toKotlinObject<MyJsonType>()
Một hàm nội tuyến với reified
kiểu không thể gọi được từ mã Java .
ĐƠN GIẢN
* thống nhất là cho phép sử dụng tại thời điểm biên dịch (để truy cập T bên trong chức năng de)
ví dụ:
inline fun <reified T:Any> String.convertToObject(): T{
val gson = Gson()
return gson.fromJson(this,T::class.java)
}
sử dụng như:
val jsonStringResponse = "{"name":"bruno" , "age":"14" , "world":"mars"}"
val userObject = jsonStringResponse.convertToObject<User>()
println(user.name)