Java中构造函数详解
1.构造函数的概念和一般使用
构造函数:创建构造对象时调用的函数。
作用:可以给对象经行初始化。(创建对象都必须要通过构造函数初始化)
1.一个类中如果没有定义过构造函数,那么该类中会有一个默认的空参数构造函数。
2.如果在类中定义了指定的构造函数那么类中的默认构造函数就没有了。
3.构造函数可以有多个,用于对不同的对象进行针对性的初始化。
4.多个构造函数在类中是以重载的形式来体现的。
什么时候定义构造函数呢?
在描述事物时,该事物一存在就具备的一些内容,这些内容都定义在构造函数中。
一般函数和构造函数的区别?
构造函数:对象创建时,就会调用与之对应的构造函数,对对象经行初始化。
一般函数:对象创建后,需要函数功能时才调用。
构造函数:对象 创建时,会调用只调用一次。
一般函数:对象创建后,可以被调用多次。
细节:
1.一般函数不能直接调用构造函数。
2.构造函数前面如果加了void就变成了一般函数。
3.构造函数中是有return语句的。
2.构造函数的使用特点。
(1)构造方法的方法名必须与类名相同。
(2)构造方法没有返回类型,也不能定义为void,在方法名前面不声明方法类型。
(3)构造方法的主要作用是完成对象的初始化工作,它能够把定义对象时的参数传给对象的域。
(4)一个类可以定义多个构造方法,如果在定义类时没有定义构造方法,则编译系统会自动插入一个无参数的默认构造器,这个构造器不执行任何代码。
(5)构造方法可以重载,以参数的个数,类型,顺序。
以下简单的代码,有助于大家理解:
class Person{
private String name;
private int age;
//定义个一个person类的构造函数
Person(){//构造函数,是空参数的
name = "zhangsan";
age = 1;
System.out.println("Person run");
}
//如果有的人一出生就有名字
Person(String n){
name = n;
}
public void setName(String n){
name = n;
}
Person(String n, int a){
name = n;
age = a;
}
public void show(){
System.out.println(name + ":" + age);
}
}
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
Person p = new Person();
p.show();
Person p1 = new Person("lisi");
p1.setName("wangwu");
p1.show();
Person p2 = new Person("xiaoming", 22);
p2.show();
}
}
运行结果:
3.java构造函数关于子父类间的继承问题
(1)子类只继承父类的默认(缺省)构造函数,即无形参构造函数。如果父类没有默认构造函数,那子类不能从父类继承默认构造函数。
(2)子类从父类处继承来的父类默认构造函数,不能成为子类的默认构造函数。
(3)在创建对象时,先调用父类默认构造函数对对象进行初始化,然后调用子类自身自己定义的构造函数。
(4)如果子类想调用父类的非默认构造函数,则必须使用super来实现。
(5)子类必须调用父类的构造函数。可以通过系统自动调用父类的默认构造函数,如果父类没有默认构造函数时,子类构造函数必须通过super调用父类的构造函数。
在类的一般方法里都有默认:this 用于指向当前对象,对应在构造函数中都有隐式的:super 用于指向父类。
构造函数格式:
A.在调用构造函数时,会先执行super 进入父类的构造函数初始化父类,再返回子类的构造函数,将子类的对象显示初始化
class Fu{
int num=3;
Fu(){//构造函数
System.out.println("Fu!");
}
}
class Zi extends Fu{
int num=4;
Zi() {
System.out.println("Zi!");
}
}
public class extendsBasic {
public static void main(String[] args) {
new Zi();
}
}
输出:Fu! Zi!
结论:在继承关系中子类会有一个super 标志父类(标志谁是它的父类)
B.当父类没有默认构造函数(自定义了有参数列表的构造函数)在子类的构造函数内需要显式的super (参数);显示初始化父类
class Fu{
int num=3;
Fu(int x){//构造函数有参数列表
System.out.println("Fu!"+x);
}
}
class Zi extends Fu{
int num=4;
Zi() {//子类的构造函数
super(8);//显式构造父类
System.out.println("Zi!");
}
}
public class extendsBasic {
public static void main(String[] args) {
new Zi();
}
}
输出:Fu! 8
Zi!
class Fu{
Fu(){
System.out.println("A");
}
Fu(int x){
System.out.println("B"+x);
}
}
class Zi extends Fu{
Zi(){
System.out.println("C");
}
Zi(int x){
System.out.println("D "+x);
}
}
public class extendsBasic {
public static void main(String[] args) {
new Zi();
new Zi(66);
}
}
输出:A
C
A
D 66
new Zi();-------Zi()->super()->Fu()
new Zi(6);------Zi(int x)->super()->Fu()
以上称为:子类的实例化
细节:
1.如果在构造函数里第一行写了this();那么super();语句在函数里不存在——因为this 和super 只能在第一行
Zi(){//在这个函数里还有super 对父类进行初始化
System.out.println("C");
}
Zi(int x){
this();//在这个构造函数里没有了super
System.out.println("D "+x);
2.在父类的构造函数中也有隐式的super(),只要是构造函数第一行都默认为super();除非你自己手动的明确父类的父类是?---在Java体系设计中,定义了一个所有类的父类object(在虚拟机启动时就存在了)(super 和this 都仅能在第一行)
总结:
(1)父类的构造函数可以为自己的对象初始化,也可以为自己子类的对象初始化
(2)在构造函数中的第一行都有隐式的super();
(3)如果隐式的super(); 没有对应的(在父类中)构造函数,必须在构造函数(子类的)中通过this 或者super()的形式明确构造函数
(4)this 和super 不能同时在一个构造函数中————因为他们都要在第一行————初始化必须要先完成
3.Java类构造函数的执行过程
类初始化时构造函数调用顺序:
(1)初始化对象的存储空间为零或null值;
(2)调用父类构造函数;
class Dollar {
Money m = new Money();
Rmb r = new Rmb();
public Dollar() {
System.out.println("Dollar is construct!");
}
public static void main(String[] args) {
new Dollar();
}
}
class Money {
public Money() {
System.out.println("Money is construct!");
}
}
class Rmb {
public Rmb() {
System.out.println("RMB is construct!");
}
}
输出结果:
Money is construct
RMB is construct
Dollar is construct!