类:描述生活中的一类事物,是一类事物所具备的共性内容。好比人类,动物类,车类。
对象:基于这个类的实体(实例),好比人类中的某一个具体的人,张三就是一个具体的对象,一个具体实例。他有本身的属性(年龄,性别,身高,地址等等),行为(吃饭,睡觉,学习等等),经过实例就能够调用行为功能。java
注意:类是一些相关属性与行为的集合,是对象的抽象描述,对象是类的实例。先要使用类来描述事物,才可使用类来建立对象。函数
对于人这个事物而言,通常人在出生以后就会有名字和年龄,那么这个事物一旦被建立就会有本身特定的属性。
建立一个对象的时候,若是须要建立好以后,就必须拥有一些属于本身自己特有的数据,而不是后面经过其余方式去修改,那么也就是说在建立对象的过程当中,就应该把这些数据赋值完成。学习
构造函数就是使用关键字new建立对象时,JVM会自动调用的函数,用来对对象成员变量进行初始化。测试
能够说没有构造函数就没有对象,构造函数是建立对象的。this
①javac命令,启动编译器,检查基本语法错误。而后编译源程序生成可被虚拟机执行的字节码文件(也就是class文件)spa
②java命令,启动JVM,加载class文件到方法区,找到程序入口(main方法),main方法进栈。
③ 经过new关键字,在堆内存开辟内存空间,对对象所在类的成员变量进行默认初始化,而后调用构造方法(无参构造调用无参,有参构造调有参构造)
④ 执行构造函数的隐式三步(super对父类进行初始化、对对象成员变量显示初始化、执行构造代码块)
⑤ 执行构造函数中的其它代码,其它代码执行完毕,构造函数出栈,对象建立完毕。
⑥ 把对象的内存地址值返回给栈内存开辟的引用变量空间。3d
4.1.时间不一样:
①构造函数在对象建立过程当中执行,当对象建立完毕,构造函数就结束了。②通常函数是在对象建立完毕以后,经过对象的引用(对象堆内存地址值)来调用,何时使用,何时调用。
4.2.调用次数不一样
①构造函数只要在new对象的时候,会被调用,一旦对象建立完成,咱们不能手动去调用构造函数。②通常函数能够经过对象随意的调用,没有次数限制。
4.3.互相调用问题
①在构造函数中能够调用通常的函数,可是通常函数不能调用构造函数
4.4.调用方式不一样
①构造函数是在建立对象时,由JVM自动调用②通常函数是在对象建立完毕,经过对象调用
①构造函数是用来建立对象的,它不须要书写返回值
②构造函数的名字必须和当前类名一致。
③参数列表,能够和通常函数的参数列表同样。(构造函数是以重载方式存在的)对象
默认构造函数:当咱们写一个类的时候,在这个类中不写任何的构造函数,那么在使用javac编译java源代码以后,生成class文件中,会自动添加一个没有参数的构造函数。把这个构造函数称为默认的构造函数。blog
注意:若是本身没有写无参构造,那么编译器会在class文件自动添加一个无参构造,若是本身写了构造函数(不管是有参仍是无参构造),那么编译器不会再class文件添加默认的构造函数。递归
因为一个类中能够产生多个对象,那么咱们就要知道类中的构造函数究竟是哪一个对象所调用的,咱们同时也要知道当前构造函数是给堆内存中哪一个地址中的哪一个对象的成员初始化值,因此在当前构造函数进入栈内存的时候,会在栈内存中的构造函数中生成一个隐式的this引用变量,来记录当前这个构造函数是被哪个对象调用。
1.1. 同一类中构造方法之间相互调用
通常方法调用:方法名(参数列表)。构造方法调用: this(参数列表), 表示调用本类的其它构造。
1.2. 不能相互嵌套调用,不然会是死递归。
1.3. this语句必须在构造的第一行
当有this(参数列表)的时候,就没有隐式super()了,由于初始化只能有一个,并且他俩不能公用,由于都须要放在语句的第一行,
父类的构造只要子类访问,完成父类的初始化就行(无论访问的是父类的有参仍是无参构造)。
1.4. 记录调用函数的对象地址值
this和对象有关,与类无关,谁调用this保存那个对象的地址值。
1.5. 区分局部变量和成员变量
只要是对象调用(不论是间接仍是直接),就有隐式this,来记录对象的地址值。只有保存了地址值,才能赋值调用等其余操做。静态方法中没有this,this是和对象有关的,而静态方法是和类有关的。
2..1. 构造函数之间不能相互嵌套使用,这样就致使无限制调用构造函数,致使死递归的问题。
2.2. this调用构造函数,必须放在构造函数的第一句。
咱们经过this调用其余构造函数的目的就是但愿经过其余的构造函数完成初始化动做,所以要求其余构造函数的初始化必须在本构造函数以前先完成初始化。
this:这个的意思,谁调用this就记录该对象的堆内存地址值。
注意:不论是构造函数仍是通常函数,由于都要使用对象,因此只要经过对象调用,那么在这个函数中都有一个this引用变量存在,记录当前调用这个函数的对象堆内存地址值。
package cn.jason01; /** * 这是演示构造函数和this关键字的用法 * @author Jason */ public class Student04 { private static String name; private static int age; private int number; public Student04() { // recursive constructor invocation Student03 // 递归结构调用Student03,那么会是死递归,调用只能调用有参的 // this(); this("林青霞", 27); System.out.println("⑤ 无参构造...this的地址值: " + this); show(); this.show(); } // 构造两个参数 public Student04(String name, int age) { super(); this.name = name; this.age = age; System.out.println("① 有两个参数构造...this的地址值:" + this); System.out.println("② 隐含this调用成员变量: " + name + " " + age); System.out.println("③ this调用成员变量: " + this.name + " " + this.age); System.out.println("④ 类名调成员变量: " + Student04.name + " " + Student04.age); } // 构造三个参数 public Student04(String name, int age, int number) { this(name, age); this.name = name; this.age = age; this.number = number; System.out.println("有三个参数构造...this的地址值:" + this); System.out.println("this调用成员变量 :" + name + " " + age + " " + number); } public void show() { System.out.println("⑥ show方法...this的地址值:" + this); } }
Student04Test测试类
package cn.jason01; /** * 这是测试构造函数和this关键字的类 * @author Jason * */ public class Student04Test { public static void main(String[] args) { System.out.println(".................构造函数以及this关键字的用法.................\n"); System.out.println("...................建立对象,使用无参构造...................."); Student04 s = new Student04(); System.out.println("..................无参构造完毕,建立对象完毕...................\n"); System.out.println("...................建立对象,使用有参构造...................."); Student04 s1 = new Student04("林青霞", 27, 123456); System.out.println("..................有参构造完毕,建立对象完毕...................\n"); } }
输出结果:
.....................................构造函数以及this关键字的用法..................................
.........................................建立对象,使用无参构造.........................................
① 有两个参数构造...this的地址值:cn.jason01.Student04@22aed3a5
② 隐含this调用成员变量: 林青霞 27
③ this调用成员变量: 林青霞 27
④ 类名调成员变量: 林青霞 27
⑤ 无参构造...this的地址值: cn.jason01.Student04@22aed3a5
⑥ show方法...this的地址值:cn.jason01.Student04@22aed3a5
⑥ show方法...this的地址值:cn.jason01.Student04@22aed3a5
......................................无参构造完毕,建立对象完毕.......................................
.........................................建立对象,使用有参构造.........................................
① 有两个参数构造...this的地址值:cn.jason01.Student04@3c9076d
② 隐含this调用成员变量: 林青霞 27
③ this调用成员变量: 林青霞 27
④ 类名调成员变量: 林青霞 27
有三个参数构造...this的地址值:cn.jason01.Student04@3c9076d
this调用成员变量 :林青霞 27 123456
......................................有参构造完毕,建立对象完毕......................................
注意事项:
静态变量在静态区开辟空间存储数据,先给静态成员变量默认初始化,当全部的静态成员变量默认初始化完毕,JVM又会从新开始给每个静态变量从新显示初始化(赋值初始化),这时类才加载完成。
内存图中凡是箭头指向静态区的表示:先在堆内存找,没有就在方法区找所在的类,而后在静态区找成员变量,这里并无引用指向。只有关键字new出来的对象才有地址引用。
3.内存图详解
① java命令启动JVM,JVM先加载mian函数所在的类,加载Student04Test.class字节码文件到方法区,静态区加载到静态区,非静态加载到非静态区。
②当Student04Test.class字节码文件加载完成时,程序向下执行,从方法区中把mian方法加载到栈内存,而后向下遇到Student04这个类,JVM先在方法区中找,没有就加载Student04.class字节码文件到方法区。
③④由于Student04.class中有静态成员变量,静态成员变量和成员方法、静态代码块都加载到静态区中,而后才对静态成员变量开辟空间,进行默认初始化。当全部静态成员变量默认初始化完成后,JVM又从新对静态成员变量进行显示初始化。当显示初始化完成后,全部的类文件才加载完成。
⑤建立Student04的对象,建立对象先执行右边,先在堆内存开辟空间,好比十六进制的地址值是0x12,而后对Student04的成员变量进行默认初始化,即int number=0。
⑥而后JVM自动调取Student04相对应的构造函数,那么Student04的无参构造进栈,由于有this("林青霞",27),因此就没有super,this和super不能共存在一个方法中。
⑦那么经过this("林青霞",27)访问Student04的带参构造,这时Student04的带参构造也有隐式this记录了当前对象的地址值,由于是this("林青霞",27)访问Student04的带参构造,因此间接把地址值0x12给了Student04的带参构造。把林青霞,27传参给了有参构造的局部变量name和age,由于成员变量name和age是静态static修饰,因此在堆内存中没有找到,就会去方法区中找,而且修改其值。当完成这些以后,Student04的有参构造执行完毕,出栈,就从栈内存消失。
⑧而后回到Student04的无参构造执行下一行代码show方法,那么show方法从方法区中加载到栈内存,隐式this机路地址值0x12,而且指向堆内存。
⑨show执行完毕,出栈,从栈内存消失。
⑩student04的无参也执行完毕,出栈,从内存中消失。
⑪这时student04的构造函数执行完毕,Student04的对象建立完毕。执行建立对象的左边,在main方法中给Student04开辟空间,空间名称为引用变量s,在吧地址值返回给s。
⑫main方法出栈内存,完成。
1.从上图结果能够看出,只要是对象调用的函数(方法)就存在隐式的this,用来记录哪一个对象的地址值。
2.当函数(方法)中存在局部变量和成员变量同名时,使用this就指的是成员变量,不然根据就近原则,局部变量在栈内存开辟空间,把传过来的值又覆盖本身的值,成员变量根本就没有赋值,因此没意义。