话不多说,直接上代码。
import java.io.*;
class Main
{
public static void main (String[] args)
{
new Son().show();
}
}
class Father {
protected String name = "father";
public void show() {
System.out.println(name);
}
}
class Son extends Father {
protected String name = "son";
}
<?php
class Father {
protected $name = "father";
public function show() {
echo $this->name;
}
}
class Son extends Father {
protected $name = "son";
}
(new Son)->show();
这两个结果居然执行不一样的,最近在写一个小 demo 发现,写继承经常碰见不可预料的结果。
话说真正的答案应该是怎么样的呢???
1
lihongming 2019-08-10 17:12:38 +08:00 via iPhone
Java 变量在使用前必须声明,所以你在子类里的声明是声明了一个新的变量,不是改变父类里同名变量的值。
而 PHP 没有声明的要求,声不声明都一样。 |
2
Cbdy 2019-08-10 17:15:07 +08:00 via Android
Java 是一门很严谨的语言
|
3
AlvaIM 2019-08-10 17:16:07 +08:00
你这种学习叫死记硬背似的学习, 其实根本没有理解面向对象的实质
|
4
xlcoder166 2019-08-10 18:00:13 +08:00
Within a class, a field that has the same name as a field in the superclass hides the superclass's field, even if their types are different. Within the subclass, the field in the superclass cannot be referenced by its simple name. Instead, the field must be accessed through super. Generally speaking, we don't recommend hiding fields as it makes code difficult to read.
From this definition, member fields can not be overridden like methods. When a subclass defines a field with the same name, the subclass just declares a new field. The field in the superclass is hidden. It is NOT overridden, so it can not be accessed polymorphically. 若是你希望输出 son 你需要重写在 show 最后不要在项目中这样做 会被喷的 |
5
DavidNineRoc OP @lihongming 我并没有打算改变父级变量的名字,而是想通过父类 统一 的获取子类的字段,而不是重写,在 Java 中是不是有别的写法呢?
@Cbdy 嗯,很严谨 @AlvaIM 大哥懂得多,能像楼下说两句话有实质性的话吗? @xlcoder166 PHP 写多了,很多框架也这样子写。导致误解了。 因为子类继承基类之后,基类有一堆统一的方法操作子类。这才有多态的意义啊。不然每次都要子类重写好麻烦。 |
6
donething 2019-08-10 19:08:14 +08:00
拿本 Java 的书从头学吧,别和 PHP 比较了。
|
7
xlcoder166 2019-08-10 19:09:05 +08:00
你这个说法有歧义呀 话句话说 你究竟想获得什么预期?
子类操作基类的 Filed 还是啥 若是前者可以通过构造函数 |
8
troywinter 2019-08-10 19:40:52 +08:00
@DavidNineRoc 父类操作子类?你怕不是对面向对象有什么误解吧
|
9
troywinter 2019-08-10 19:42:59 +08:00
如果你想改变 son 的值,应该直接 this.son = "son" , 而不是重新定义它,你还是先了解一下子类的 initialization 顺序吧
|
10
kenvix 2019-08-10 19:45:29 +08:00
用 PHP 做入门语言就会被这个语言神奇的语法所迷惑。
|
11
bkmi 2019-08-10 21:14:12 +08:00
Java 不支持 override 成员变量,Kotlin 支持,每一门语音都会有一些差异,不要让老的思想禁锢了你。
|
12
nguoidiqua 2019-08-10 21:23:55 +08:00 3
多态的意义是同一个方法可以由子类进行不同的实现,然后用父类调用的时候可以表现不同的形态。
所以你这个例子本身就体现不了多态的意义,能表现的只有继承机制的意义。 你是想 show 的时候显示子类赋值的名字而已,那你直接给 name 字段改个值就是了,Java 声明并赋值和单纯赋值是有区别的,这跟 PHP 不一样。 你去反编译下 class 文件看看就知道了,如果子类没有重写父类方法的话,实际上子类是没有这个方法的,它会去引用的父类方法,字段也是如此的,没有声明的话就是没有这个字段。它运行时会先从自身寻找方法或字段,找不到就去上级类找。而父类那个 show 方法,编译后它会把参数改成 this.name,所以它打印的是一定是它自身的 name 字段。 现在你没有去改 super.name 的值,你是在子类这层新声明了一个新的 name 字段,你赋值的时候,改的只是子类这层的字段,父类不会变的。如果你没有声明新字段,而是直接赋值 this.name = "son",那么由于子类是没有这个字段的,它就回去往上找这个字段,找到父类有这个字段,然后改成 ” son “,这就能达到了你的目的。 |
13
DavidNineRoc OP @donething 从头学是应该的
@xlcoder166 抱歉,没表达清楚.因为想通过基类操作子类的属性.达到代码量的减少. @troywinter 不是改变 son 的值,比如我有一个基类窗口标题是通过 name 属性显示,我想要它的所有子类重新定义 name 值. 然后就可以通过 基类的 getName 方法获取到不一样的值. @kenvix 是有点迷 @bkmi 好的,谢谢忠告 @nguoidiqua |
14
DavidNineRoc OP @nguoidiqua 感谢, 看了文档. 了解更多了.
|
15
random0O 2019-08-10 21:58:26 +08:00 via Android
@DavidNineRoc 你需要的是在父类声明一个 abstract getName(), 然后不同子类提供不同实现,父类不必操心他们实际把值存在哪里。
|
16
DavidNineRoc OP @random0O 写多 PHP 更喜欢定义属性,而不是重写方法. 看来要改改了. 不过已经参考 12 l 的做法了.
|
17
xlcoder166 2019-08-10 22:34:11 +08:00
|
18
nguoidiqua 2019-08-10 22:42:43 +08:00
如果你非要说父类的字段我就是不要改,我就是要两个字段同时存在并打印子类新声明的同名字段,那只能重写 show,虽然一模一样……
如果你只是想要子类打出和父类不一样的值,那给字段赋值的方法很多,最简单的就是在初始化代码块里面赋值,就写两个大括号而已,不要声明,直接赋值。 class Son extends Father { { this. name = "son"; } } 其实 PHP 和 Java 的继承机制不同的,我试了下把你这个 PHP 例子里面 Father 的 name 字段直接去掉,子类依然可以正常调用 show 方法,倒是 Father 自己调会报错。我感觉 PHP 的继承好像就是把父类的字段和方法直接 include 到子类里面去,和 Java 完全不一样的。 老实说,比起它们这两者,我更喜欢 GO 那种面向对象的实现方式。 |
19
DavidNineRoc OP |