如何在Java中向下转换对象

如何在Java中向下转换对象,java,inheritance,downcast,Java,Inheritance,Downcast,我正在我的公司使用一个API,我想为现有对象创建一个子类。以下是注意事项: 我不能修改超类 我无法修改超类对象的实例化方式 我看到的最常见的例子是狗作为动物的一个子类,所以我将使用它。假设API中有这样一个类: //API class, which I cannot modify public class Animal(){ public void eat(){ //All animals can do this } } 现在我想创建一个这样的类,它为Ani

我正在我的公司使用一个API,我想为现有对象创建一个子类。以下是注意事项:

  • 我不能修改超类
  • 我无法修改超类对象的实例化方式
我看到的最常见的例子是狗作为动物的一个子类,所以我将使用它。假设API中有这样一个类:

//API class, which I cannot modify
public class Animal(){
    public void eat(){
        //All animals can do this
    }
}
现在我想创建一个这样的类,它为Animal添加了一些方法

//My subclass, which I can modify
public class Dog extends Animal(){
    public void fetch(){
        //Only dogs can do this
    }
}

现在让我们假设我有一个动物的例子(一个不是狗的例子)。我基本上需要把它扔给一条狗。我知道Java不直接支持向下转换,但是有没有解决方法

public class AnimalExample{
    public static void main(String[] args){
        Animal animal = MyApi.getAnAnimal();
        //Dog dog = (Dog) animal; ---throws a runtime error
        Dog dog = Dog.getDog(animal); //Maybe something like this?

        //Then I should be able to call both eat() and fetch()
        dog.eat();
        dog.fetch();
    }
}
再一次,我明白下行广播是不直接支持的。但必须有一些解决办法,我想不出来。我知道我可以使用包装器类(例如
DogWrapper
),但这比我希望的要困难一些,因为我仍然经常调用几十个超类方法


更新:我知道它还不是一只狗,但我想知道是否有办法把它变成一只狗。从人们的说法来看,我要么必须手动转换它(逐个复制每个属性/方法),要么只使用包装类。包装器类看起来没有那么凌乱,所以很不幸,我只能走这条路了。因此,
DogWrapper
将有一个
fetch()
方法和一个
getAnimal()
方法。因此,如果我想让
狗吃东西,那么我必须调用
Dog.getAnimal().eat()
。我本来是想避免那样做的,但我想这是没有办法的。有人看到了比这更简单的东西吗?

你可以有一个构造函数,它接受Animal并用默认值或根据需要实例化对象的Dog部分

public Dog (Animal animal) {
    super(); // any instantiation that has to be done for animal
    // Dog instantiation
   // Use animal properties as required
}
Dog dog = new Dog(animal);

还有一个静态方法,如您所述。getDog(animal)
是一个选项,取决于您的编码偏好。

您可以有一个构造函数,它接受animal并根据默认值或需要实例化对象的Dog部分

public Dog (Animal animal) {
    super(); // any instantiation that has to be done for animal
    // Dog instantiation
   // Use animal properties as required
}
Dog dog = new Dog(animal);

还有一个静态方法,如您所述。getDog(animal)是一个选项,取决于您的编码偏好。

让我们假设我创建了一个需要
狗的方法,但它是为了扩展
animal
API。当然,我可以这样做签名:

public void doFetch(Dog dog)
但正如我所说,我想扩展
Animal
API。现在,如果给定的
动物
不是
,我无法取回。考虑到这一点,我可以做以下工作:

public void doFetch(Animal fetcher) {
    if(fetcher instanceof Dog) {
        Dog dog = (Dog) fetcher;
        ... //Do fetchy things
        return;
    }
    //If we reach this point, then the animal is not a dog
    throw new IllegalArgumentException("fetcher is not a Dog!");
}
现在让我们假设,在你的例子中,我有一只
动物
,它不是狗,但出于某种原因,我希望它是一只
。在这种情况下,我可以使用某种翻译器将任何
动物
转换成狗。我更喜欢在
Dog
类本身中将这样的东西定义为
static
方法:

//Breaks the laws of nature by making a Dog from any Animal.
public static Dog fromAnimal(Animal animal) {
     Dog dog = new Dog();
     //Here you would set all the properties of the animal, e.g.:
     dog.setName(animal.getName());
     ...
     return dog;
}

让我们假设我创建了一个方法,该方法需要一只
,但要扩展
动物
API。当然,我可以这样做签名:

public void doFetch(Dog dog)
但正如我所说,我想扩展
Animal
API。现在,如果给定的
动物
不是
,我无法取回。考虑到这一点,我可以做以下工作:

public void doFetch(Animal fetcher) {
    if(fetcher instanceof Dog) {
        Dog dog = (Dog) fetcher;
        ... //Do fetchy things
        return;
    }
    //If we reach this point, then the animal is not a dog
    throw new IllegalArgumentException("fetcher is not a Dog!");
}
现在让我们假设,在你的例子中,我有一只
动物
,它不是狗,但出于某种原因,我希望它是一只
。在这种情况下,我可以使用某种翻译器将任何
动物
转换成狗。我更喜欢在
Dog
类本身中将这样的东西定义为
static
方法:

//Breaks the laws of nature by making a Dog from any Animal.
public static Dog fromAnimal(Animal animal) {
     Dog dog = new Dog();
     //Here you would set all the properties of the animal, e.g.:
     dog.setName(animal.getName());
     ...
     return dog;
}

“我基本上需要把它变成一只狗”,但它不是一只
狗。你不能要求非狗表现得像狗一样。支持向下投射,但已安全完成。。。仅当执行时间类型与请求的类型兼容时,强制转换才会成功。您希望
dog.fetch()
做什么?如果它使用了在
Dog
中声明的一些字段,而这些字段不在实际对象中,该怎么办?因此,您有一些
动物
,它们不是
,但您希望将其视为
。你必须自己把它变成一只狗;Java本身不知道如何做到这一点。(为什么你认为这是有用的?如果动物不是
,那么如果你调用一个特定于
?)的方法,它该怎么办?我建议你做一些像If(动物实例of Dog){Dog Dog=(Dog)animal}或者{//处理问题案例}这样的事情“我想使用委托模式将非狗包装在狗的东西中,这样我就可以将其用作狗,但我不想努力工作并编写所有委托方法“是吗?我知道它还不是一只
狗,但我想知道是否有办法把它变成
狗。从人们的说法来看,我要么手动转换它(逐个复制每个属性),要么只使用包装器类。包装器类看起来没有那么凌乱,所以很不幸,我不得不去那里。因此,
DogWrapper
将有一个
fetch()
方法和一个
getAnimal()
方法。因此,如果我想让
狗吃东西,那么我必须调用
Dog.getAnimal().eat()
。我一直在避免这样做,但我想这是没有办法的。“我基本上需要把它扔给一只狗”,但它不是一只
狗。你不能要求非狗表现得像狗一样。支持向下投射,但已安全完成。。。仅当执行时间类型与请求的类型兼容时,强制转换才会成功。您希望
dog.fetch()
做什么?如果它使用在
Dog
中声明的一些字段,而这些字段不在实际对象中,会怎么样?因此,您有一些
Animal
不是