具有继承性的静态和动态类型 - Java中的细微之处?

时间:2012-08-09 07:32:14

标签: java inheritance

所以我有这个相关的代码......

public class PokemonTrainer {
    private Pokemon p = new Squirtle();
    private String name;

    public PokemonTrainer(String name) {
        this.name = name;
    }

    public static void main(String[] args) {
        PokemonTrainer pt = new PokemonTrainer("Ash");
        try {pt.fightGary();}

        catch (Charmander c) {
            System.out.println("You were roasted by a Charmander.");
        }

        catch (Squirtle s) {
            System.out.println("You were drowned by a Squirtle.");
        }

        catch (Bulbasaur b) {
            System.out.println("You were strangled by a Bulbasaur.");
        }

        catch (Pokemon p) {
            System.out.println("You survived!");
        }
    }

    public void fightGary() throws Pokemon {
        throw p;
    }

public class Pokemon extends Exception {}
public class Bulbasaur extends Pokemon {}
public class Squirtle extends Pokemon {}
public class Charmander extends Pokemon {}

为什么打印“你被一个Squirtle淹死了”?

在我的推理中,“catch”是一种方法,当一个对象被传递给一个方法时,该方法根据对象的STATIC TYPE进行评估 - 也就是说,“Pokemon”,在这种情况下 - 这被证明在下面的简短例子中:

public class PokemonTrainer {
    private Pokemon p = new Squirtle();
    private String name;

    public PokemonTrainer(String name) {
        this.name = name;
    }

    public static void main(String[] args) {
        PokemonTrainer pt = new PokemonTrainer("Ash");
        pt.fightGary(pt.p); // ------------ Prints "Pokemon!!!"
    }

    public void fightGary(Pokemon p) {
        System.out.println("Pokemon!!!");
    }

    public void fightGary(Squirtle s) {
        System.out.println("Squirtle!!!");
    }
}

那么这两个例子有什么不同?为什么第一个例子打印它的作用?

谢谢!

4 个答案:

答案 0 :(得分:8)

  

在我的推理中,“catch”是一种方法

这是第一个错误。 catch不是一种方法,并试图将其视为可能会导致问题。

这是一种具有自己规则的语言结构。您应该阅读language specification section 14.20exceptions tutorial以获取更多信息。

简而言之,当您有一系列catch块时,将执行第一个匹配抛出异常的执行时间类型的块。 (编译器将阻止您在更具体的异常之前捕获更一般的异常。)

所以如果你有:

try {
  doSomething();
} catch (FileNotFoundException e) {
  ...
} catch (IOException e) {
  ...
}

然后,如果doSomething()抛出FileNotFoundException,它将执行第一个catch块(而那个) - 而如果它抛出任何其他类型的IOException,它将执行第二个catch块。任何其他异常都会在堆栈中传播。

答案 1 :(得分:1)

嗯,catch不是一种方法,而是Java语言的一部分。

但是要回答您的问题,pSquirtle的实例:

Pokemon p = new Squirtle();

由于有一个catch子句可以捕获Squirtle,所以它就是这样。

catch (Squirtle s)

如果此行不存在,则更通用

catch (Pokemon p)

会处理抛出的Squirtle

答案 2 :(得分:1)

虽然Pokemon p被声明为口袋妖怪,但它被实例化为带有new Squirtle()的Squirtle。因为它在内部是一个Squirtle,getClass(),当它被调用时,将返回Squirtle.class,因此try-catch在甚至检查Pokemon catch之前捕获Squirtle catch。

这称为polymorphism

关于你的推理,catch不是一个方法,而是一个带有try块的语句,用于声明在抛出某些异常的情况下该怎么做。

答案 3 :(得分:1)

您将reference的类型与object的类型混淆。

Catch更像是switch对象上的instanceof

考虑一个更简单的例子

String s = "hello";
Object o = s;

在这种情况下,o的引用类型为Object,但Strings的对象类型为o,因为它们相同对象