as
是 Kotlin 中转换的关键字。例子:someInstance as CastTarget
。 Java 的等价物是(CastTarget) someInstance
。这些通常是特定于语言的,但某些语言具有相同的语法。 C++ 与 Java 具有相同的语法(尽管它还有一个额外的语法,但这不是重点)。
按钮扩展了视图。这意味着,按钮就是一个视图。However,这并不意味着视图是一个按钮。 View 还可以是 TextView、ListView、RecyclerView 等。View 的列表很长,而且还有添加更多内容的库。
这意味着这是有效的:
val view: View = Button(...)
val btn = view as Button
这是可行的,因为在本例中视图是一个按钮。但是,如果您有:
val view: View = RecyclerView(...)
val btn = view as Button
它会失败。这是因为,在本例中,出于非常明显的原因,RecyclerView 不是按钮。原因View(...) as Button
失败是因为视图也不是按钮。当您进行强制转换时,您只能将实例强制转换为其自身或父类,而不能将其强制转换为子类。这是一个实际的例子:
interface Base
class Parent : Base
class Child1 : Parent()
class Child11 : Child1()
class Child2 : Parent()
现在,在这种情况下,这些类就没用了。它们不执行任何操作,但仍可用于演示继承和转换。
现在,假设你有这个:
val base = getRandomBaseChild()
这是否意味着您有Child2
?这里推断的类型是Base
,这意味着它可以是扩展/实现 Base 的任何类(或接口,因为 Base 是一个接口)。事实并非如此have成为一个Child2,但它可以。由于本例中的方法是随机的,因此有时会失败,但并非总是如此:
val child2 = base as Child2
这是因为在某些情况下,基实际上是 Child2。但对于任何其他实例,它都不是 Child2。
假设我们用 Child1 代替:
val child1 = base as Child1
这实际上有两个有效目标:Child1 和 Child11。您始终可以向下转型,但决不能向上转型,除非类型匹配。有了这个,你现在知道这永远会成功:
val obj = base as Any
因为一切都是Any
(/Object
在爪哇)。但除非类型正确,否则向上转型不一定会成功。
现在,如果您遇到这样的情况,其中类型实际上有所不同,最简单的方法是使用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?
如果失败则返回 null。
您还可以看看这篇文章来自甲骨文 https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html关于类型和继承。