在Java程序中,每个类都必须至少有一个构造器(Constructor)。构造器是创建一个类的实例(对象)时需要调用的一个特殊的方法。
利用构造器可以产生一个类的实例,并且提供了一个地方用来定义创建类的实例时都需要执行的初始化(initialize)代码。构造器的定义语法如下:
<modifier><class_name> ( [<argument_list>] )
{
[<statements>]
}
从上面的语法中可以看出,它和类中的方法定义很类似:可以有访问修饰符modifier、有自己的方法名称、有参数列表、有方法体,因此,可以将构造器当成一个特殊的方法(在许多资料里面,就是将Constructor称为构造方法),这个方法的作用就是用来产生一个类的实例。但是要认识到构造器与普通方法的区别,主要表现在以下3个方面。
(1)修饰符:和方法一样,构造器可以有任何访问的修饰:public、protected、private或者没有修饰。不同于方法的是,构造器不能有以下非访问性质的修饰:abstract、final、native、static或者 synchronized。
(2)返回值:方法能返回任何类型的值或者无返回值(void),构造器没有返回值,也不需要void。
(3)命名:构造器使用和类相同的名字,通常为名词。而方法则不同,通常为描述一个操作的动词。按照习惯,方法通常用小写字母开始,而构造器通常用大写字母开始。
下面定义一个用来表示"美食"的类Food。
源文件:Food.java
public class Food {
private String food_name ;
public Food(String name){
this.food_name= name;
}
}
在Food类中,定义了一个属性food_name,还定义了一个构造器,在构造器中传入一个字符串类型的参数,将参数值赋给属性food_name。此时,就可以通过这个构造器来实例化这个类,如下所示。
Food myDinner = newFood("pizza");
这样,就得到了一个food_name名为"pizza"的实例,还可以再创建一个food_name名为"cola"的实例来搭配你的晚餐。
如果在程序中没有定义任何的构造器,则编译器将会自动加上一个不带任何参数的构造器。默认的构造器不带任何的参数,也没有"方法体"。
通过上面的示例,在Food类中定义了一个带一个参数的构造器。如果上面的Food类没有定义构造器,则编译器会自动加上一个构造器:
public class Food {
private String food_name ;
public Food(){
}
}
所以,这时可以用下面的语句来实例化这个类:
Food myDinner = newFood();
如果在程序中定义了构造器,则编译器将不再提供默认的构造器,即使定义的构造器同样没有参数。如果再使用默认构造器的话,编译器会报错。
使用Java 构造器中的一些注意事项:
1.首先要注意的是Java的构造器并不是函数,所以他并不能被继承,这在我们extends的时候写子类的构造器时比较的常见,即使子类构造器参数和父类的完全一样,我们也要写super就是因为这个原因。
2.构造器的修饰符比较的有限,仅仅只有public private protected这三个,其他的例如任何修饰符都不能对其使用,也就是说构造器不允许被成名成抽象、同步、静态等等访问限制以外的形式。
3.因为构造器不是函数,所以它是没有返回值的,也不允许有返回值。但是这里要说明一下,构造器中允许存在return语句,但是return什么都不返回,如果你指定了返回值,虽然编译器不会报出任何错误,但是JVM会认为他是一个与构造器同名的函数罢了,这样就会出现一些莫名其妙的无法找到构造器的错误,这里是要加倍注意的。
4.构造器中一定不要创建自身的实例,否则会造成调用栈溢出错误。这个规则也适用于对象的实例变量,如果对象中有自身的引用,这个引用一定不能在定义中或者构造器中初始化。
5.如果父类是一个抽象类,那通过调用父类的构造器,也可以将它初始化,并且初始化其中的数据。
6.如果你要在构造器中调用一个方法时,将该方法声明为private。
对于这个规则是需要一些说明的,假使你的父类构造器中要调用一个非静态方法,而这个方法不是private的又被子类所重载,这样在实际创建子类的过程中递归调用到了父类的构造器时,父类构造器对这个方法的调用就会由于多态而实际上调用了子类的方法,当这个子类方法需要用到子类中实例变量的时候,就会由于变量没有初始化而出现异常(至于为什么子类中的实例变量没有初始化可以参考上边的实例初始化过程),这是Java不想看到的情况。而当父类构造器中调用的方法是一个private方法时,多态就不会出现,也就不会出现父类构造器调用子类方法的情况,这样可以保证父类始终调用自己的方法,即使这个方法中调用了父类中的实例变量也不会出现变量未初始化的情况(变量初始化总是在当前类构造器主体执行之前进行)
今天的过程:
实现一个类,专门用来记录一个人的头部信息:包括人鼻子的大小,眼睛的眼睛,有及人物编号,并且实现下面两个信息的存储的显示:
Jim:ID:1 EyeColor:blue NoseSize:big
Hua:ID:2 EyeColor:black NoseSize:small
第一种方法是使用一般的方法实现.第二种方法是使用构造器来实现!
构造器作用:
我把它做如下简单的归纳:简化类的初始化过程!方便对象的定义
法一:通过一般方法实现:
代码如下:
class Face{
public int id ;
public String eyecolor = "black";
public String nosesize = "normal";//声明三个变量
private static int nextid = 1;//为ID的产生声明一个递增的变量
public static void main(String args[]){
//采用一般方法来实例化类(产生两个对象)
Face jim = new Face();
jim.id = nextid++;
jim.eyecolor = "blue";
jim.nosesize = "big";
Face hua = new Face();
hua.id = nextid++;
hua.eyecolor = "black";
hua.nosesize = "small";//采用一般方法定义两个对象
System.out.println("jim/n/tID/t/t:/t"+jim.id +"/n/tEyeColor/t:/t"+jim.eyecolor+ "/n/tNoseSize/t:/t" + jim.nosesize);
System.out.println("hua/n/tID/t/t:/t"+hua.id+"/n/tEyeColor/t:/t"+hua.eyecolor + "/n/tNoseSize/t:/t" +hua.nosesize);
//显示两个对象的值
}
}
方法二:通过构造器实现
class Face{
public int id ;
public String eyecolor = "black";
public String nosesize = "normal";
private static int nextid = 001;
//构造器部分开始,它需要使用与类名相同的名字
Face(String faceeyecolor , String facenosesize){
id = nextid ++;
eyecolor = faceeyecolor ;
nosesize = facenosesize ;
}//构造器完成
public static void main(String args[]){
Face jim = new Face("blue","big");
Face hua = new Face("black","small");
System.out.println("jim/n/tID/t/t:/t"+jim.id+"/n/tEyeColor/t:/t"+jim.eyecolor + "/n/tNoseSize/t:/t" +jim.nosesize);
System.out.println("hua/n/tID/t/t:/t"+hua.id+"/n/tEyeColor/t:/t"+hua.eyecolor + "/n/tNoseSize/t:/t" +hua.nosesize);
}
}
当创建一个个对象时,系统会该对象的属性默认初始化,基本类型属性的值为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类得构造器