在Java中调用继承的方法

时间:2018-06-20 05:17:55

标签: java

我有以下Java代码,

class Animal {
    private String name="Animal";

    public String getName() {
        return name;
    }
}

class Cat extends Animal {
    private String name = "Cat";
}

public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();
        System.out.println(cat.getName());
    }
}

运行该代码后,我得到了输出Animal,但我认为它应该是Cat。在像这样在getName中覆盖Cat方法之后,我得到了Cat

@Override
public String getName() {
    return name;
}

那是因为在子类实例中调用继承的(而不是覆盖的)方法就像cat.getName()等于调用super.getName()(因此,我得到Animal而不是Cat第一种情况)?还是因为实例变量隐藏的奇怪行为(我不太确定)?

6 个答案:

答案 0 :(得分:2)

在子类中重新声明了name字段,但是在父级中实现了方法getName时,唯一要读取的字段是父级Animal.name

在子类中声明在超类中声明的字段始终是一个坏主意,因为字段不会被“覆盖”,而只是被隐藏。

您打算做的是以下其中一项:

覆盖方法:

class Animal {
    private String name="Animal";

    public String getName() {
        return this.name;
    }
}

class Cat extends Animal {
    public String getName() {
        return "Cat";
    }
}

您还可以在子类中声明其他字段,但这仍然不是一个好主意。做到这一点的“正确”方法是重写方法。

或者,将字段暴露给子类,然后更改子类的值:

class Animal {
    protected String name = "Animal";

    public String getName() {
        return name;
    }
}

class Cat extends Animal {
    public Cat() {
        this.name = "Cat";
    }
}

这样,就不会混淆哪个字段存储实际值,并且很清楚“覆盖”发生在哪里。

答案 1 :(得分:0)

在Cat类中添加一个具有相同名称的私有作用域变量并不会掩盖Animal类中的变量。要更改行为,您需要重写accessor方法以从Cat类上下文读取变量。

答案 2 :(得分:0)

您可以重载方法,而不是数据成员。 Animal.nameCat.name是两个不同的数据成员。 Animal.getName()没什么特别的-它返回Animal.name,并且完全不知道Cat.name

一种可能的方法是只拥有一个数据成员Animal.name,并让每个类以不同的方式初始化它。例如:

class Animal {
    private String name;

    public Animal() {
        this("Animal);
    }

    protected Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

class Cat extends Animal {
    public Cat() {
        this("Cat');
    }
}

或者,如果您想依靠类名,可以只使用getSimpleName

class Animal {
    private String name;

    public Animal() {
        name = getClass().getSimpleName();
    }

    public String getName() {
        return name;
    }
}

class Cat extends Animal {
}

答案 3 :(得分:0)

这是因为cat.getName()调用getName()类中的Animal方法,该方法只知道自己的 name字段,而不是一个子类。

可能的解决方案可能是:

class Animal {
    private String name = "Animal";

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

class Cat extends Animal {
    private String name = "Cat";

    public Cat() {
        setName(name);    
    }
}

public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();
        System.out.println(cat.getName());
    }
}

我不鼓励您重写方法,因为您应该在以后的每个Animal子类中使用它。

答案 4 :(得分:0)

  

您需要重写方法getName()。它是实例级别   您可以在子类中调用它的函数,但不能对其进行修改   而不覆盖功能。所以它正在调用父类函数   具有父类属性。

     

如果要在输出中显示“ cat”,请覆盖该方法。

答案 5 :(得分:0)

可接受的答案涵盖了一些好的答案,但是我想补充一些内容。

  1. 如果您要执行完全相同的操作,则不建议在Cat类中添加重写的getName方法。这是为了防止您可能创建的任何其他子类中的代码重复。
  2. 您可以创建一个构造函数来初始化名称字段,然后将名称字段切换为protected。

例如

class Animal {
    protected String name;

    public Animal() {
        this.name = "Animal";
    }

    public String getName() {
        return this.name;
    }
}

class Cat extends Animal {
    public Cat() {
        this.name = "Cat";
    }
}

  1. 或者,如果要将名称字段保持私有,则可以创建一个受保护的setter方法,以仅允许子类设置名称。

例如

class Animal {
    private String name = "Animal";

    public String getName() {
        return this.name;
    }

    protected void setName(String name) {
        this.name = name;
    }
}

class Cat extends Animal {
    public Cat() {
        setName("Cat");
    }
}