Java构造函数
Java构造函数是在实例化对象时调用的特殊方法。换句话说,当我们使用new
关键字时。 Java构造函数的目的是在使用新创建的对象之前对其进行初始化。该Java构造函数教程将更详细地探讨Java构造函数。
这是一个创建对象的简单示例,该对象导致类构造函数被调用:
MyClass myClassObj = new MyClass();
这个例子导致创建一个新的MyClass对象,并调用MyClass的no-arg构造函数。稍后我们将了解no-arg构造函数。
Java类构造函数初始化该类的实例(对象)。通常,构造函数会初始化需要初始化的对象的字段。 Java构造函数也可以使用参数,因此可以在创建时在对象中初始化字段。
用Java定义构造函数
这是一个简单的Java构造函数声明示例。该示例显示了具有单个构造函数的非常简单的Java类。
public class MyClass { public MyClass() { } }
构造函数是这一部分:
public MyClass() { }
Java构造函数声明的第一部分是访问修饰符。访问修饰符的含义与方法和字段的含义相同。它们确定哪些类可以访问(调用)构造函数。我的Java访问修饰符教程中更详细地介绍了访问修饰符。
Java构造函数声明的第二部分是构造函数所属的类的名称。使用构造函数的类名会向Java编译器发出信号,表明这是构造函数。还要注意,构造函数没有其他类型一样的返回类型。
Java构造函数声明的第三部分是构造函数可以采用的参数列表。构造函数的参数在构造函数的类名部分之后的括号()中声明。在上面的构造函数声明示例中,未声明任何参数。在本文后面的部分中,我将显示带有参数的Java构造函数声明的示例。
Java构造函数声明的第四部分是构造函数的主体。构造函数的主体在参数列表后的大括号" {}"内定义。在上面的构造函数示例中,构造函数在构造函数体内没有任何操作。据说它是一个"空"的构造函数。
构造函数重载-Java类的多个构造函数
一个类可以有多个构造函数,只要它们的签名(它们采用的参数)不同即可。我们可以根据需要定义任意数量的构造函数。当一个Java类包含多个构造函数时,我们说该构造函数已重载(有多个版本)。这就是构造函数重载的含义,一个Java类包含多个构造函数。
这是一个Java构造函数重载示例:
public class MyClass { private int number = 0; public MyClass() { } public MyClass(int theNumber) { this.number = theNumber; } }
上面的Java类包含两个构造函数。第一个构造函数是无参数构造函数,这意味着它不带任何参数(没有参数)。第二个构造函数采用一个" int"参数。在构造函数主体内部,将int
参数值分配给一个字段,这意味着将参数的值复制到该字段中。因此,该字段被初始化为给定的参数值。
字段名(this.number)前面不需要关键字
this`。它只是向编译器发出信号,即正在引用名为" number"的字段。有关构造函数参数的部分将对此进行详细说明。
默认,无参数构造函数
我们不必为类定义构造函数,但是如果我们没有定义任何构造函数,则Java编译器将为我们插入一个默认的无参数构造函数。因此,一旦编译了类,它将至少始终具有一个无参数的构造函数。
如果确实为类定义了构造函数,则Java编译器不会将默认的无参数构造函数插入类。
构造函数参数
如我们所见,Java构造函数有可能采用参数。然后,这些参数可用于初始化新创建对象的内部状态(字段)。这是一个例子:
public class Employee { private String firstName = null; private String lastName = null; private int birthYear = 0; public Employee(String first, String last, int year ) { firstName = first; lastName = last; birthYear = year; } }
在此示例中,Java构造函数声明以粗体标记。如我们所见,声明了三个参数:" first"," last"和" year"。在构造函数的主体内部,这三个参数的值被分配给Employee
对象的字段。
每个参数之后的换行符是可选的。 Java编译器在此忽略换行符。我们还可以根据需要在一行中编写参数声明,如下所示:
public Employee(String first, String last, int year ) { firstName = first; lastName = last; birthYear = year; }
要调用带有三个参数的该构造函数,我们可以实例化一个Employee
对象,如下所示:
Employee employee = new Employee("Hyman", "Daniels", 2000);
在等号右侧的类名之后,将参数传递给括号内的构造函数。然后创建对象,并执行构造函数。执行完上述构造函数后,构造函数初始化的字段将具有传递给构造函数的参数值。
Java构造函数参数可以与字段具有相同的名称。如果构造函数参数与字段具有相同的名称,则Java编译器在知道我们引用的对象时会遇到问题。默认情况下,如果参数(或者局部变量)与同一类中的字段具有相同的名称,则该参数(或者局部变量)对该字段"阴影"。看下面的构造函数示例:
public class Employee { private String firstName = null; private String lastName = null; private int birthYear = 0; public Employee(String firstName, String lastName, int birthYear ) { firstName = firstName; lastName = lastName; birthYear = birthYear; } }
在Employee类的构造函数中," firstName"," lastName"和" birthYear"标识符现在引用构造函数参数,而不是具有相同名称的Employee字段。因此,构造函数现在只需将参数设置为等于自身即可。 Employee字段永远不会初始化。
为了向Java编译器发出信号,意思是Employee类的字段而不是参数,请在字段名前面加上" this"关键字和一个点。这是以前的Java构造函数声明与该更改的相似之处:
public class Employee { private String firstName = null; private String lastName = null; private int birthYear = 0; public Employee(String firstName, String lastName, int birthYear ) { this.firstName = firstName; this.lastName = lastName; this.birthYear = birthYear; } }
现在,Employee字段已在构造函数中正确初始化。
调用构造函数
创建包含构造函数的类的新实例时,可以调用构造函数。这是一个Java构造函数调用示例:
MyClass myClassVar = new MyClass();
本示例调用(调用)本文前面定义的MyClass的无参数构造函数。
如果要将参数传递给构造函数,请在类名称后的括号之间包含参数,如下所示:
MyClass myClassVar = new MyClass(1975);
本示例将一个参数传递给采用" int"作为参数的" MyClass"构造函数。
从构造函数调用构造函数
在Java中,可以从另一个构造函数内部调用一个构造函数。当我们从另一个构造函数内部调用一个构造函数时,可以使用this
关键字来引用该构造函数。这是在Java中从另一个构造函数中调用一个构造函数的示例:
public class Employee { private String firstName = null; private String lastName = null; private int birthYear = 0; public Employee(String first, String last, int year ) { firstName = first; lastName = last; birthYear = year; } public Employee(String first, String last){ this(first, last, -1); } }
注意第二个构造函数定义。在构造函数的主体内,我们可以找到以下Java语句:
this(first, last, -1);
关键字" this"后跟括号和参数意味着正在调用同一Java类中的另一个构造函数。正在调用哪个其他构造函数取决于传递给构造函数调用的参数(在" this"关键字后面的括号内)。在此示例中,它是该类中的第一个构造函数。
在超类中调用构造函数
在Java中,一个类可以扩展另一个类。当一个类扩展另一个类时,它也被称为从其扩展的类"继承"。扩展的类称为子类,而扩展的类称为超类。在我有关Java继承的教程中更详细地介绍了继承。
扩展另一个类的类不会继承其构造函数。但是,子类必须在子类构造函数之一内的超类中调用一个构造函数!
查看以下两个Java类。汽车类(继承自汽车类)扩展。
public class Vehicle { private String regNo = null; public Vehicle(String no) { this.regNo = no; } }
public class Car extends Vehicle { private String brand = null; public Car(String br, String no) { super(no); this.brand = br; } }
注意Car类中的构造函数。它使用以下Java语句在超类中调用构造函数:
super(no);
使用关键字" super"表示使用" super"关键字的类的超类。当super
关键字后跟括号时,如此处所示,它指向超类中的构造函数。在这种情况下,它引用Vehicle类中的构造函数。由于Car扩展了Vehicle,因此Car构造函数必须全部在Vehicle中调用构造函数。
Java构造函数访问修饰符
构造函数的access修饰符确定应用程序中允许哪些类调用该构造函数。访问修饰符在Java访问修饰符的文本中有更详细的说明。
例如,如果构造函数被声明为" protected",则只有同一包中的类或者该类的子类才能调用该构造函数。
一个类可以有多个构造函数,每个构造函数可以有自己的访问修饰符。因此,某些构造函数可能可用于我们应用程序中的所有类,而其他构造函数仅可用于同一包,子类中的类,甚至仅可用于类本身(私有构造函数)。
构造函数的异常抛出
可以从Java构造函数中引发异常。这是带有可引发异常的构造函数的Java类的示例:
public class Car { public Car(String brand) throws Exception { if(brand == null) { throw new Exception("The brand parameter cannot be null!"); } } }
注意构造函数声明的" throws Exception"部分。该部分声明构造函数可能会抛出"异常"。如果发生这种情况,则创建的Car
实例无效。
这是一个调用Car构造函数的示例:
Car car = null; try{ car = new Car("Mercedes"); //do something with car object } catch(Exception e) { // handle exception }
如果从Car构造函数抛出异常,则不会为car变量分配对我们要创建的Car对象的引用。 car变量仍将指向null。
如果要防止在无效状态下创建给定类的对象,则使构造函数引发异常可能是一个好主意。通常,构造函数的输入参数可能导致对象无效。如果构造函数检测到无效的输入参数,则可能引发异常并阻止将对象分配给任何变量。