reified là một từ khóa trong Kotlin cho phép truy cập vào kiểu tham số generic bên trong hàm inline tại thời điểm chạy. Trong generic thông thường, type erasure được áp dụng — thông tin kiểu bị xóa ở thời điểm biên dịch, nhưng reified giữ lại nó. Theo Kotlin Documentation, 2025, reified chỉ hoạt động bên trong các hàm inline vì trình biên dịch thay thế kiểu thực tế tại giai đoạn inlining.
Điểm chính
reified là một bộ sửa đổi cho tham số generic của hàm inline giúp kiểu trở nên thực tế (reify — “làm cho thực”) tại thời điểm chạy. Không có reified, kiểu T bên trong hàm generic không thể truy cập được — trình biên dịch áp dụng type erasure, xóa sạch mọi thông tin kiểu. reified buộc trình biên dịch thay thế kiểu cụ thể tại vị trí gọi, làm cho nó có thể truy cập qua T::class và toán tử is.
Theo Khảo sát Kotlin bởi Kodee (2024), các tham số kiểu reified nằm trong top mười tính năng Kotlin được yêu cầu nhiều nhất — 52% nhà phát triển được khảo sát sử dụng chúng, chủ yếu để viết các factory generic, container DI và bộ tuần tự hóa. reified đặc biệt phổ biến khi kết hợp với Gson, Moshi và Kotlinx Serialization.
Về mặt kỹ thuật, cơ chế rất đơn giản: khi gọi một hàm inline với tham số reified, trình biên dịch biết kiểu đối số cụ thể (Int, String, User) và thay thế nó cho T. Trong bytecode, tham số reified trở thành Class<T> thông thường được truyền dưới dạng đối số ẩn.
Sử dụng reified để viết các hàm generic khi cần kiểu tại thời điểm chạy — tạo thể hiện, kiểm tra kiểu, lấy Class<T> cho phản chiếu hoặc tuần tự hóa.
Type erasure là cơ chế trong Java và Kotlin mà thông tin tham số generic bị xóa trong quá trình biên dịch. Trong bytecode, List<String> và List<Int> trở thành List đơn thuần. Điều này được thực hiện để tương thích ngược với Java 1.4 vốn không có generic, nhưng tạo ra những hạn chế khi làm việc với các kiểu tại thời điểm chạy.
// ❌ Lỗi: Không thể kiểm tra instance của kiểu đã bị xóa
fun <T> checkType(value: Any) {
if (value is T) { // type erasure — T không xác định
println("Kiểu khớp")
}
}
// ✅ Solution: pass Class as parameter
fun <T> checkTypeWithClass(
value: Any,
clazz: Class<T>
) {
if (clazz.isInstance(value)) {
println("Kiểu khớp")
}
}
Trong ví dụ, checkType không biên dịch được do type erasure — trình biên dịch không biết kiểu nào để thay thế cho T. Trong checkTypeWithClass, vấn đề được giải quyết bằng cách truyền Class<T> một cách tường minh, nhưng điều này đòi hỏi boilerplate: mỗi lần gọi đi kèm với .java hoặc ::class.java. reified loại bỏ hoàn toàn boilerplate này.
Bộ sửa đổi reified được đặt trước tham số generic trong một hàm inline. Hàm phải là inline — trình biên dịch phải có khả năng thay thế kiểu cụ thể tại giai đoạn inlining.
inline fun <reified T> isA(value: Any): Boolean {
return value is T
}
fun main() {
println(isA<String>("Hello")) // true
println(isA<Int>("Hello")) // false
}
Trong quá trình biên dịch, lời gọi isA<String>(“Hello”) được thay thế bằng kiểm tra value is String. Lời gọi isA<Int>(“Hello”) trở thành value is Int. Kiểu được thay thế theo nghĩa đen, cho phép sử dụng is, as, ::class và các thao tác khác không khả dụng với type erasure.
Nếu bạn dịch ngược bytecode của isA<String>(“Hello”), IntelliJ IDEA sẽ hiển thị kết quả gần đúng trong Java: String.class.isInstance(value). Thay vì tham số generic, trình biên dịch đã thay thế java.lang.String.class cụ thể — không có phản chiếu với tìm kiếm kiểu theo tên, chỉ một tham chiếu trực tiếp đến lớp.
Cách sử dụng phổ biến nhất của reified là kiểm tra kiểu thông qua toán tử is. Trong một hàm generic thông thường, value is T không biên dịch được. Với reified, nó hoạt động như với một lớp thông thường: value is String, value is List<Int> (gần như vậy — với hạn chế cho các kiểu được tham số hóa).
inline fun <reified T> List<Any>.filterByType(): List<T> {
return this.filter { it is T }.map { it as T }
}
val mixed = listOf("a", 1, "b", 2)
val strings = mixed.filterByType<String>() // ["a", "b"]
val ints = mixed.filterByType<Int>() // [1, 2]
Hàm mở rộng filterByType lọc một danh sách, chỉ giữ lại các phần tử thuộc kiểu được chỉ định. Không có reified, bạn phải viết filterByType<String>(list) với tham số Class<String>. Với reified, lời gọi được đọc như một thao tác tự nhiên trên danh sách, cải thiện khả năng đọc của các chuỗi xử lý dữ liệu.
Theo Hướng dẫn Coroutines Kotlin (JetBrains, 2025), các kiểm tra kiểu reified được sử dụng trong launch và async để truyền kiểu kết quả coroutine, tránh chỉ định kiểu tường minh trong hầu hết các trường hợp.
reified cung cấp quyền truy cập vào T::class — một tham chiếu đến KClass, từ đó có thể lấy Class Java qua .java. Điều này mở ra khả năng tạo các thể hiện thông qua phản chiếu, làm việc với bộ tuần tự hóa và lấy các chú thích của lớp tại thời điểm chạy.
inline fun <reified T> createInstance(): T =
T::class.java.getDeclaredConstructor().newInstance()
// Cách dùng
data class User(val name: String = "default")
val user = createInstance<User>()
// Tuần tự hóa với Gson
inline fun <reified T> Gson.fromJson(json: String): T =
this.fromJson(json, T::class.java)
// Lấy chú thích
inline fun <reified T> hasAnnotation<A>(): Boolean where A : Annotation =
T::class.java.isAnnotationPresent(A::class.java)
Wrapper fromJson cho Gson là một ví dụ cổ điển về việc sử dụng reified trong sản xuất. Thay vì gson.fromJson(json, User::class.java), bạn có thể viết gson.fromJson<User>(json). Điều này có vẻ là một cải tiến nhỏ, nhưng trong một dự án có hàng trăm lời gọi tuần tự hóa, reified làm giảm đáng kể boilerplate và làm cho mã sạch hơn.
reified có những hạn chế. Thứ nhất — chỉ hoạt động trong các hàm inline. Nếu một hàm không thể được inline (ví dụ, nó đệ quy hoặc quá lớn), reified không khả dụng. Thứ hai — reified không thể sử dụng trực tiếp với các hàm suspend, chỉ thông qua các wrapper inline.
Thứ ba — reified không hoạt động hoàn toàn với các kiểu được tham số hóa. Ví dụ, filterByType<List<String>>() có thể cho kết quả không mong đợi vì đối với các kiểu được tham số hóa, reified chỉ giữ lại kiểu raw (List), không có các đối số generic. Để kiểm tra đầy đủ các kiểu được tham số hóa, cần phản chiếu với TypeToken.
| Thao tác | Có reified | Không có reified |
|---|---|---|
| value is T | ✅ Hoạt động | ❌ Lỗi biên dịch |
| T::class | ✅ Hoạt động | ❌ Lỗi biên dịch |
| List<String> is T | ⚠️ Chỉ raw type | ❌ Lỗi |
| Tạo thể hiện | ✅ Qua phản chiếu | ❌ Cần Class<T> |
| Hàm suspend | ❌ Chỉ qua wrapper inline | ❌ Không áp dụng |
Trong trường hợp reified không khả dụng, hãy sử dụng mẫu với Class<T> tường minh hoặc TypeToken từ các thư viện (ví dụ, Gson TypeToken hoặc Jackson TypeReference). Cách tiếp cận này hoạt động trong bất kỳ hàm nào nhưng đòi hỏi boilerplate và ít tiện lợi hơn.
Câu hỏi thường gặp
Trình biên dịch thay thế tham số reified T bằng kiểu cụ thể trong quá trình inline phần thân hàm. Nếu hàm không phải inline, trình biên dịch không có nơi để thay thế kiểu — một lời gọi hàm generic diễn ra thông qua một bytecode duy nhất, nơi T bị xóa. Inline tạo một bản sao bytecode riêng cho mỗi kiểu đối số.
Không, reified chỉ áp dụng cho các tham số hàm. Đối với thuộc tính, hãy sử dụng mẫu inline fun <reified T> với giá trị trả về, hoặc truyền Class<T> một cách tường minh qua hàm tạo. Các thuộc tính mở rộng cũng không hỗ trợ reified.
reified hỗ trợ các kiểu nullable: reified T : Any (không null) và đơn giản là reified T (có thể null). Đối với các kiểu nullable, T::class trả về lớp cho phiên bản không null (String::class cho String?). Phép kiểm tra value is T tính đến null: nếu T = String?, thì null is T = true.
Tối thiểu. reified không sử dụng phản chiếu — trình biên dịch thay thế kiểu cụ thể tại giai đoạn inlining. Trong bytecode, đây là một tham chiếu trực tiếp đến lớp (ldc + checkcast/invokevirtual). Không có chi phí so với việc truyền Class<T> thủ công — cả hai cách tiếp cận đều tạo ra bytecode giống hệt.
Có, reified được sử dụng tích cực trong Android. Bundle.getParcelable<T>(), Intent.getSerializableExtra<T>(), viewModels<T>() từ Android KTX — tất cả các hàm này đều sử dụng reified để tránh truyền Class<T> một cách tường minh. Theo Tài liệu Android của Google (2025), reified được khuyến nghị cho các API generic khi cần kiểu tại thời điểm chạy.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm