Как проверить тип объекта (instanceof) в Kotlin?
Использование оператора is для проверки типа
В Kotlin аналогом Java-оператора instanceof является оператор is. Он работает практически так же, но с одним важным преимуществом — умным приведением типов (smart cast). После успешной проверки типа с помощью is вам не нужно явно приводить объект к этому типу — компилятор делает это автоматически.
val obj: Any = "Привет, Kotlin!"
if (obj is String) {
// Здесь obj автоматически приведён к String
println(obj.length) // Работает без явного приведения
}
Если вы хотите проверить обратное (что объект НЕ является определённым типом), используйте оператор !is:
if (obj !is String) {
println("obj — не строка")
}
Использование в when выражении
Оператор is отлично работает внутри when, что делает код более читаемым и лаконичным:
fun describe(obj: Any): String {
return when (obj) {
is String -> "Строка длиной ${obj.length}"
is Int -> "Целое число: $obj"
is List<*> -> "Список из ${obj.size} элементов"
else -> "Неизвестный тип"
}
}
В каждом блоке when объект автоматически приводится к соответствующему типу, так что вы можете сразу использовать его свойства.
Безопасное приведение с помощью as?
Иногда вам нужно не просто проверить тип, но и получить объект нужного типа, или выполнить действие, если приведение невозможно. Для этого используйте оператор as? (безопасное приведение):
val obj: Any = "Kotlin"
val str: String? = obj as? String // Если obj — не String, вернёт null
println(str?.length) // Безопасный вызов через ?.
Если вы уверены в типе на 100% и готовы рискнуть исключением, используйте оператор as (небезопасное приведение):
val str: String = obj as String // Может выбросить ClassCastException
Проверка типов с дженериками
Из-за стирания типов (type erasure) в Kotlin (как и в Java) вы не можете проверить тип дженерика во время выполнения напрямую:
if (obj is List<String>) { } // Ошибка: Cannot check for instance of erased type
Однако вы можете проверить сам тип коллекции, а затем работать с её элементами, используя фильтрацию:
val list: Any = listOf("a", "b", "c")
if (list is List<*>) {
val strings = list.filterIsInstance<String>() // Оставит только строки
println(strings) // [a, b, c]
}
Лучшие практики
- Всегда используйте
isвместоasдля проверки типа — это безопаснее и читаемее. - Применяйте
whenсisдля обработки нескольких возможных типов — это избавляет от цепочек if-else. - Избегайте небезопасного приведения
asбез явной проверкиis— это может привести к ClassCastException. - Для работы с коллекциями используйте
filterIsInstance<T>()— это типобезопасный способ отфильтровать элементы по классу.
В итоге, Kotlin делает проверку типов более удобной и безопасной, чем Java. Вы не только проверяете тип, но и сразу получаете готовый к использованию объект нужного типа без лишних приведений.
<<Альтернативный подход: использование when с несколькими условиями
Если вам нужно проверить тип объекта и выполнить разные действия, when — это идиоматический способ в Kotlin. Но иногда удобно комбинировать проверку типа с другими условиями:
fun process(obj: Any) {
when {
obj is String && obj.length > 5 -> println("Длинная строка: $obj")
obj is Int && obj > 100 -> println("Большое число: $obj")
obj is List<*> && obj.isNotEmpty() -> println("Непустой список: ${obj.size} элементов")
else -> println("Что-то другое")
}
}
Этот подход позволяет добавлять дополнительные логические условия без вложенных if-блоков.
Работа с nullable типами
Оператор is также работает с nullable типами. Например, если у вас есть переменная типа String?, вы можете проверить, не является ли она null и имеет ли нужный тип:
val obj: Any? = "Hello"
if (obj is String) {
// obj автоматически приведён к String (не String?)
println(obj.length)
}
Обратите внимание: если объект равен null, проверка obj is String вернёт false, так как null не является экземпляром никакого класса.
Таким образом, is и as? покрывают все сценарии, которые в Java требовали instanceof и явного приведения. Kotlin делает код чище и безопаснее.