Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/209.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android Kotlin类强制转换异常_Android_Class_Exception_Kotlin - Fatal编程技术网

Android Kotlin类强制转换异常

Android Kotlin类强制转换异常,android,class,exception,kotlin,Android,Class,Exception,Kotlin,我是Android开发新手,我在教程中看到了这段代码 class MainActivity : AppCompatActivity() { private val newNumber by lazy(LazyThreadSafetyMode.NONE) { findViewById<EditText>(R.id.newNumber) } override fun onCreate(savedInstanceState: Bundle?) {

我是Android开发新手,我在教程中看到了这段代码

class MainActivity : AppCompatActivity() {
    private val newNumber by lazy(LazyThreadSafetyMode.NONE) { 
        findViewById<EditText>(R.id.newNumber) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val listener = View.OnClickListener {v ->
            val b = v as Button
            newNumber.append(v.text)
        }

    }
}

为什么会发生这种情况?

在Kotlin中,
as
是一个类型转换操作符

val b = v as Button
在Java中的等价项(忽略空检查)是

此外,第一段代码中的
listener
未被使用


对于第二段代码,
按钮
肯定是一个
视图
,但是
视图
可能不是
按钮
。如果您尝试强制转换一个
视图
,它实际上不是一个
按钮
,您将得到该强制转换异常。

这是java的基本概念。如果您仔细阅读了异常文档

抛出,指示代码试图将对象强制转换为它不是实例的子类。 简单地说,如果父类对象(v)包含子类对象实例,则只能将其类型转换为子类类型(按钮)

所以正确的代码应该是

val v: View = Button()
val b = v as Button
b.c()

as
是在Kotlin中铸造的关键字。示例:
someInstance作为CastTarget
。Java等价物是
(CastTarget)someInstance
。这些通常是特定于语言的,但有些语言具有相同的语法。C++和java有相同的语法(尽管它还有一个额外的语法,但这不是重点)。p> 按钮扩展视图。也就是说,按钮就是一个视图然而,这并不意味着视图是一个按钮。视图也可以是TextView、ListView、RecyclerView等。视图列表很长,还有添加更多内容的库

这意味着这是有效的:

val view: View = Button(...)
val btn = view as Button
这是因为在本例中,视图是一个按钮。但是,如果您有:

val view: View = RecyclerView(...)
val btn = view as Button
它将失败。这是因为,在本例中,出于非常明显的原因,RecyclerView不是按钮。查看(…)as按钮失败的原因是视图也不是按钮。强制转换时,只能将实例强制转换为自身或父类,而不能转换为子类。下面是一个实际的例子:

interface Base 
class Parent : Base 
class Child1 : Parent()
class Child11 : Child1()
class Child2 : Parent()
现在,在这种情况下,类是无用的。它们什么都不做,但仍然可以用来演示继承和铸造

现在,假设你有:

val base = getRandomBaseChild()
这是否意味着你有一个
孩子2
?这里的推断类型是
Base
,这意味着它可以是扩展/实现Base的任何类(或接口,因为Base是一个接口)。不一定非得是个孩子,但也可以是。由于这种情况下的方法是随机的,因此有时会失败,但并非总是如此:

val child2 = base as Child2
这是因为在某些情况下,基地实际上是一个孩子2。但对于其他任何一种情况,它都不是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");
您还添加了一些代码;在您的示例中,您将始终能够将按钮转换为文本视图或视图,并且文本视图可以转换为视图。但是,如果将视图强制转换为文本视图或按钮,则会失败,因为类型不同

TL;医生:

视图不是按钮。要使代码正常工作,请使用
val v:View=Button()
,然后强制转换<仅当声明为父类型的实例实际上是指定的子实例时,code>v才能强制转换为子实例。您还可以使用
is
在强制转换之前检查类型是否匹配,或者使用
as?
在失败时获取null



您还可以了解类型和继承

因为这个问题不是特定于Android的,所以让我们创建一个简单的示例

考虑以下继承层次结构,其中我们有一个水果,它有两个子类
Apple
Banana

open class Fruit
class Apple: Fruit()
class Banana: Fruit()
让我们做一些测试,如果强制转换失败,它将返回
null

val fruit = Fruit()
fruit as? Apple // returns null - fruit is not of type Apple

val apple = Apple()
apple as? Fruit // apple is a Fruit
apple as? Banana // returns null - apple is not a Banana
如果您创建一个
水果
,它既不是
苹果
,也不是
香蕉
。一般来说只是一个水果


如果您创建一个
苹果
,它就是一个
水果
,因为
水果
是它的超类,但是
苹果
香蕉

无关,非常感谢!我是一个拥有Kotlin和类型化语言的noob,因为我来自javascript世界。我终于明白了!:)太好了!确保通过接受任何你认为有用的答案来结束问题。非常感谢你给出了这个非常详细的答案。我很感激。
val child2 = base as? Child2 ?: TODO("Cast failed");
open class Fruit
class Apple: Fruit()
class Banana: Fruit()
val fruit = Fruit()
fruit as? Apple // returns null - fruit is not of type Apple

val apple = Apple()
apple as? Fruit // apple is a Fruit
apple as? Banana // returns null - apple is not a Banana