Java 中的构造函数

Java中的构造函数用于创建类的实例。构造函数几乎与方法相似,除了两件事-它的名称与类名相同,并且它没有返回类型。有时构造函数也被称为初始化对象的特殊方法。

Java中的构造函数

每当使用new关键字创建类的实例时,都会调用构造函数并返回类的对象。因为构造函数只能将对象返回给类,所以它是由Java运行时隐式完成的,我们不应该向它添加返回类型。如果我们将返回类型添加到构造函数中,那么它将成为类的方法。这是Java运行时区分普通方法和构造函数的方式。让我们假设在Employee类中有以下代码。

1public Employee() {
2    System.out.println("Employee Constructor");
3}
4
5public Employee Employee() {
6    System.out.println("Employee Method");
7    return new Employee();
8}

这里第一个是构造函数,注意没有返回类型和返回语句。第二个是一个普通的方法,我们再次调用第一个构造函数来获取Employee实例并返回它。建议不要使用与类名相同的方法名,因为这样会造成混淆。

Java中的构造函数类型

Java中有三种类型的构造函数。

1.默认构造函数 2.无参数构造函数 3.参数化构造函数

让我们通过示例程序来研究所有这些构造函数类型。

Java中的默认构造函数

不需要总是在类代码中提供构造函数实现。如果我们不提供构造函数,那么Java将提供默认的构造函数实现供我们使用。让我们来看一个简单的程序,其中使用了默认构造函数,因为我们不会显式定义构造函数。

1package com.journaldev.constructor;
2
3public class Data {
4
5    public static void main(String[] args) {
6    	Data d = new Data();
7    }
8}

1.默认的构造函数唯一角色是初始化对象并将其返回给调用代码。 2.默认构造函数始终不带参数,只有在没有定义现有构造函数的情况下才由Java编译器提供。 3.大多数情况下,我们可以使用默认构造函数本身,因为可以通过getter setter方法访问和初始化其他属性。

无参数构造函数

不带任何参数的构造函数称为无参数构造函数。它类似于覆盖默认构造函数,用于执行一些预初始化工作,如检查资源、网络连接、日志记录等。让我们快速了解一下Java中的无参数构造函数。

 1package com.journaldev.constructor;
 2
 3public class Data {
 4        //no-args constructor
 5    public Data() {
 6    	System.out.println("No-Args Constructor");
 7    }
 8    public static void main(String[] args) {
 9    	Data d = new Data();
10    }
11}

现在,当我们调用new data()时,我们的无参数构造函数将被调用。下图显示了此行为,请检查程序的控制台输出。java中没有args构造函数

参数化构造函数

带参数的构造函数称为参数构造函数。让我们看一看Java中的参数化构造函数的例子。

 1package com.journaldev.constructor;
 2
 3public class Data {
 4
 5    private String name;
 6
 7    public Data(String n) {
 8    	System.out.println("Parameterized Constructor");
 9    	this.name = n;
10    }
11
12    public String getName() {
13    	return name;
14    }
15
16    public static void main(String[] args) {
17    	Data d = new Data("Java");
18    	System.out.println(d.getName());
19    }
20
21}

使用parameters的JAVA类构造函数

Java中的构造函数重载

当我们有多个构造函数时,这就是Java中的构造函数重载。让我们来看一个Java程序中构造函数重载的例子。

 1package com.journaldev.constructor;
 2
 3public class Data {
 4
 5    private String name;
 6    private int id;
 7
 8    //no-args constructor
 9    public Data() {
10    	this.name = "Default Name";
11    }
12    //one parameter constructor
13    public Data(String n) {
14    	this.name = n;
15    }
16    //two parameter constructor
17    public Data(String n, int i) {
18    	this.name = n;
19    	this.id = i;
20    }
21
22    public String getName() {
23    	return name;
24    }
25
26    public int getId() {
27    	return id;
28    }
29
30    @Override
31    public String toString() {
32    	return "ID="+id+", Name="+name;
33    }
34    public static void main(String[] args) {
35    	Data d = new Data();
36    	System.out.println(d);
37    	
38    	d = new Data("Java");
39    	System.out.println(d);
40    	
41    	d = new Data("Pankaj", 25);
42    	System.out.println(d);
43    	
44    }
45
46}

Java中的私有构造函数

请注意,我们不能将abstract,最终关键字、static关键字和同步关键字与构造函数一起使用。但是,我们可以使用访问修饰符来控制类对象的实例化。使用Publicdefault访问仍然可以,但是将构造函数设为私有有什么用呢?在这种情况下,任何其他类都不能创建类的实例。如果我们想要实现Singleton Design pattern.],则构造函数被设置为私有的由于Java自动提供默认构造函数,因此我们必须显式创建一个构造函数并将其保持为私有。客户端类提供了一个实用程序静态方法来获取类的实例。下面给出了一个Data类的私有构造函数示例。

1// private constructor
2private Data() {
3    //empty constructor for singleton pattern implementation
4    //can have code to be used inside the getInstance() method of class
5}

Java中的构造函数链接

当一个构造函数调用同一类的另一个构造函数时,称为构造函数链。我们必须使用this关键字来调用该类的另一个构造函数。有时它被用来设置类变量的一些缺省值。请注意,另一个构造函数调用应该是代码块中的第一个语句。此外,不应该有会创建无限循环的递归调用。让我们来看一个Java程序中构造函数链接的例子。

 1package com.journaldev.constructor;
 2
 3public class Employee {
 4
 5    private int id;
 6    private String name;
 7    
 8    public Employee() {
 9    	this("John Doe", 999);
10    	System.out.println("Default Employee Created");
11    }
12    
13    public Employee(int i) {
14    	this("John Doe", i);
15    	System.out.println("Employee Created with Default Name");
16    }
17    public Employee(String s, int i) {
18    	this.id = i;
19    	this.name = s;
20    	System.out.println("Employee Created");
21    }
22    public static void main(String[] args) {
23
24    	Employee emp = new Employee();
25    	System.out.println(emp);
26    	Employee emp1 = new Employee(10);
27    	System.out.println(emp1);
28    	Employee emp2 = new Employee("Pankaj", 20);
29    	System.out.println(emp2);
30    }
31
32    @Override
33    public String toString() {
34    	return "ID = "+id+", Name = "+name;
35    }
36    public int getId() {
37    	return id;
38    }
39
40    public void setId(int id) {
41    	this.id = id;
42    }
43
44    public String getName() {
45    	return name;
46    }
47
48    public void setName(String name) {
49    	this.name = name;
50    }
51
52}

我重写了toString()方法以打印有关Employee对象的一些有用信息。以下是上述程序产生的输出。

1Employee Created
2Default Employee Created
3ID = 999, Name = John Doe
4Employee Created
5Employee Created with Default Name
6ID = 10, Name = John Doe
7Employee Created
8ID = 20, Name = Pankaj

注意一个构造函数是如何从另一个构造函数调用的,这称为构造函数链接过程。

Java超级构造函数

有时一个类是从一个超类继承而来的,在这种情况下,如果我们必须调用超类构造函数,那么我们可以使用Super关键字来实现。让我们来看一个使用超类构造函数的示例。请注意,超级构造函数调用应该是子类构造函数中的第一条语句。同样,在实例化子类构造函数时,Java首先初始化超类,然后初始化子类。因此,如果没有显式调用超类构造函数,则Java运行时将调用默认的或无参数的构造函数。让我们通过一些示例程序来理解这些概念。让我们假设我们有两个类,如下所示。

 1package com.journaldev.constructor;
 2
 3public class Person {
 4
 5    private int age;
 6
 7    public Person() {
 8    	System.out.println("Person Created");
 9    }
10
11    public Person(int i) {
12    	this.age = i;
13    	System.out.println("Person Created with Age = " + i);
14    }
15
16}
 1package com.journaldev.constructor;
 2
 3public class Student extends Person {
 4
 5    private String name;
 6
 7    public Student() {
 8    	System.out.println("Student Created");
 9    }
10
11    public Student(int i, String n) {
12    	super(i); // super class constructor called
13    	this.name = n;
14    	System.out.println("Student Created with name = " + n);
15    }
16
17}

现在,如果我们创建一个Student对象,如下所示;

1Student st = new Student();

产出会是多少呢?上述代码的输出将为:

1Person Created
2Student Created

因此,调用转到Student类的no-args构造函数,因为在第一个语句中没有超级调用,即调用Person类的no-args或默认构造函数。因此,输出。如果我们使用Student类的参数化构造函数作为Student st = new Student(34,);,输出将是:

1Person Created with Age = 34
2Student Created with name = Pankaj

这里的输出很清楚,因为我们显式地调用了超类构造函数,所以Java不需要从它们那端做任何额外的工作。

Java Copy构造函数

Java复制构造函数将同一类的对象作为参数,并创建其副本。有时,我们需要另一个对象的副本来进行一些处理。我们可以通过以下方式做到这一点:

1.实施cloning 2.提供了copyof the Object]的实用方法。 3.拥有复制构造函数

现在,让我们看看如何编写复制构造函数。假设我们有一个类‘Fruits’,如下所示。

 1package com.journaldev.constructor;
 2
 3import java.util.ArrayList;
 4import java.util.List;
 5
 6public class Fruits {
 7
 8    private List<String> fruitsList;
 9
10    public List<String> getFruitsList() {
11    	return fruitsList;
12    }
13
14    public void setFruitsList(List<String> fruitsList) {
15    	this.fruitsList = fruitsList;
16    }
17
18    public Fruits(List<String> fl) {
19    	this.fruitsList = fl;
20    }
21    
22    public Fruits(Fruits fr) {
23    	List<String> fl = new ArrayList<>();
24    	for (String f : fr.getFruitsList()) {
25    		fl.add(f);
26    	}
27    	this.fruitsList = fl;
28    }
29}

请注意,Fruits(Fruits fr)正在执行深度复制以返回对象的副本。让我们看看一个测试程序,以理解为什么使用复制构造函数来复制对象更好。

 1package com.journaldev.constructor;
 2
 3import java.util.ArrayList;
 4import java.util.List;
 5
 6public class CopyConstructorTest {
 7
 8    public static void main(String[] args) {
 9    	List<String> fl = new ArrayList<>();
10    	fl.add("Mango");
11    	fl.add("Orange");
12
13    	Fruits fr = new Fruits(fl);
14
15    	System.out.println(fr.getFruitsList());
16
17    	Fruits frCopy = fr;
18    	frCopy.getFruitsList().add("Apple");
19
20    	System.out.println(fr.getFruitsList());
21
22    	frCopy = new Fruits(fr);
23    	frCopy.getFruitsList().add("Banana");
24    	System.out.println(fr.getFruitsList());
25    	System.out.println(frCopy.getFruitsList());
26
27    }
28
29}

上述程序的输出为:

1[Mango, Orange]
2[Mango, Orange, Apple]
3[Mango, Orange, Apple]
4[Mango, Orange, Apple, Banana]

请注意,当使用复制构造函数时,原始对象及其副本彼此无关,其中一个对象中的任何修改都不会反映到另一个对象中。这就是Java中的构造函数。

Published At
Categories with 技术
Tagged with
comments powered by Disqus