如何在Kotlin中将超类对象转换为子类对象?

huangapple go评论80阅读模式
英文:

How to cast super class object to sub class object in Kotlin?

问题

在这里,我试图将超类对象转换为子类。我收到了运行时错误,错误消息是“无法强制转换类”。

示例:

class Animal {}
class Cat : Animal() {}

class abc {
    fun abcd(): Animal {
        return Animal()
    }

    fun getData() {
        val cat: Cat = abcd() as Cat     // 给我运行时错误。
    }
}
英文:

Here I am trying to converting superclass object to subclass. I am getting the runtime error as "class can not be cast".

Eg :

class Animal {}
class Cat : Animal() {}

class abc {
fun abcd(): Animal {
    return Animal()
}

fun getData() {
    val cat: Cat = abcd() as Cat     //Giving me runtime error.
}
}

答案1

得分: 5

无法将基类 'instance' 强制转换为派生类,因为基类不一定实现其派生类的行为,也不知道它们的任何信息。

在您的具体示例中,方法 abcd() 返回基类 Animal 的一个实例,因此无法将其强制转换为 Cat,因为 Animal 可能不具有 Cat 中定义的任何行为。

举个例子,想象一下您还有一个 Dog 类,CatDog 都实现了不同的方法,例如 dog.fetch()cat.jump()。这些行为在基类 Animal 中不存在,因此不能将其明确地转换为特定的动物。

反过来是有效的,因此可以将 Cat 转换为 Animal,因为 Cat 继承了其基类 Animal 的行为。

相反,您可以在 abcd() 中实例化一个 Cat,并仍然返回 Animal

fun abcd(): Animal {
    return Cat()
}

这是有效的,强制转换将起作用。但是,您必须注意避免在运行时混用派生类时出现潜在的 ClassCastException,例如,如果在返回类型为 Animal 的情况下实例化一个 Dog 并将其用作 Cat

**小提示:**我假设在您的示例中,Animal 不是 open 的原因只是一个复制粘贴错误,因为明显需要此关键字来允许继承。

英文:

You can't cast a base class 'instance' to a descendant class, because a base class does not necessarily implement the behaviors of its descendants neither knows anything about them.

In your specific example the method abcd() returns an instance of the base class Animal, and therefore such can't be cast to Cat, since Animal may not have any of the behaviors defined in Cat.

An example, imagine you had also a Dog class, and both Cat and Dog implement different methods such as dog.fetch() and cat.jump(). Such behaviors don't exist in the base class Animal, and therefore it can't be explicitly cast to a specific animal.

The opposite is valid, so casting Cat to Animal, because Cat inherits the behaviors of its base class Animal.

Instead, what you can do is to instantiate a Cat in abcd(), and still return Animal:

fun abcd(): Animal {
    return Cat()
}

This is valid, and the casting will work. But, you must pay attention to avoid potential ClassCastException's at runtime if mixing up derived classes, for example if instantiating a Dog while the return type is Animal and try to use it as Cat.

Small remark: I'm assuming the reason Animal isn't open in your example is just a copy/paste mistake, as it clearly needs such keyword to allow inheritance.

答案2

得分: 2

也许你想要做的是创建一个类型,并基于子类型执行某些操作,就像这样:

sealed class Animal

data class Cat(val...) : Animal()
data class Dog(val...) : Animal()

class YourMapper {
    fun animal(condition: Type): Animal {
        return when(condition) {
            ... -> Dog(...)
            ... -> Cat(...)
        }
    }

    fun getData(condition: Type): Animal {
        return animal(condition)
    }
}

然后使用方式为:

val data = YourMapper().getData(condition)
when(data) {
  is Dog -> {/*与狗相关的操作*/}
  is Cat -> {/*与猫相关的操作*/} 
}
英文:

Maybe what you are trying to do is something like creating a type and based on what sub-type then do something, like this:

sealed class Animal

data class Cat(val...) : Animal()
data class Dog(val...) : Animal()

class YourMapper {
    fun animal(condition: Type): Animal {
        return when(condition) {
            ... -> Dog(...)
            ... -> Cat(...)
        }
    }

    fun getData(condition: Type): Animal {
        return animal(condition)
    }

And then the usage is

val data = YourMapper().getData(condition)
when(data) {
  is Dog -> {/*do something with your dog*/}
  is Cat -> {/*do something with your cat*/} 
}

答案3

得分: 1

我知道这是一个旧问题,但它是搜索“Kotlin如何将超类转换为子类”的谷歌首选结果,所以为了记录:

在Kotlin中如何转换为子类
使用“as”关键字,就像原问题中所示:

val animal: Animal = Cat()
if (animal is Cat) {
    val cat: Cat = animal as Cat
}

原问题
简短回答,你不能将超类对象直接转换为子类对象。转换仅会改变对象的引用类型,对象本身保持不变。

问题中的Animal类几乎肯定应标记为抽象类。这样就不可能意外实例化非特定的动物,这是问题中发生的情况,并导致了异常。

Animal的引用变量确实可以被转换为Cat,前提是它引用的对象是Cat。但在问题中,实例化了一个非特定的Animal对象,然后尝试将其转换为Cat,但由于它没有引用到Cat对象,因此理所当然地会抛出异常。

因此,与将Int转换为Double等情况不同,其中转换似乎改变了对象的类型,类型转换实际上并不“改变”对象本身,只是改变了你引用它的方式的精细程度。
类型转换无法将Dog变为Cat,它只能使你从将动物视为通用的Animal,查看所有动物都共有的属性,转变为将其视为Cat或Dog,并额外获得只有Cat或Dog拥有的属性。

英文:

I know this is an old question, but it's the first Google hit for the search "Kotlin how to cast superclass to subclass", so for prosperity:

How to cast to subcalss in Kotlin
use the "as" keyword as in the original question:

if(animal is Cat) {
    Cat cat = animal as Cat
}

The original question
Short answer, you can't cast a superclass object to a subclass object. Casting only changes the type of the reference to the object, the object itself remains unchanged.

The Animal class in the question should almost certainly be marked as abstract. That way there's no possibility to accidentally instantiate non-specific animals, which is what happens in the question and causes the exception.

An Animal reference variable can absolutely be cast to a Cat, provided the object it references is a Cat. But in the question a non-specific Animal is instantiated, and then later attempted to cast to a Cat, but as it is not referencing a Cat object, this understandably throws an exception.

So unlike, say, casting an Int to a Double where the cast seemingly changes the type of the object, casting object references doesn't actually "change" the object, only how finely-grained your reference to it is.
Casting cannot turn a Dog into a Cat, it can only change you from examining an animal as a generic Animal, viewing properties commont to ALL animals, to examining it as a Cat or a Dog and additionally having access to the properties only Cats or Dogs have.

huangapple
  • 本文由 发表于 2020年10月8日 22:03:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/64264203.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定