关于Java继承的一个小疑点。

关于Java继承的一个小问题。。。

今天看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个变量,看看输出对象是不是一样的。
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楼放出 内存管理模型 这个 也太高大上了吧
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楼放出 内存管理模型 这个 也太高大上了吧


其实我要说的就是 父类引用指向子类对象 ,这也没啥高大上吧
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()方法,如果有就执行,如果没有就在其父类中找,如果有就执行.