Java构造函数

时间:2020-01-09 10:35:41  来源:igfitidea点击:

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。

如果要防止在无效状态下创建给定类的对象,则使构造函数引发异常可能是一个好主意。通常,构造函数的输入参数可能导致对象无效。如果构造函数检测到无效的输入参数,则可能引发异常并阻止将对象分配给任何变量。