java - 方法重载,为什么必须强制转换父类(super class)型

标签 java overloading

尝试重构一些代码时,我偶然发现了一个可以通过以下代码演示的问题:

public static abstract class Animal {

    public abstract void attack(Animal other);
}

public static class Cat extends Animal {

    @Override
    public void attack(Animal other) {
        catAttack(other); <-------- Problem here
    }

    private void catAttack(Cat other) {
        // Maybe a meow showdown wins the fight, no need to get physical
    }

    private void catAttack(Dog other) {
        // Dogs are dangerous, run!
    }

}

public static class Dog extends Animal {

    @Override
    public void attack(Animal other) {

    }

}

为什么找不到catAttack(other)other的具体类型,从而无法调用最具体的方法?相反,必须执行此检查:

if (other instanceof Cat)
 catAttack((Cat) other);
if (other instanceof Dog)
 catAttack((Dog) other);

编辑:这个问题可能有点不清楚,这是我作为对答案的评论发布的澄清:

the cat can attack a dog or another cat which both happen to be animals, I am curious as to why the burden of casting the other animal to either dog or cat is on me, why doesn't java try and see if it is either cat or dog because I have two methods that match either a cat or a dog and then throw an error if it was an elephant instead?

最佳答案

the cat can attack a dog or another cat which both happen to be animals, I am curious as to why the burden of casting the other animal to either dog or cat is on me, why doesn't java try and see if it is either cat or dog because I have two methods that match either a cat or a dog and then throw an error if it was an elephant instead?

不幸的是,您的建议与当前 java 编译器实现的方法匹配系统不一致。

编译器必须执行所谓的静态类型检查,它基本上包括静态检查(即在程序运行之前)代码是否类型安全,这将在后一种情况会导致运行时错误。

举个例子,考虑:

float b = 4.6f;
int a = 5 + b;

这里编译器知道b是float类型,知道operator +有一个(int + float = float)的条目,并且知道a是integer类型。因此,它推断表达式的类型为 float,并且必须转换为整数才能分配给 a。 java 中不允许这种转换,因此它会输出错误以防止精度损失。

对于对象,基本上是相同的,知道层次结构较深的类可以“转换”为其较浅的父类,但反之则不然。

因此,就您而言:

public void attack(Animal other) {
    catAttack(other); <-------- Problem here
}

private void catAttack(Cat other) {
    // Maybe a meow showdown wins the fight, no need to get physical
}

private void catAttack(Dog other) {
    // Dogs are dangerous, run!
}

在不运行整个程序的情况下,java编译器无法推断方法attack(Animal other)中变量other的真实类。 它只能知道“指针”是 Animal 类型,因此真正的类可以是扩展 Animal 的任何类,并且它必须对您对 catAttack(other) 的调用进行类型检查(并静态解析方法调用)/code> 只知道这一点。

由于没有 catAttack(Animal) 方法,java 编译器无法保证代码的类型安全,并输出错误。

你可以做的是:

public static abstract class Animal {

   public abstract void attack(Animal other);

   public abstract void beAttackedByCat(Animal cat);
   public abstract void beAttackedByDog(Animal dog);
}

public static class Cat extends Animal {

   @Override
   public void attack(Animal other) {
       other.beAttackedByCat(this);
   }

   public void beAttackedByCat(Animal cat){ // cat > cat }
   public void beAttackedByDog(Animal dog){ // dog > cat }
}

public static class Dog extends Animal {

   @Override
   public void attack(Animal other) {
      other.beAttackedByDog(this);
   }

   public void beAttackedByCat(Animal cat){ // cat > dog }
   public void beAttackedByDog(Animal dog){ // dog > dog }
}

这可能与完美的解决方案相去甚远,但只是为了让您了解可以做什么和不能做什么。

关于java - 方法重载,为什么必须强制转换父类(super class)型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18094401/

相关文章:

java - Unix shell : Turn file with directory names to ':' separated classpath

java - log4j2 使用 slf4j 关闭所有附加程序

java - 有效结尾的正则表达式

c++ - 如何为模板的成员类型重载自由函数

mysql进程不断重载

c++ - C++ 中的错误 c6277 重载 &&

java - @IntoMap @Binds 如何与 Dagger 一起工作?

java - 如何使用selenium webdriver在FB中打印在线好友姓名?

c++ - unique_ptr 和 shared_ptr 的重载方法与多态性不明确

Java 8 消费者/函数 Lambda 歧义