关于Java继承的一个小疑点。
关于Java继承的一个小问题。。。
其实我要说的就是 父类引用指向子类对象 ,这也没啥高大上吧
向上转型是说,在函数调用时,接收 形参的子类作为参数(实参).但是 假如子类方法覆盖了 父类的同名方法,则实际调用的还是子类的方法,不会调用父类的方法. 即,向上转型不会真正的把子类对象转换成父类对象(更不会转型成一个接口了,所以 "Hero的对象h向上转型为一个Canfight" 这个是错的). 这里就用到了多态的概念. 楼主这种用法确实是向上转型,但是 了解了 多态的概念,应该就不会出现文中楼主所述的困惑了. 说3楼的 高大上, 是因为,楼主看了3楼的回答不但不能理解,反而会更加困惑. 比如,在Hero里面再实现一个
public void fight() {
System.out.println("Fight from Hero");
}
这样,楼主可能有会困惑了.
今天看Java 编程思想的时候遇见一个问题,运行的结果和自己想想的完全不一样。先把代码贴出来!
//CanFight接口 interface Canfight { void fight(); } //ActionCharacter类 class ActionCharacter { public void fight() { System.out.println("Fight from ActionCharacter"); } } //Hero类继承ActionCharacter类实现Canfight接口 class Hero extends ActionCharacter implements Canfight { public void swin() {} public void fly() {} } public class Adventure { //参数为Canfight,向上转型,调用fight方法 public static void t(Canfight x) { x.fight(); } //参数为ActionCharacter类型,向上转型,调用fight方法 public static void w(ActionCharacter x) { x.fight(); } public static void main(String[] srgs) { Hero h = new Hero(); t(h); w(h); } } /*运行结果 Fight from ActionCharacter Fight from ActionCharacter */
在main方法中,调用t方法时,Hero的对象h向上转型为一个Canfight,然后在调用Canfight的fight方法,由于fight方法没有具体的实现,我认为应该不会有输出或者编译器报错。
事实结果应该是 Hero继承ActionCharacter,在运行时,将Hero中所有在ActionCharacter中能用到的东西全部复制到ActionCharacter中,这样在ActionCharacter类中就有了一个fight方法的具体实现。从另外一个角度讲就是在ActionCharacter类中有了接口Canfight中的fight方法的实现。
我自己分析的是这样的,希望大神给出指点。。。
1 楼
cs6641468
昨天
肯定是这样的,不然编译阶段就报错了。
2 楼
devilyard
昨天
Hero继承了ActionCharacter,当然ActionCharacter 中的public方法使用子类Hero也是可以调用的,你可以认为Hero自己有了一个fight方法,当Hero再实现一个Canfight接口的时候自然也就有了一个实现。
3 楼
fsplove520
昨天
小哥,你这样理解完全是错误的!可能你对内存分配管理方面还不太了解。在这个过程中,不管是ActionCharacter x 还是 Canfight x 他们都是都是指向同一份内存的引用,故2个x.fight(); 都是跑的同一个函数内存栈。
你可以试着打印下这3个变量,看看输出对象是不是一样的。
你可以试着打印下这3个变量,看看输出对象是不是一样的。
4 楼
jackyin5918
18 小时前
"在main方法中,调用t方法时,Hero的对象h向上转型为一个Canfight,然后在调用Canfight的fight方法,由于fight方法没有具体的实现,我认为应该不会有输出或者编译器报错。" -- 楼主的理解不正确,这里不是转型
这里用到的概念应该是多态. 可以简单理解成: 函数的参数(形参) 是一个接口类型. 调用函数时,传递的 实参 是 形参的 具体实现类, 则调用的是实参 本身类型的方法. 比如 interface C { methodC; }
class A implemet C { println("A"); }
class B implemet C { println("B"); }
上面接口C的两个实现类A B, 如果一个参数(形参)是C类型的,A和B的示例都可以作为实参,
然后调用的分别是 A和B的println 方法.
ps 3楼放出 内存管理模型 这个 也太高大上了吧
这里用到的概念应该是多态. 可以简单理解成: 函数的参数(形参) 是一个接口类型. 调用函数时,传递的 实参 是 形参的 具体实现类, 则调用的是实参 本身类型的方法. 比如 interface C { methodC; }
class A implemet C { println("A"); }
class B implemet C { println("B"); }
上面接口C的两个实现类A B, 如果一个参数(形参)是C类型的,A和B的示例都可以作为实参,
然后调用的分别是 A和B的println 方法.
ps 3楼放出 内存管理模型 这个 也太高大上了吧
5 楼
fsplove520
18 小时前
jackyin5918 写道
"在main方法中,调用t方法时,Hero的对象h向上转型为一个Canfight,然后在调用Canfight的fight方法,由于fight方法没有具体的实现,我认为应该不会有输出或者编译器报错。" -- 楼主的理解不正确,这里不是转型
这里用到的概念应该是多态. 可以简单理解成: 函数的参数(形参) 是一个接口类型. 调用函数时,传递的 实参 是 形参的 具体实现类, 则调用的是实参 本身类型的方法. 比如 interface C { methodC; }
class A implemet C { println("A"); }
class B implemet C { println("B"); }
上面接口C的两个实现类A B, 如果一个参数(形参)是C类型的,A和B的示例都可以作为实参,
然后调用的分别是 A和B的println 方法.
ps 3楼放出 内存管理模型 这个 也太高大上了吧
这里用到的概念应该是多态. 可以简单理解成: 函数的参数(形参) 是一个接口类型. 调用函数时,传递的 实参 是 形参的 具体实现类, 则调用的是实参 本身类型的方法. 比如 interface C { methodC; }
class A implemet C { println("A"); }
class B implemet C { println("B"); }
上面接口C的两个实现类A B, 如果一个参数(形参)是C类型的,A和B的示例都可以作为实参,
然后调用的分别是 A和B的println 方法.
ps 3楼放出 内存管理模型 这个 也太高大上了吧
其实我要说的就是 父类引用指向子类对象 ,这也没啥高大上吧
6 楼
fsplove520
18 小时前
就是LZ说的 向上转型
7 楼
jackyin5918
17 小时前
fsplove520 写道
就是LZ说的 向上转型
向上转型是说,在函数调用时,接收 形参的子类作为参数(实参).但是 假如子类方法覆盖了 父类的同名方法,则实际调用的还是子类的方法,不会调用父类的方法. 即,向上转型不会真正的把子类对象转换成父类对象(更不会转型成一个接口了,所以 "Hero的对象h向上转型为一个Canfight" 这个是错的). 这里就用到了多态的概念. 楼主这种用法确实是向上转型,但是 了解了 多态的概念,应该就不会出现文中楼主所述的困惑了. 说3楼的 高大上, 是因为,楼主看了3楼的回答不但不能理解,反而会更加困惑. 比如,在Hero里面再实现一个
public void fight() {
System.out.println("Fight from Hero");
}
这样,楼主可能有会困惑了.
8 楼
elliotann
13 小时前
我的理解,当接口中,声明了一个方法,而继承中,实现了这个方法,3楼说的也没错,这种调用方法确实是同一内在的引用,所以打印一样
9 楼
thc1987
1 小时前
可以简单的理解成
当调用x.fight()时,在Hero中找有没有fight()方法,如果有就执行,如果没有就在其父类中找,如果有就执行.
当调用x.fight()时,在Hero中找有没有fight()方法,如果有就执行,如果没有就在其父类中找,如果有就执行.