下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第7讲 构造函数与垃圾回收对象的前世今生,【学习重点】,1. 明确对象、各种变量的生存空间,2. 理解调用方法时堆栈的动态变化,3. 掌握构造函数的应用,4. 对象、各种变量的生命周期和作用域,7.1 栈与堆生存空间,对象有生有死,你必须为对象的生命循环周期负责,何时创建对象?如何创建?何时销毁对象(回收内存空间)?,栈:方法调用及局部变量(栈变量)的生存空间,堆:所有对象的生存空间,又称为垃圾回收堆,变量的有效范围?内存管理?异常处理?线程?,实例变量:声明在类中(不是方法里),存在于所属对象中,public class Dog ,int size; /每个Dog对象都会有独立的size,局
2、部变量和方法的参数:声明在方法中,生命周期仅限于方法调用至执行完毕为止(方法被放在栈上的这段期间,是暂时的),public void foo(int x) /形参x和变量i,b都是局部变量,int i = x + 3;,boolean b = true;,7.2 方法会被堆在一起,调用方法时,方法放在调用栈的栈顶。实际被堆上栈的是堆栈块,它带有方法的状态,包括执行到哪一行程序及所有的局部变量的值,栈顶的方法是目前正在执行的,方法会一直待到这里直到执行完毕,public void doStuff() ,boolean b = true;,go(4);,public void go(int x)
3、,int z = x + 24;,crazy();,public void crazy() ,char c = a;,当crazy()执行完毕,堆栈块被释放掉,7.3 对象局部变量存在栈上,public class StackRef ,public void foof() ,barf();,public void barf() ,Duck d = new Duck(13);,对象引用变量与primitive主数据类型变量都放在栈上,7.4 实例变量存放于对象所属的堆上,如果实例变量是对象的引用,则引用与对象都在堆上,实例变量有默认值,整型的默认值为0,浮点型的默认值为0.0,布尔型的默认值为f
4、alse,引用的默认值为null,7.5 对象是如何创建的,对象声明、 创建、 赋值三部曲的第三遍上映(天啦!),第1步:声明一个引用变量,Dog myDog = new Dog();,JVM分配栈空间给引用变量,并将此引用变量命名为myDog,且只允许其引用到Dog对象,或为null,第2步:创建对象(谜团:对象是如何诞生的?),Dog myDog = new Dog();,JVM分配堆空间给新建立的Dog对象,第3步:连接对象和引用,Dog myDog = new Dog();,Dog myDog = new Dog();,且慢!这不就是在调用Dog()这个方法吗?,不是,这是在调用Dog
5、的构造函数,构造函数带有在初始化对象时会执行的程序代码,即新建一个对象时就会被执行,可是我并没有写什么构造函数呀?,就算你没有写构造函数,编译器也会帮你写一个没有参数的,编译器帮你写的是,public Dog() /默认的构造函数是没有参数的,构造函数名一定要与类的名称相同,构造函数没有返回类型,而方法有返回类型,7.6 构造Dog,构造函数能够在对象被赋值给引用之前就执行,你有机会在对象被使用前介入,class Dog ,public Dog() ,System.out.println(“Wuff!Wuff!”);,public class UseADog ,public static vo
6、id main (String args) ,Dog myDog = new Dog(); /启动Dog的构造函数,7.7 新建Dog状态的初始化,使用构造函数初始化对象的状态(设置和给对象的实例变量赋值),public Dog() ,size = 34;,如果想要由使用Dog的人来决定size的值,怎么办?,使用该类的setSize()来设定大小, /构造函数介入new的过程,初始化时输出Wuff!Wuff!,class Dog ,int size; /实例变量,public Dog() /构造函数,System.out.println(“Wuff!Wuff!”);,public void
7、setSize(int dogSize) /setter方法,size = dogSize;,public class UseADog ,public static void main (String args) ,Dog myDog = new Dog();,myDog.setSize(34);,/ 新建Dog后却没有size值,你必须自行设定size大小,7.8 使用构造函数来初始化Dog的状态,class Dog ,int size;,public Dog(int dogSize) /给构造函数加上参数,System.out.println(“Wuff!Wuff!”);,size = d
8、ogSize; /使用参数值设定实例变量size,System.out.println(“size is ” + size);,public class UseADog ,public static void main (String args) ,Dog myDog = new Dog(34); /传值给构造函数, /只需上面一行就可以创建新的Dog对象并设定好size,如果对象不应在状态被初始化之前就开始使用,我们可以将初始化的程序代码放在构造函数中,然后将构造函数设定成需要参数的,7.9 Dog的简易饲养方法有参数却允许不输入的构造函数,刚才Dog的构造函数需要一个dogSize参数,但
9、如果不知道Dog的大小,难道就无法创建Dog对象吗?,创建Dog对象时提供2个选项:一个可以指定dogSize(通过构造函数的参数),另外一个使用默认值而无需指定大小,一种并不理想的方法是:,class Dog ,int size;,public Dog(int dogSize) /给构造函数加上参数,if (dogSize = 0) /传入0意味着使用默认大小,size = 27;, else ,size = dogSize;,我们可以用2种方法来创建出新的Dog对象:,class Dog ,int size;,public Dog() /无参的构造函数,指定默认值,size = 27;,p
10、ublic Dog(int dogSize) /使用参数设定,size = dogSize;, /使用2个构造函数来分辨2种选项,一种需要参数,另一种不需参数, /Dog类有一个以上的构造函数,则它们重载,参数顺序与类型必须不同,知道大小时:,Dog d1 = new Dog(15);,不知道大小时:,Dog d2 = new Dog();,重载构造函数:有一个以上的构造函数,且参数都不相同,构造函数的重载,与方法的重载是相同的,想到父类的构造函数了吗?,7.10 父类的构造函数在对象的生命中所扮演的角色,在创建新对象时,所有继承下来的构造函数都会执行,即每个父类都有一个构造函数(至少一个),
11、且每个构造函数都会在子类对象创建时期执行,由此看来,执行new指令,会启动构造函数的连锁反应,那么,抽象类有构造函数吗?提示:我们不能对抽象类执行new操作,抽象类终究是父类,因此它的构造函数将在具体子类创建出实例时执行,构造函数在执行时,第一件事是执行它的父类的构造函数,一直连锁反应到Object类,这样的过程称为“构造函数链”,创建Dog的时候,也创建了Animal与Object,class Animal ,public Animal() ,System.out.println(“Making an Animal”);,class Dog extends Animal ,public Do
12、g() ,System.out.println(“Making a Dog”);,public class TestDog ,public static void main (String args) ,System.out.println(“Starting”);,Dog myDog = new Dog();, 简单的内存分析如下:,执行new Dog()时,Dog()的构造函数进入堆栈最上方的堆栈块,Dog()调用父类的构造函数,导致Animal()的构造函数进入栈顶,Animal()调用父类的构造函数,导致Object()的构造函数进入栈顶,Object()执行完毕,它的堆栈块被弹出,接
13、着继续执行Animal(),Dog()是最早被调用的,但却是最后一个执行完毕,7.11 如何调用父类的构造函数?,Dog的构造函数会直接调用Animal()吗?,class Dog extends Animal ,int size;,public Dog(int dogSize) ,size = dogSize;,Animal();/错,调用父类构造函数的唯一方法是调用super(),在构造函数中调用super()会将父类的构造函数放在堆栈的最上方,父类的构造函数做什么?,父类的构造函数将继续调用它的父类构造函数,一路上去直到调用Object的构造函数为止,然后再一路执行,弹出回到原来的构造函
14、数,Super(); /编译器帮你加上的一定是无参的版本,/假使父类还有多个重载版本,也只有无参的版本会被调用到,你可以将父类想象成子类的父母,显然是父类先存在,因此父类的部分必须在子类创建完成之前就必须完整地成型,由于子类对象需要继承父类的实例变量和方法 ,所以父类的实例变量和方法必须先完成,父类的构造函数必须在子类的构造函数之前结束,Dog的构造函数第一个被调用(在堆栈的第一个),却是最后一个完成!,每个子类的构造函数会调用父类的构造函数,如此一路往上直到Object,Object的构造函数调用完毕后回去执行Animal的构造函数,Animal的构造函数调用完毕后回去执行Dog构造函数的剩
15、余部分,对Super()的调用必须是构造函数的第一条语句!,7.12 带参数的父类构造函数,class Animal ,private String name;,public String getName() /Dog将继承此getter,return name;,public Animal (String animalName) /带参构造函数,name = animalName; /设定name,class Dog extends Animal ,public Dog(String dogName) /此构造函数要求传实参,super(dogName); /传递给Animal的构造函数,p
16、ublic class MakeDog ,public static void main (String args) ,Dog myDog = new Dog(“WorldCup”);,System.out.println(myDog.getName());,Dog继承了getName()这个方法,但是却无法继承name实例变量,Dog靠Animal的部分维持name实例变量,然后从getName()返回值,Animal如何取得值?,唯一的办法:通过super()来引用父类,从而将 dogName的值传进去,存入私有的name实例变量中,7.13 从某个构造函数调用重载的另一构造函数,如果某个
17、重载的构造函数除了不能处理不同类型的参数外,可以处理所有工作,但我们不想让相同的程序代码出现在每个构造函数中,只想让程序代码只摆在某个构造函数中(包括对super()的调用),这样所有的构造函数都会先调用该构造函数,只要调用this()就行,this()就是对对象本身的引用,使用this()来从某个构造函数调用同一个类的另外一个构造函数,class Teddy extends Dog ,Color color;,public Teddy() ,this(Color.Red);, /此无参构造函数以某种颜色(这里用红色)调用另一构造函数,public Teddy(Color c) ,super(
18、“Teddy”);,color = c;,以上是this关键字带参数的用法,主要用于调用构造函数,避免直接以构造函数的名称来调用。,有时,我们需要this关键字不带参数的用法,代表当前所在类的对象,用于解决变量的命名冲突和不确定性问题,此时,this 出现在构造函数或方法中,用于获得当前类的对象引用。,当构造函数或方法中的局部变量和类的实例变量同名时,实例变量将被屏蔽,此时要访问实例变量,必须用this.的方式来引用,public class Dog /仅演示this关键字的使用 String name; int size; public Dog(String name) /不提倡重名的命名方
19、式 = name; public Dog(String name, int size) this(name); /执行上一构造函数中的代码 this.size = size; ,7.14 对象、变量的生命周期与作用域,对象的生命周期:依据引用变量的生命周期而定,实例变量与对象共存亡,局部变量仅存在于声明该变量的方法中,public class Animal ,public void eat() ,int grass = 1; /局部变量grass只能用在eat()方法中,sleep();, /当eat()方法结束时,局部变量grass会完全消失,public void sl
20、eep() ,grass = 30; /非法,sleep()方法无法存取grass变量, / 原因:grass变量不在sleep()方法的堆栈块中,grass变量的生命周期仅限于eat()方法 当sleep()方法执行完毕回到eat()方法中时,eat()还能使用grass变量,但一旦eat()方法执行完毕,被弹出,grass变量就死亡,public class Dog ,int size; /size在类中到处都可用,public void setSize(int dogSize) ,size = dogSize;, /方法的形参dogSize的作用域仅限于其所属的setSize()方法中,
21、局部变量的生命周期:只要局部变量的堆栈块还存在,局部变量就算活着。也就是说,活到方法执行完毕为止,局部变量的作用域:局部变量的作用域仅限于声明它的方法之内。当 此方法调用别的方法时,该变量还活着,但不在目前的范围内。执行其它方法完毕返回时,范围也就跟着回来,public void doStuff() ,boolean b = true;,go(4);,doStuff()方法运行于堆栈,局部变量b存活于其作用域内,public void go(int x) ,int z = x + 24;,crazy();,调用go()方法,局部变量x,z,b都活着,但只有局部变量b不在其作用域内,public void crazy()
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年江苏省南京市中小学编制教师招聘考试模拟试题及答案详解
- 2026年三明市三元区中小学编制教师招聘笔试参考试题及答案详解
- 2026年宁夏回族自治区固原市中小学编制教师招聘考试参考试题及答案详解
- 2026年沈阳市东陵区中小学编制教师招聘考试备考试题及答案详解
- 2026年池州市贵池区中小学编制教师招聘笔试备考试题及答案详解
- 2026年防城港市防城区中小学编制教师招聘考试备考试题及答案详解
- 2026年西安市雁塔区中小学编制教师招聘笔试备考题库及答案详解
- 2026年菏泽市牡丹区事业单位人员招聘考试模拟试题及答案详解
- 2026年兰州市七里河区中小学编制教师招聘考试模拟试题及答案详解
- 2026年台州市椒江区中小学编制教师招聘考试参考题库及答案详解
- 2025至2030中国汽车安全气囊行业市场深度调研及需求分析与投资报告
- TCECS 1853-2025 无障碍设施扶手和安全抓杆受力性能现场检测方法标准
- 2025年法律专业知识题库及答案
- 【完整版】2025年自考《马克思基本原理概论》真题及答案
- T/CNSS 013-2021吞咽障碍膳食营养管理规范
- 机关运行保障课题申报书
- 压力容器与安全培训课件
- 酒店服务礼仪知识培训
- 综合执法局执法考试试题库(附答案)
- 江西省萍乡市2024-2025学年高一下学期期末考试 英语含解析
- 福建省厦门市双十中学本校和分校联考2024-2025学年八年级下学期6月期末考试数学试卷(含答案)
评论
0/150
提交评论