为什么向上转换一个不改变被覆盖方法的类?

时间:2015-12-15 05:17:12

标签: java inheritance subclass superclass upcasting

我有一个继承自ScottishPerson类的子类BritishPerson

class BritishPerson {
    public String name = "A british name";

    public void salute() {
        System.out.println("Good Morning!");
    }
}

class ScottishPerson extends BritishPerson {
    public String name = "A scottish name "; //Variable overriding
    public String clanName = "MacDonald";

    public void salute() //Method overriding
    {
        System.out.println("Madainn Mhath!");
    }

    public void warcry() {
        System.out.println("Alba Gu Brath!");
    }
}

class Driver {

    public static void main(String[] args) {
        ScottishPerson scottishPerson = new ScottishPerson(); //Created as a subclass, can always be upcasted.
        BritishPerson britishPerson = new BritishPerson(); //Created as the superclass, throws an error when downcasted.
        BritishPerson britishPersonUpcasted =
                new ScottishPerson(); //Created as the subclass but automatically upcasted, can be downcasted again.

        //Checking the methods and parameters of scottishPerson
        scottishPerson.salute();
        scottishPerson.warcry();
        System.out.println(scottishPerson.name);
        System.out.println(scottishPerson.clanName);

        //Checking the methods and parameters of britishPerson
        britishPerson.salute();
        System.out.println(britishPerson.name);

        //Checking the methods and parameters of britishPersonUpcasted
        britishPersonUpcasted.salute();
        System.out.println(britishPersonUpcasted.name);
    }
}

运行代码,这是输出。

Madainn Mhath!
Alba Gu Brath!
A scottish name 
MacDonald
Good Morning!
A british name
Madainn Mhath!
A british name

这就是混乱所在。向上转换ScottishPersonBritishPerson会将变量名称更改为超类定义的变量名称。仅存在于子类中的方法和变量(例如warcry()clanName)将被丢弃。但是,在upcasted类上调用方法salute()仍然会返回基于子类实现的字符串。

是因为当我创建对象britishPerson时,我只初始化BritishPerson类,当我创建对象britishPersonUpcasted时,我创建了BritishPerson类和导致永久覆盖ScottishPerson方法的salute()类?

5 个答案:

答案 0 :(得分:2)

您实际调用方法的对象属于ScottishPerson,因此在编译时它会检查引用变量,但运行时它总是执行属于不引用它的对象的方法。运行时多态性实际上就是这个概念的背后。

答案 1 :(得分:2)

请详细了解这个问题,以便更好地理解上传和下传:

What is the difference between up-casting and down-casting with respect to class variable

我也是一个看待上传行为的例子:

abstract class Animal 
{ 
    public void saySomething()
    {
        System.out.println("Some Animal sound");
    }

    public abstract void getTheBall();
}

class Horse extends Animal
{ 
    public void saySomething()
    {
        System.out.println("Neigh Neigh");
    }

    public void getTheBall()
    {
        System.out.println("I won't, Try a dog, I am a Horse!");
    }
}

class Dog extends Animal 
{ 
    public void saySomething()
    {
        System.out.println("woof woof, waon waon");
    }

    public void getTheBall()
    {
        System.out.println("huf huf, here it is!");
    }
}

public class Main 
{
    public static void main (String [] args) 
    {
        Dog dog = new Dog(); 
        Horse horse = new Horse();
        Animal animal = dog;
        Animal horseAnimal = new Horse();

        //upcasting
        Dog upcastedAnimal = upcastToDog(animal);
        dog.saySomething();
        dog.getTheBall();

        upcastedAnimal.saySomething();
        upcastedAnimal.getTheBall();

        horse.saySomething();
        horse.getTheBall();

        try {
            Dog upcastedDog = upcastToDog(horseAnimal);
        } catch (Exception ex){
            System.out.println(ex.getClass().getSimpleName() + ": Obviously a horse is not a dog!");
        }
    }

    public static Dog upcastToDog(Animal animal){
        return (Dog) animal;
    }
}

输出:

woof woof, waon waon
huf huf, here it is!
woof woof, waon waon
huf huf, here it is!
Neigh Neigh
I won't, Try a dog, I am a Horse!
ClassCastException: Obviously a horse is not a dog!

首先,如果尝试生成不兼容的类型,java将抛出异常。

在可以进行强制转换的情况下,将始终从实际实例中调用overriden方法。在您的情况下,实例是ScottishPerson,因此即使您在BritishPerson中持有其引用,也会在ScottishPerson上调用方法。

您可以在此处运行示例https://repl.it/B83f/3

在JLS中,这里涵盖了“Narrowing Reference Conversion”,因为他的名字表明只有参考被缩小或扩大(或上升或下调)而不是实例。

答案 2 :(得分:1)

  • 访问静态字段,实例字段和静态方法取决于变量所指向的引用变量类而不是实际对象
  • 请记住,成员变量是阴影的,不会被覆盖。
  • 这与实例方法的情况相反 在实例方法的情况下,调用对象的实际类的方法。

请考虑以下示例。

    class ABCD {
        int x = 10;
        static int y = 20;

        public String getName() {
            return "ABCD";
        }
    }

    class MNOP extends ABCD {
        int x = 30;
        static int y = 40;

        public String getName() {
            return "MNOP";
        }
    }

    public static void main(String[] args) {

      System.out.println(new MNOP().x + ", " + new MNOP().y);

      ABCD a = new MNOP();
      System.out.println(a.x); // 10
      System.out.println(a.y); // 20
      System.out.println(a.getName()); // MNOP
    }

在您的方案中,name对象的britishPersonUpcasted属性被BritishPerson遮蔽。

希望这有帮助。

答案 3 :(得分:1)

变量在Java中不是多态的。子类中声明的相同变量不会覆盖超类中的值。

要反映与超类关联的值,您需要将其传递给构造函数并使用super关键字设置超类变量。这样:

rake db:schema:load

以下是我修改过的代码以显示该代码。

  public ScottishPerson(String name) {
    super.name = name;
    this.name = name;
  }

答案 4 :(得分:1)

您可以在子类中声明一个与超类中的字段同名的字段,从而将其隐藏(不推荐)。

即使您需要它,也可以通过super关键字

访问它