构造函数
在类中,我们可以定义方法,但有一种特殊类型的方法用于解决特定的问题、构造对象。构造函数方法之所以特别,是因为它们的角色以及它们有很多关于声明和用法的规则。
每次创建对象时,都会调用构造函数。基于这个事实,在Java中, 每个类至少有一个构造函数,即使程序员没有显式地声明一个构造函数。
构造函数方法角色是:
主要角色-构造对象,意味着在堆中分配空间
次要角色[可选]–使用默认值(记住,当创建对象时,实例变量会获得其默认值)或给定值初始化实例变量;
考虑给定类和主要方法
public class Book { float price; String title; String author; public static void main(String[] args) { //create a book Book b1 = new Book(); } }
很明显,在 main()方法中,它构造了一个类型为 Book的对象,被[b1]引用所引用。那么,构造器呢?。
关于构造函数的一条规则规定:如果没有显式声明的构造函数, 编译器将提供一个默认构造函数(一个无参数的构造函数)
编译器生成的默认构造函数的形式是:
public Book() { }
Java中声明和调用构造函数的规则
构造函数与父类具有相同的名称(区分大小写);
构造函数没有返回类型(这是合乎逻辑的,因为它们总是返回对已构造对象的引用);与类同名但具有返回类型的方法是常见的方法,而不是构造函数:
public class Book { //不是构造函数-因为有返回类型 public void Book(){ System.out.println("A simple no-sense method !"); } public static void main(String[] args) { //使用默认构造函数创建一个book对象 Book b1 = new Book(); b1.Book(); //call the method } }
构造函数可以声明为public或private(对于Singleton);
构造函数可以不带参数、带一些参数和可变参数列表var-args;
//不带参数的构造函数 public Book(){ price = 100; title = "Nothing"; } //3 个参数的构造函数 public Book(float Price, String Title, String Author){ price = Price; title = Title; author= Author; } //2 个参数的构造函数 public Book(String Title, String Author){ price = 0; //默认值 title = Title; author= Author; } //var-arg 可变参数构造函数 public Book(float Price, String ... someStrings){ //处理过程 }
默认的构造函数是一个无参数的;
如果不编写任何构造函数,编译器将生成默认的构造函数;
如果我们编写了至少一个构造函数(与它的参数无关),编译器将不会生成默认的构造函数;
如果我们编写了至少一个构造函数,并且需要默认的构造函数,则必须编写它;否则,当我们尝试调用它时,将出现编译器错误:
public class Book { float price; String title; String author; //2个参数的构造函数 public Book(String Title, String Author){ price = 0; //默认值 title = Title; author = Author; } public static void main(String[] args){ // 创建Book对象 Book b1 = new Book(); //compiler error //cannot find symbol : constructor Book() } }
构造器不能定义为 *static、 final或 abstract;
在构造函数中,可以使用 this引用引用构造的对象(有助于避免阴影(shadowing)
构造器中的 第一条语句是使用 this()调用另一个构造器,或者使用 super()调用超类构造器(详见继承主题);如果不使用 this()或 super(),编译器将进行 super()调用;为了理解谁是super(),必须了解一些关于继承的知识
使用 new运算符或使用其他构造函数的 this()调用构造函数;不允许像调用其他方法一样调用构造函数;
使用this()调用其他构造函数时,请注意可能生成无限递归和运行时异常的交叉调用(某些编译器可能会捕获此问题并生成递归构造函数调用错误:
构造函数可以访问静态方法或变量;
抽象类有构造函数;
重载构造函数(使用相同的名称定义方法,但使用不同的参数列表)时,必须使用不同的参数列表(作为数字或类型)定义它们