我有一个继承自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
这就是混乱所在。向上转换ScottishPerson
到BritishPerson
会将变量名称更改为超类定义的变量名称。仅存在于子类中的方法和变量(例如warcry()
和clanName
)将被丢弃。但是,在upcasted类上调用方法salute()
仍然会返回基于子类实现的字符串。
是因为当我创建对象britishPerson
时,我只初始化BritishPerson
类,当我创建对象britishPersonUpcasted
时,我创建了BritishPerson
类和导致永久覆盖ScottishPerson
方法的salute()
类?
答案 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
关键字