as
- ключевое слово для кастинга в Котлине.Пример: someInstance as CastTarget
.Эквивалент Java равен (CastTarget) someInstance
.Обычно они зависят от языка, но некоторые языки имеют такой же синтаксис.С ++ имеет тот же синтаксис, что и Java (хотя он и имеет дополнительный, но это не относится к делу).
Кнопки расширяют вид.Это означает, что кнопка является представлением. Однако , это не означает, что View является кнопкой.Представлением также может быть TextView, ListView, RecyclerView и т. Д. Существует длинный список представлений, а также есть библиотеки, которые добавляют больше.
Это означает, что это действительно:
val view: View = Button(...)
val btn = view as Button
Это работает, потому что в данном случае представление представляет собой кнопку.Однако, если у вас есть:
val view: View = RecyclerView(...)
val btn = view as Button
, это не удастся.Это происходит потому, что по довольно очевидным причинам в этом случае RecyclerView не является кнопкой.Причина сбоя View(...) as Button
в том, что View тоже не кнопка.Когда вы приводите, вы можете использовать только экземпляр как самого себя или как родительский, но не дочерний класс.Вот фактический пример:
interface Base
class Parent : Base
class Child1 : Parent()
class Child11 : Child1()
class Child2 : Parent()
Теперь, в этом случае, классы бесполезны.Они ничего не делают, но их все еще можно использовать для демонстрации наследования и приведения.
Теперь, скажем, у вас есть это:
val base = getRandomBaseChild()
Означает ли это, что у вас есть Child2
?Предполагаемый тип здесь будет Base
, что означает, что это может быть любой класс (или интерфейс, поскольку Base является интерфейсом), который расширяет / реализует Base.Это не имеет , чтобы быть Child2, но это может быть.Так как метод в этом случае будет случайным, это может произойти несколько раз, но не всегда:
val child2 = base as Child2
Это связано с тем, что в некоторых случаях основой будет Child2.Но для любого другого экземпляра это не Child2.
Скажем, мы взяли Child1 вместо:
val child1 = base as Child1
Это фактически имеет две действительные цели: Child1 и Child11.Вы можете всегда понижать, но никогда не повышать, если тип не соответствует.Теперь вы знаете, что это всегда будет успешным:
val obj = base as Any
Потому что все Any
(/ Object
в Java).Но обновление не обязательно будет успешным, пока тип не будет правильным.
Теперь, если вы находитесь в таком случае, когда тип действительно меняется, самый простой способ - использовать is
:
if(base is Child2) // cast and do something
В качестве альтернативы, есть более тяжелый подход с использованием as?
.Обратите внимание, что это добавит обнуляемый тип;если произойдет сбой приведения, вы получите null:
val child2 = base as? Child2 ?: TODO("Cast failed");
Вы также добавили некоторый код;в ваших примерах вы всегда сможете использовать Button как TextView или View, а TextView можно преобразовать как View.Однако, если вы приведете View как TextView или Button, произойдет сбой, потому что тип не совпадает.
TL; DR:
Вид не является кнопкой.Чтобы ваш код работал, используйте val v: View = Button()
, а затем приведите.v
может быть приведен как дочерний, только если экземпляр, объявленный как родительский тип, фактически является указанным дочерним.Вы также можете использовать is
, чтобы проверить, является ли тип совпадающим, прежде чем разыграть, или использовать as?
, чтобы получить ноль, если он потерпит неудачу.
Вы также можете взглянуть на эту статью из Oracle о типах и наследовании.