Java 为什么变量在重写时的行为与方法不同。?
一般来说,重写是重新定义子类中成员含义的概念。在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
例如:
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; }
}