研究问题:
- java中的多继承仅适用于接口,类没有多继承,只有单继承
- 为什么java没有多继承???
- 多层继承时,有参无参构造函数的调用顺序?
- 若父类和子类的构造方法实际参数列表和参数列表长度不同,同时也没有使用super访问父类,则不能通过编译器!!!
- super与this傻傻分不清?
- 多态继承中的内存图解???多态中的对象变化内存图解???
- 继承时,父类引用指向子类对象(多态)的内存问题??以及父子类类型强制转换问题??
要点:
- 造函数时,实例化子类对象时,先调用父类构造函数,最后调用子类构造函数。
- 子类扩充父类功能时,需使用super访问父类来初始化父类成员!!
- 多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
来自 http://www.cnblogs.com/chenssy/p/3372798.html - JAVA中的多层继承
详情请见:http://download.csdn.net/download/qq_31360933/10252912 - 为什么java没有多继承???
多继承的问题在于无法找到一个合理的规则去初始化基类的数据。
菱形继承中,两个子类分别调用父类构造函数进行初始化时,到底该调用谁?都调用的话,谁先谁后?
C++的解决方案把这个问题丢给了使用者,也就是孙类。似乎是解决了问题。可是它忽视了子类并没有虚继承父类的义务的问题。如果想要组合两个自己不能修改的父类,而这两个父类恰好有公共的父类,而且又不是虚继承,就玩不转了。
所以比C++更加面向对象的Java选择放弃虚继承带来的初始化的混乱,转而用Interface去支持多继承。
Interface中没有数据对象,不存在初始化顺序的问题。仅仅是功能的组合。
- 多态继承中的内存图解???
- 多态中的对象变化内存图解???
父类引用指向子类对象时,在内存中即:栈上父类声明的一片内存指向堆上开辟出的子类对象地址。
截图展示区:
- 在Java中一共规定了四种访问控制权限:
- java中的多态分为编译期多态、运行期多态。
在编译时:参阅引用型变量所属类中是否有调用的方法。如果有。编译通过,没有编译失败。
在运行时:参阅对象所属类中是否有调用方法。
成员变量:编译看左边,运行看左边
成员方法:编译看左边,运行看右边
静态方法:编译看左边,运行看左边
(虽然静态只能被静态重写,但静态属于类的,多态时(父类引用指向子类对象)访问的还是父类。若是子类引用指向子类对象,则还是访问子类静态方法)
package com.java.DuoTai;
/*
* 静态属于类的,没有重写的说法
*/
class Fu7{
public int num=100;
public void show(){
System.out.println("show fu");
}
public void method(){
}
public static void function(){
System.out.println("function fu");
}
}
class Zi7 extends Fu7{
public int num=1000;
public int num2=200;
public void show(){
System.out.println("show zi");
}
public void method(){
System.out.println("method zi");
}
public static void function(){
System.out.println("function zi");
}
}
class DuoTaiDemo{
public static void main(String[] args){
Fu7 f=new Zi7();//多态必须有重写,非抽象子类必须重写父类方法
f.show();
f.method();
f.function();//相当于Fu7.function(),编译时Fu7中有成员方法function()通过
System.out.println(f.num);
//编译看左边,运行看左边
// System.out.println(f.num2);//编译不通过
}
}
运行结果:
3. Java多态及其继承
package com.java.DuoTai;
class A{
public void show(){
show2();
}
public void show2(){
System.out.println("啊");
}
}
class B extends A{
//有没有show()都可以,因为B可以从A中继承show(),
//B有就相当于重写,B没有就在其父类中查找
/*public void show(){
show2();
}*/
public void show2(){
System.out.println("西");
}
}
class C extends B{
public void show(){
super.show();
}
public void show2(){
System.out.println("吧");
}
protected void show3(){
System.out.println("德玛西亚");
}
}
class Demo9{
public static void main(String[] args){
A a=new B();
a.show();//B从A中继承show(),再调用自身的show2()
B b=new C();
b.show();
//C从B中继承show(),没有就继续从A中继承show(),再调用自身的show2()
// C c=new C();
// c.show3();//无法通过编译
}
}
运行结果:
4. 继承时,父类引用指向子类对象(多态)的内存问题??以及父子类类型强制转换问题??
假设现在有一个父类Father,它里面的变量需要占用1M内存.有一个它的子类Son,它里面的变量需要占用0.5M内存.
现在通过代码来看看内存的分配情况:
Father f = new Father();//系统将分配1M内存.
Son s = new Son();//系统将分配1.5M内存!因为子类中有一个隐藏的引用super会指向父类实例,所以在实例化子类之前会先实例化一个父类,也就是说会先执行父类的构造函数.由于s中包含了父类的实例,所以s可以调用父类的方法.
Son s1 = s;//s1指向那1.5M的内存.
Father f1 = (Father)s;//这时f1会指向那1.5M内存中的1M内存,即是说,f1只是指向了s中实例的父类实例对象,所以f1只能调用父类的方法(存储在1M内存中),而不能调用子类的方法(存储在0.5M内存中).
Son s2 = (Son)f;//这句代码运行时会报ClassCastException.因为f中只有1M内存,而子类的引用都必须要有1.5M的内存,所以无法转换.
Son s3 = (Son)f1;//这句可以通过运行,这时s3指向那1.5M的内存.由于f1是由s转换过来的,所以它是有1.5M的内存的,只是它指向的只有1M内存.
来自 http://blog.csdn.net/zdwzzu2006/article/details/5979886