Java中子类可以继承父类的属性和方法,那么子类对象就可以直接使用父类对象的属性和方法,实现机制就是,当某个子类对象实例化的时候,会首先实 例化一个其父类对象,但这个父类对象对外不可见,只能通过子类中的super来访问;以此类推,父类对象初始化前又会先初始化它的父类对象......直 至初始化Object对象为止。这样的效果就是,新建一个类的实例实际上得到的是一个对象的“链条”,通过关键字super连接的对象链条。子类对象就可以通过super来访问到所有它继承到的东西。
为了实现这样的初始化动作,应该在每个类的构造器中所有代码的前面先初始化这个类的直接父类对象。
但是事实上,我们平时写代码的时候,构造器中多数没有写过父类对象初始化的语句,甚至很多时候,连构造器都不写。但是程序依然正常运行,为了一探究竟,我用DJ Java Decompiler工具来反编译class文件,查看内部细节。
Parent类,没有写任何构造器,
1. package
2. public class
3.
4. }
反编译该类文件,可以看到,Java编译时看到程序没有写任何构造器,就会自动加上一个“空”的无参构造器,(若程序中已定义构造器,不论有参无参,这个“空”的无参构造器就不会自动产生)
1. // Decompiled by DJ v3.9.9.91 Copyright 2005 Atanas Neshkov Date: 2010-4-2 14:44:26
2. // Home Page : http://members.fortunecity.com/neshkov/dj.html - Check often for new version!
3. // Decompiler options: packimports(3)
4. // Source File Name: Parent.java
5. package
6.
7. public class
8. {
9. public
10. {
11. }
12. }
我们现在定义一个子类Son,继承这个Parent类
1. package aa;
2. public class
3. public
4. }
5. }
这里子类Son的构造器中没有写任何的实例化父类的语句,反编译的程序中也没有,但是我们查看class文件内容
1. // Decompiled by DJ v3.9.9.91 Copyright 2005 Atanas Neshkov Date: 2010-4-2 14:53:01
2. // Home Page : http://members.fortunecity.com/neshkov/dj.html - Check often for new version!
3. // Decompiler options: packimports(3) disassembler
4. // Source File Name: Son.java
5. package
6.
7. // Referenced classes of package aa:
8. // Parent
9. public class Son extends
10. {
11. public
12. {
13. // 0 0:aload_0
14. // 1 1:invokespecial #8 <Method void Parent()>
15. // 2 4:return
16. }
17. }
可以看到在Son的构造器内部,并不是空的,第二条的指令就是调用父类的构造器 Method void Parent(),相当于Son的构造器里面写了一条super(); 这里编译器自动加的是父类的无参构造器,而不管父类究竟是否有无参构造器,这也正是父类没有无参构造器(程序员写了一个带参数的构造器,编译器就不再自动 添加一个“空”的无参构造器)时,子类构造器中若不显示初始化父类对象,编译器就会报错的原因。(因为子类构造器中没有初始化父类对象的语句,所以编译器 自动为子类构造器添加了一个调用父类无参构造器的指令,但是父类没有无参构造器,找不到指定的方法,便会报错)
所以正常情况下,我们可以不写构造器(编译器会帮我们加一个),在构造器中我们也不必显示初始化父类对象(编译器会帮我们调用父类无参构造器),但这不代表程序中就真的可以没有。
当创建一个个对象时,系统会该对象的属性默认初始化,基本类型属性的值为0(数值类型),false(布尔类型),把所有的引用类型设置为null.
构造器可以改变这种默认的初始化。
构造器的作用:是创建java对象的重要途径,是不是说构造器完全负责创建java对象?????
答:是创建java对象的重要途径,通过new关键字调用构造器时,构造器也确实返回了该类的对象,但这个对象并不是完全由构造器负责创建的。
系统调用构造器时的执行过程分析:
当调用构造器时,系统会为该对象分配内存空间,并对该对象进行默认的初始化,这个对象已经产生了,---------------------------------------》这些操作在构造器执行 之前已经完成了。也就是在构造器的执行体执行之前,系统已经创建了一个对象,只是这个对象还不能被外部程序访问,只能在构造器中,通过this引用它,当构造器的执行体结束之后,这个对象作为该构造器的返回值被返回,同时还赋给另一个引用类型的变量。从而外部程序可以访问该对象。
个人理解:构造器作用,1.创建java对象的重要途径。2.对系统产生的对象初始化 。3.并将该对象作为返回值返回,是外部程序可以访问。
一个类中构造器之间的相互调用(一个构造器调用另一个构造的初始化代码):构造器不能直接调用,必须使用new关键字调用,但是会导致系统重新创建一个对象。为了避免重新创建对象,可以使用this关键字来调用相应的构造器
this调用另一个构造器,只能在构造器中使用,而且必须作为构造器语句的第一条语句。
super是java提供的一个关键字,是直接父类的引用。java程序创建某个类得对象时,会隐式的创建该类的父类对象,只要有一个子类对象存在,则一定存在一个与之对应的父类对 象。
this,super:不能出现在static修饰的方法中,static修饰的方法是属于类得,该方法的调用者是类而不是对象,也就不存在对应的对象以及父对象了,所以this,super引用就失去了意义。
使用super调用父类构造器必须出现在子类构造器的第一行。所以this调用和super调用不会同时出现。
子类构造器调用父类构造器的几种情况:
1.子类构造器的执行体的第一行用super显式调用父类构造器,系统将根据super 调用里传入的实例列表调用父类对应的构造器
2.子类构造器执行体的第一行是this显式调用本类中重载的构造器,系统根据this调用里传入的实参列表调用本类中另一个构造器,执行本类中另一个构造器时,既会调用父类的构造器。
3.子类构造器中既没有this,也没有super,系统将会在执行子类构造器之前隐式调用父类无参的构造器
不管上面哪种情况,当调用子类构造器来初始化子类对象时,父类构造器总会在子类构造器之前执行,不仅如此,执行父类构造器时,系统会再次上溯执行其父类的构造器。。。。以此类推。创建任何java对象,最先执行的总是java.lang.Object类得构造器