Java 拾遗补阙 ----- 深入了解父类引用指向子类对象

父类应用指向子类对象指的是:

父类Animal,子类 Cat,Dog。其中Animal可以是接口或类,Cat和Dog是继承或实现Animal的子类。

Animal animal= new Cat();

声明的为父类,实际指向的是子类对象。我们先从内存角度理解。

假设Aninal父类,它里面的变量需要占用1M,它的子类Dog和Cat,需要占用0.5M内存。

 

1、通过代码看内存分配

 

Animal animal=new Animal();  // 系统将分配内存1M

Catcat = new Cat();  // 系统将分布1.5M内存!因为子类有一个隐藏引用super会指向父类实例。所以实例化子类前会先实例化一个父类。先执行父类构造函数。由于包含了父类的实例,所以s可以调用父类的方法。

Cat cat1= cat;  // 指向那1.5M内存.

Animal animalOne=(Animal)cat;  // 这时候animalOne会指向1.5M内存中1M内存,animalOne只是指向cat中实例的父类实例对象。所以animalOne职能调用父类的方法,不能调用子类的方法(存储在0.5M内存中). Cat cat2=(Cat)animal//运行时会报ClassCatException。因为animal中只有1M内存,而子类的引用都必须要有1.5M内存,所以无法转换。

Cat cat3=(Cat)animalOne;  // 这句可以通过运行,这时s3指向那1.5M的内存.由于f1是由s转换过来的,所以它是有1.5M的内存的,只是它指向的只有1M内存

以上是从内存的角度进行分析的。

 

 

2、从对象的角度看问题

 

 

我们先看几个关键词:多态,动态链接,向上转型

封装:隐藏了类的内部实现机制,可以在不影响使用者的前提下修改类的内部结构,同时保护了数据;

继承:是为了重用父类代码,子类继承父类就拥有了父类的成员。

多态:由方法的重写、重载与动态连接构成

 

理解多态,首先要知道“向上转型”(子类转为父类)。

定义了一个子类Cat,它继承了Animal类,那么后者就是前者是父类。可以通过Catc = new Cat(); 实例化一个Cat的对象,这个不难理解。但当我这样定义时:Animal a = new Cat(); 这代表什么意思呢?它表示我定义了一个Animal类型的引用,指向新建的Cat类型的对象。由于Cat是继承自它的父类Animal,所以Animal类型的引用是可以指向Cat类型的对象的。这就是“向上转型”。

 

那么这样做有什么意义呢?

因为子类是对父类的一个改进和扩充,所以一般子类在功能上较父类更强大,属性较父类更独特,定义一个父类类型的引用指向一个子类的对象既可以使用子类强大的功能,又可以抽取父类的共性。所以,父类类型的引用可以调用父类中定义的所有属性和方法,而对于子类中定义而父类中没有的方法,父类引用是无法调用的;

 

 

3、那什么是动态链接呢?

 

当父类方法子类未重写,调用父类;若子类重写父类方法,调用子类方法,这就是动态连接。

class Father{   
    Public void func1(){  
        Func2();  
    }  
    Public void fun2(){  
        System.out.println("AAA");  
    }  
}  
  
Class Child extends Father{  
  
    Public void func1(int i){  
        System.out.println("BBB");  
    }  
      
    Public void func2(){  
        System.out.println("CCC");  
    }  
}  
  
Public class Test{  
    Public static void mian(String [ ]args){  
        Father child= new Child();  
        child.func1();//打印结果将会是什么?  
        child.func1(89);//?该方法会怎样呢?  
    }  
  
  
}  

 

class Child extends Father{     
    //func1(int i)是对func1()方法的一个重载,主要不是重写!    
    public void func1(int i){     
        System.out.println("BBB");     
    }     
    //func2()重写了父类Father中的func2()方法     
    //如果父类类型的引用中调用了func2()方法,那么必然是子类中重写的这个方法     
    public void func2(){     
        System.out.println("CCC");     
    }     
}     
      
public class PolymorphismTest {     
    public static void main(String[] args) {     
        Father child = new Child();     
        child.func1();//打印结果将会是什么?      
        child.func1(68);  //由于在父类中没有定义这个方法,所以它不能被父类类型的引用调用     
                           //所以在child.func1(68)会跑出异常的   
    }     
  
}    

上面的程序是个很典型的多态的例子。子类Child继承了父类Father,并重载了父类的func1()方法,重写了父类的func2()方法。重载后的func1(inti)和func1()不再是同一个方法,由于父类中没有func1(int i),那么,父类类型的引用child就不能调用func1(inti)方法。而子类重写了func2()方法,那么父类类型的引用child在调用该方法时将会调用子类中重写的func2()。

 

 

那么该程序将会打印出什么样的结果呢?很显然,应该是“CCC”

 

小结:

 

通过以上两种方式我们认识了父类引用指向子类,其实是多态的应用,体现在以下几点

  • 使用父类类型的引用指向子类的对象
  • 该引用只能调用父类中定义的方法和变量
  • 如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用)
  • 变量不能被重写(覆盖),”重写“的概念只针对方法,当子类定义具有与父类相同名称的字段时,该子类仅声明一个新字段。超类中的字段是隐藏的。它没有被重写,所以它不能被多态访问。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值