java的继承内存机制_第二章:java面向对象之对象内存的管理和继承上篇(3)

详细介绍请查看(全选链接黏贴至浏览器阅读,介绍更为详细,小便也是对其进行总结和实例演示罢了):

http://pdf7.tarena.com.cn/tts8_source/ttsPage/JAVA/JSD_V05/OOP/DAY03/SUPERDOC/01/index.html#Key02

继承之泛化的过程:

前面的案例中定义了T类和J类, 通过分析可以发现, 在这两个类中存在着大量的重复代码,像cells属性、print方法、drop方法、moveLeft方法、moveRight方法,在这两个类中都存在,并且实现上基本也是相同的,本着代码重用的原则,可以使用继承的方式来实现。

首先,构建T类和J类的父类Tetromino类,将公共的(T类和J类公有的)信息存放在父类中, T类和J类继承Tetromino父类。此时,子类即可以共享父类的数据。这个过程就是泛化的过程。

extends关键字:

使用继承可以实现代码的重用,在java语言中,需要通过extends关键字实现类的继承。继承完成后,子类(Sub class)可以继承父类(Super class)的成员变量及成员方法,同时子类也可以定义自己的成员变量和成员方法。届时,子类将具有父类的成员及本类的成员。

需要注意的是,Java语言不支持多重继承,即:一个类只能继承一个父类,但一个父类可以有多个子类。看下面的代码:

19f700053bc0d56bdef3.jpg

如上代码说明:声明父类Tetromino,将公共信息放在其中,包括Cell[]声明、drop()方法、moveLeft()方法、moveRight()方法,print()方法。声明无参构造函数,对成员变量Cell数组进行实例化。声明子类TetrominoT继承Tetromino,并声明有参构造函数,传递行row,列col参数,进行T型数组元素的初始化。

下面在main方法中,声明一个T型对象,即可以实现T型对象的构建:

19f50005304eb5ffada1.jpg

上面的代码,在创建子类对象时,调用了子类的有参构造函数进行数据的初始化,试想下,父类Tetromino的无参构造函数执行了吗?通过分析可以肯定的是,父类的无参构造函数被执行了。在程序中并没有声明父类的构造函数,那它是如何执行的呢?

继承中构造方法:

父类的无参构造方法之所以被执行,是因为java规定,子类在构造之前必须先构造父类。

事实上,子类的构造方法中是必须要通过super关键字来调用父类的构造方法的,这样才可以保证妥善的初始化继承自父类的成员变量。

但是看上一个案例中的代码并没有super调用父类构造方法,那是因为,如果子类的构造方法中没有调用父类的构造方法,则java编译器会自动的加入对父类无参构造方法的调用。请看如下代码,演示了super关键字的用法:

19f800052fa81f6f93b6.jpg

上面的代码中,super();为编译器自动加入的,并且super关键字必须位于子类构造方法的第一行,否则会有编译错误。

另外一点需要注意的是,若父类没有提供无参的构造方法,则会出现编译错误。请看如下的示例:

19f40006e49746df5fbe.jpg

分析上面的代码,在子类构造方法中没有写super调用父类构造方法,这时编译器会默认添加super()来调用父类的无参构造方法,但是父类中又没有定义无参的构造方法,因此会发生编译错误。

针对上面的问题,可以有两种解决方案,方案一为在父类中添加无参的构造方法,方案二为在子类构造方法中显示调用父类的有参构造方法(常常使用),这样可以保证父类的成员变量均被初始化,参见下面的代码:

19f8000536f66d8ed5d8.jpg

如上的代码,在子类中调用了父类的构造方法,初始化了继承自父类的value成员变量,编译正确。

父类的引用指向子类的对象:

一个子类的对象可以向上造型为父类的类型。即,定义父类型的引用可以指向子类的对象。看如下代码所示:

19f2000538ef60abb9dd.jpg

上面的代码,在main方法中,声明了父类型的引用来指向子类型的对象。但是通过父类的引用只能访问父类所定义的成员,而不能访问子类所扩展的部分。看下面的代码:

19f50005388043e16c45.jpg

分析上面的代码,在main方法中,声明父类型的引用指向了子类的对象,而后,访问父类的成员变量value及调用父类的方法f,均可以正常编译。但是,当通过obj引用访问num变量及g的方法时,会出现编译错误。那是因为,当用父类型引用指向了子类对象后,java编译器会根据引用的类型(Foo),而不是对象的类型(Goo)来检查调用的方法是否匹配。

总结:

1.java虚拟机在内存空间开辟了一个称为堆的存储空间,这部分空间用于存储使用new关键字所创建的对象。

Cell c = new Cell( ) ;

19f200053a41f7e9291d.jpg

new cell( );所创建的对象在堆中分配,并赋值为0。 引用类型变量在栈内存中分配。

2.成员变量的生命周期:如上代码。堆中的cell需要栈中的c来引用,那么当一个对象没有任何引用时,该对象被视为废弃对象,属于被回收的范围,同时该对象中的所有成员变量也随之被gc回收,所以,成员变量的生命首期为:从对象在堆中创建开始到脱离引用被回收结束,

3.垃圾回收机制:垃圾回收器(GC)JVM自带的一个线程,用于回收没有任何引用所指向的对象。gc会从栈内存中开始跟踪,从而判定哪些内存是正在使用的,若gc无法跟踪到某一块内存,那么gc就会认为这块内存不再使用了,即是可回收的,gc全程自动管理。

4.java中的内存泄露问题:指不再被使用的内存没有被及时回收,占用内存从而导致程序崩溃,

5.栈内存:JVM开辟了一个称为栈的空间,这部分空间用于存储程序运行时在方法中声明的所以的局部变量,

Cell c = new Cell( );

int num = 5;

19f90006decf2333c4ee.jpg

6.局部变量的生命周期:方法调用完成之后。

7.成员变量和局部变量的区别:

成员变量:1.定义在类中,方法外,2.由系统设定默认值,可以不显示初始化。3.所在类被实例化后存在堆中,对象被回收时,成员变量失效。

局部变量:1.定义在方法中,2.没有默认值,必须自行设定初始值,3.方法被调用时,存在栈中,方法调用结束后,从栈中清除。

8.继承:泛化的过程,将公共的信息存放在父类中,子类继承父类,这时子类即可共享父类的数据。当两个类中存在大量的重复代码时,并且实现上基本也是相同的,本着代码重用的原则,可以使用继承,同过extends关键字实现类的继承,继承完成后,如上所述,子类可以继承父类的成员变量和方法,同时子类也可以定义自己的成员变量和方法,届时,子类将具有父类及自己的成员变量和成员方法。

需要注意的是:java不支持多重继承,即只可以有一个爸爸,但一个父类可以有多个子类继承它。

9.继承中的构造方法:子类的构造方法中是必须要通过super关键字来调用父类的构造方法的,这样才可以保证妥善的初始化继承自父类的成员变量。如果子类的构造方法中没有调用父类的构造方法,java编译器会自动的加入对父类无参构造方法的调用,如果父类没有无参的构造方法,那么会编译出错,解决办法有两个:

1.在父类中添加无参的构造器,

2.在子类构造器中使用super()调用父类有参构造器。

19f40006e71762144855.jpg

10.向上造型:一个子类的对象可以向上造型为父类的类型,即定义父类型的引用可以指向子类的对象.

用途:可以用来用父类定义变量引用多种子类对象,可以大大提高程序的可扩展性,

面向对象的三大特性:封装,继承,多态,而向上造型可以看成是多态的一种体现,即允许一种类型有不同的实现,

19f200053af2dfa621ca.jpg

案例2:

19f1000555bf71e3e529.jpg

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值