Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/387.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么变量在重写时的行为与方法不同。?_Java_Inheritance_Overriding - Fatal编程技术网

Java 为什么变量在重写时的行为与方法不同。?

Java 为什么变量在重写时的行为与方法不同。?,java,inheritance,overriding,Java,Inheritance,Overriding,一般来说,重写是重新定义子类中成员含义的概念。在java中重写时,为什么变量的行为不像方法? 例如: class Base { int a = 10; void display() { System.out.println("Inside Base :"); } } class Derived extends Base { int a = 99; @Override // method overriding voi

一般来说,重写是重新定义子类中成员含义的概念。在java中重写时,为什么变量的行为不像方法?
例如:

class Base {

    int a = 10;

    void display() {
        System.out.println("Inside Base :");
    }
}

class Derived extends Base {

    int a = 99;

    @Override
    // method overriding
    void display() {
        System.out.println("Inside Derived :");
    }
}

public class NewClass {

    public static void main(String... a) {
        Derived d = new Derived();
        Base b = d;
        b.display(); // Dynamic method dispatch
        System.out.println("a=" + b.a);
    }
}
由于指定了数据成员
a
的包访问权限,因此
派生的
类也可以使用它。但通常,在使用基类引用调用重写的方法时,会调用在派生类中重新定义的方法(动态方法调度)…但变量的情况不同..为什么

预期产量

内部派生:
a=99

获得的产量:

内部派生:
a=10

打印10-为什么变量的行为与派生类中的方法不同?

为什么不允许在子类中重写变量?

无法重写类变量。在Java中不重写类变量,而是隐藏它们。重写的是实例方法。

您键入的
b
Base
的实例。因此,当编译器需要解析
b.a
时,它会查看
Base
的定义以了解
b.a
的含义。实例字段没有多态性。

因为多态性在Java中唯一适用的是实例方法

因此,既不能覆盖静态成员,也不能覆盖实例成员字段。如果将这些成员放在具有相同名称的派生类中,则只需使用新定义隐藏它们

System.out.println("a="+b.a);

虽然,
Base b
可能指向子类对象(在运行时),但上面的
a
在编译时已经绑定到
Base
类(静态绑定)。因此,它打印10个变量。

变量的行为是这样的,因为它们缺少行为。换句话说,变量是被动的


对于变量的定义,派生类不能通过重写来合理更改:

  • 它不能更改其类型,因为这样做可能会破坏基类的方法
  • 它不能降低其可见性,因为这将打破替代原则
  • 如果不使它对基类无用,它就不能使它成为final

因此,在派生类中声明的成员变量会隐藏基类中的变量。

答案与变量作用域有关,而不是多态性。换句话说,您正在类范围中重写该变量。因此,
d.a
将在
Derived
的类范围内返回变量,而
b.a
将在
Base
的类范围内返回变量。

在这种情况下,编写getter方法可能是一个好主意:


现在您可以在派生类中重写它。

首先,我们不重写任何类变量。方法而已

其次,如果您希望看到变量值已被更新或替换,则应该将其声明为“static int”而不是“int”。通过这种方式,它将在每个人共享同一个变量的情况下工作,并在其上添加新值

第三,如果您希望看到变量值的赋值和使用方式有所不同,您可以将其设计为在构造函数中传递参数,或类似的东西,以使其按照您的意愿相应地工作。

在面向对象编程(OOP)中其思想是将数据隐藏在对象中,让对象只与调用方法通信。这就是变量不能重载的原因,事实上它们是“作用域”/“附加”到特定类的

此外,派生类不应再次定义a,它已在基类中定义,因此只需将对象上的a设置为所需的值,例如:

class Base {
    private int a = 10;
    public int getA() { return a; }
    public void setA(inta) { this.a = a; }
}

class Derived extends Base {
    // adding new variables, override methods, ...
}

// then later:

Derived d = new Derived();
d.setA(99); // override the default value 10

如果变量可以覆盖其他变量,会发生什么情况?突然,您的类必须知道父类正在使用哪些变量,以免您意外地重写一个变量,并破坏父类中正在使用的任何变量。封装的全部目的是避免对另一个对象的内部状态有那种亲密的了解。因此,变量会隐藏相同名称的其他变量,而您看到的变量取决于您试图通过什么类型访问变量

不过还是有希望的。如果您只想重写该值,则不必重新声明该变量。只需更改init块中的值。如果您这样做损害了基类,那么它为该变量选择了错误的可见性

class Base {
    int a = 10;
}

class Derived extends Base {
    { a = 99; }
}
当然,这对
final
变量不太有效

  • 我们不重写任何类变量。方法而已
  • 如果希望看到变量值已更新,或 替换后,您应该将其声明为“static int”,而不是 “int”。通过这种方式,它将发挥作用,因为每个人都共享相同的资源 变量,并将在其上添加新值
  • 如果您希望看到变量值被赋值,并且 使用不同的方法,可以将其设计为传入参数 构造器,或类似的东西,使其按照 你想要的

  • 此外,如果变量被重写了,那么父类本身就剩下了什么,如果java允许更改父类变量的值,那么就破坏了类的安全性。

    …因为java就是这样设计的吗?请看这个相关的SO问题:我认为很好理解它是如何工作的,但您的示例正是您不应该将包私有成员与继承混合的原因。如果您将其中一个类移动到另一个包中,您的代码将表现出不同的行为,这一事实违反了最不令人惊讶的原则,并且会导致代码不透明。您不能重写字段,只能将其隐藏。“派生类无法通过重写合理更改变量”-哦,是的,有-值-
    Base{String name;print(){sysout(name);}}}派生的{String
    
    class Base {
        int a = 10;
    }
    
    class Derived extends Base {
        { a = 99; }
    }