Java中的构造函数——通过示例学习Java编程(14)
作者:CHAITANYA SINGH
来源:https://www.koofun.com//pro/kfpostsdetail?kfpostsid=25
构造函数是用来初始化新创建的对象的代码块。构造函数类似于java中的实例方法(Instance Method),但它不是一个方法(Method),因为它没有返回类型。简而言之,构造函数和方法是不同的(在本指南的末尾将有更多的介绍)。人们经常把Java中的构造函数称为特殊类型的方法。
构造函数的名称必须与与类名相同,如下图中的java代码所示:
1
2
3
4
5
6
|
public class MyClass{ //This is the constructor MyClass(){ } .. } |
注意,构造函数名与类名必须一致,并且没有返回类型。
构造函数是如何工作的?
下面我们通过一个例子来帮助大家理解构造函数的工作原理。我们先创建一个名字叫MyClass的类:
1
|
MyClass obj = new MyClass(); |
以上代码的意思就是通过new关键字来创建类MyClass的对象并调用这个类的构造函数来初始化这个新创建的对象,然后把这个对象赋值给对象变量obj。语句new MyClass()表示创建一个新的关于类MyClass的对象并调用构造函数来初始化这个新创建的对象。
下面我们来通过代码实例来解释什么是新创建对象的初始化。
一个简单的java构造函数程序
这里我们基于类Hello创建了一个对象obj,然后我们显示这个对象的实例变量name的值。在构造函数里面,我们给变量name赋值“BeginnersBook.com”,在赋值语句里面的this关键字表示引用当前的对象。我们将在下一个教程中详细介绍this关键字。
1
2
3
4
5
6
7
8
9
10
11
|
public class Hello { String name; //Constructor Hello(){ this .name = "BeginnersBook.com" ; } public static void main(String[] args) { Hello obj = new Hello(); System.out.println(obj.name); } } |
输出:
1
|
BeginnersBook.com |
构造函数的类型
构造函数有三种类型:默认构造函数、无参数构造函数和参数化构造函数。
默认构造函数
如果在类(class)中没有定义代码来实现任何构造函数,Java编译器将会在编译的字节码里面为你插入默认构造函数。不会在源代码(java文件)中找到它,因为默认构造函数是在编译期间由编译器插入到代码中,并且存在于.class文件中,所以你在源代码(java文件)里面是看不到这个默认构造函数的。这个过程如下图所示:
注:如果你在类(class)里面实现了任何构造函数,那么Java编译器将不会在你的代码中插入默认构造函数。
无参数构造函数
不带参数的构造函数称为无参数构造函数,其形式看上去与默认构造函数相同,但是无参数构造函数里面可以有任何代码,而默认构造函数里面则是空的。
注:虽然您可能会看到一些人声称默认构造函数和无参数构造函数是相同的,但实际上它们并不相同,只要是你写的构造函数,就不能称之为默认构造函数。
示例:无参数构造函数
1
2
3
4
5
6
7
8
9
10
|
class Demo { public Demo() { System.out.println( "This is a no argument constructor" ); } public static void main(String args[]) { new Demo(); } } |
输出:
This is a no argument constructor
参数化构造函数
带参数的构造函数称为参数化构造函数。
示例1:参数化构造函数
在这个例子中,我们定义的类Employee里面有一个带有两个参数(id,name)的参数化构造函数。用这个类Employee创建两个对象,obj1和obj2,在创建obj1和obj2时都调用了这个参数化构造函数,分别往里面传了两套不同的参数:10245、"Chaitanya"和92232、"Negan",传进去的参数都赋值给了类的成员变量empId和empName,后面的代码把obj1和obj2的empId和empName分别打印出来,见下图:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public class Employee { int empId; String empName; //parameterized constructor with two parameters Employee( int id, String name){ this .empId = id; this .empName = name; } void info(){ System.out.println( "Id: " +empId+ " Name: " +empName); } public static void main(String args[]){ Employee obj1 = new Employee( 10245 , "Chaitanya" ); Employee obj2 = new Employee( 92232 , "Negan" ); obj1.info(); obj2.info(); } } |
输出:
1
2
|
Id: 10245 Name: Chaitanya Id: 92232 Name: Negan |
例2:参数化构造函数
在这个例子中,我们有两个构造函数,一个默认构造函数和一个参数化构造函数。当我们在使用new关键字创建对象而且不传递任何参数时,系统将调用默认构造函数,但是如果我们在使用new关键字创建对象的时候传递了参数,那么系统将调用与传递的参数列表匹配的参数化构造函数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
class Example2 { private int var; //default constructor public Example2() { this .var = 10 ; } //parameterized constructor public Example2( int num) { this .var = num; } public int getValue() { return var; } public static void main(String args[]) { Example2 obj = new Example2(); Example2 obj2 = new Example2( 100 ); System.out.println( "var is: " +obj.getValue()); System.out.println( "var is: " +obj2.getValue()); } } |
输出:
1
2
|
var is: 10 var is: 100 |
如果我们类中只实现了参数化构造函数,而没有实现默认构造函数(不带参数的),会发生什么?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Example3 { private int var; public Example3( int num) { var=num; } public int getValue() { return var; } public static void main(String args[]) { Example3 myobj = new Example3(); System.out.println( "value of var is: " +myobj.getValue()); } } |
输出:编译报错
原因:在代码Example3 myobj = new Example3();中,我们调用了类Example3里面的不含参数的默认构造函数,还记得我们在上面提到的,一旦我们在类里面有实现带参数的构造函数,那么编译器就不会自动在背后给我们插入不含参数的默认构造函数,而代码new Example3();调用了类(class)Example3的不存在的默认构造函数,当然编译就会报错啦!
如果我们从上面的代码中删除参数化构造函数的实现代码,那么程序编译和运行都不会有问题,因为编译器会在编译的过程中将默认构造函数插入到您的代码中。
构造函数链
当构造函数调用同一个类的另一个构造函数时,这称为构造函数链,见下图:
super()
每当我们调用子类构造函数时,它都隐式地调用了父类的构造函数,可以把这理解为编译器在子类构造函数的开头插入了super();语句。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class MyParentClass { MyParentClass(){ System.out.println( "MyParentClass Constructor" ); } } class MyChildClass extends MyParentClass{ MyChildClass() { System.out.println( "MyChildClass Constructor" ); } public static void main(String args[]) { new MyChildClass(); } } |
输出:
1
2
|
MyParentClass Constructor MyChildClass Constructor |
构造函数重载
构造函数重载指的是同一个类里面定义实现了多个不同参数列表的构造函数,虽然这些构造函数的名字都是一样的(和类名一样),但在创建这个类的对象的时候,如果传进去的参数不同,调用的构造函数也是不同的。
Java的复制构造函数
复制构造函数用于将一个对象的值复制到另一个对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
class JavaExample{ String web; JavaExample(String w){ web = w; } /* This is the Copy Constructor, it * copies the values of one object * to the another object (the object * that invokes this constructor) */ JavaExample(JavaExample je){ web = je.web; } void disp(){ System.out.println("Website: "+web); } public static void main(String args[]){ JavaExample obj1 = new JavaExample("BeginnersBook"); /* Passing the object as an argument to the constructor * This will invoke the copy constructor */ JavaExample obj2 = new JavaExample(obj1); obj1.disp(); obj2.disp(); } } |
输出:
1
2
|
Website: BeginnersBook Website: BeginnersBook |
要点回顾:
1. 每个类都有一个构造函数,不管它是普通类还是抽象类。
2. 构造函数不是方法,它们没有任何返回类型。
3. 构造函数名应该与类名匹配。
4. 构造函数可以使用任何访问说明符,它们也可以声明为私有。在java中可以使用私有构造函数,但是私有构造函数的作用域局限在类里面。
5. 我们也可以定义一个和类名相同的方法,但方法必须要定义返回值的数据类型,我们可以据此判断和类名相同的方法和构造函数的区别。
6. 如果我们没有在类中定义和实现任何构造函数,编译器就会在编译的时候自动在后台的代码中插入默认构造函数。
7. this()和super()这两个语句如果放在构造函数代码里面,一定要放在构造函数代码里面的第一行。如果我们的代码里面没有这两个语句,编译器会在后台的代码中自动插入这两个语句。
8. 构造函数可以重载(overload),但不能重写(override)。这意味着我们可以在类中重载(overload)构造函数,但不能重写(override)构造函数。
9. 构造函数不能继承。
10. 如果父类(super class)没有定义无参数构造函数(默认构造函数),那么编译器也不会自动在子类(child class)的后台代码里面自动插入默认构造函数。
11. 接口没有构造函数。
12. 抽象类可以有构造函数,抽象类的构造函数在创建具体类的对象的时候被调用到。
13. 构造函数代码里面还可以调用同一个类的另一个构造函数,使用方法就是通过调用this()方法,例如,在一个构造函数里面要调用另一个带参数的构造函数,可以用这样的写法:this(parameter list),这里parameter list就是传进去的几个参数。
构造函数(constructor)与方法(method)的区别
1. 构造函数的目的是初始化类的对象,而方法的目的是通过执行java代码来执行任务。
2. 构造函数不能是抽象的(abstract)、最终的(final)、静态的(static)和同步的(synchronised),而方法则可以是。
3. 构造函数没有返回类型,而方法有返回类型。
Java中的构造函数——通过示例学习Java编程(14)的更多相关文章
- Java中的数据类型——通过示例学习Java编程(5)
作者:CHAITANYA SINGH 来源:https://www.koofun.com//pro/kfpostsdetail?kfpostsid=15 数据类型用来定义变量可以采用的值,例如,如果变 ...
- Java中的变量——通过示例学习Java编程(4)
作者:CHAITANYA SINGH 来源:https://www.koofun.com/pro/kfpostsdetail?kfpostsid=14&cid= 变量是用来存放可以更改的值的容 ...
- java中的构造函数
在c++中就学习了构造函数,今天学习java又碰到了构造函数,重新写一篇博客来理解一下 其实直接听这个词并不能理解这是什么,但其实看了它的作用,就很好理解了 当创建一个对象时,往往需要做一些初始化工作 ...
- Hash Map 在java中的解释及示例
目录 HashMap在java中的应用及示例 HashMap的内部结构 HashMap的性能 同步HashMap HashMap的构造函数 HashMap的时间复杂度 HashMap的方法 1. vo ...
- Java中的构造函数和重载
一.Java中的构造函数 构造函数是对象被创建时初始化对象的成员方法,它具有和它所在的类完全一样的名字.构造函数只能有入口参数,没有返回类型,因为一个类的构造方法的返回类就是类本身.构造函数定义后,创 ...
- Java中有关构造函数的一道笔试题解析
Java中有关构造函数的一道笔试题解析 1.详细题目例如以下 下列说法正确的有() A. class中的constructor不可省略 B. constructor必须与class同名,但方法不能与c ...
- Java中的Swing及AWT又称GUI编程
Java中的Swing及AWT又称GUI编程. 关于学习Java要不要学Swing及AWT,这个完全取决于个人的开发及发展方向. 如果从事web方向的开发,则可以不用学习Swing及AWT. 如果从事 ...
- java中myeclipse连接mysql问题(java.lang.ClassNotFoundException: com.mysql.jdbc.Driver)
java中myeclipse连接mysql问题(java.lang.ClassNotFoundException: com.mysql.jdbc.Driver) 1.往项目中添加mysql-conne ...
- 第九节:详细讲解Java中的泛型,多线程,网络编程
前言 大家好,给大家带来详细讲解Java中的泛型,多线程,网络编程的概述,希望你们喜欢 泛型 泛型格式:ArrayList list= new ArrayList(); ArrayList list= ...
随机推荐
- RMI RPC socket
1.RPC RPC(Remote Procedure Call Protocol)远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC不依赖于具体的 ...
- dubbo设计实现的健壮性
Dubbo 作为远程服务暴露.调用和治理的解决方案,是应用运转的经络,其本身实现健壮性的重要程度是不言而喻的. 这里列出一些 Dubbo 用到的原则和方法. 日志 日志是发现问题.查看问题一个最常用的 ...
- BZOJ1503:[NOI2004]郁闷的出纳员
浅谈\(splay\):https://www.cnblogs.com/AKMer/p/9979592.html 浅谈\(fhq\)_\(treap\):https://www.cnblogs.com ...
- poj1325机器工作——二分图最小点覆盖
题目:http://poj.org/problem?id=1325 二分图求最大匹配,即为最小点覆盖: 一开始我写得较麻烦,求出最大匹配又去搜增广路,打标记求最小点覆盖: 然而两种方法都没写“ans= ...
- 实现PIX需要参考的标准资料
•初步了解PIX V2和V3:"IHE_ITI_TF_Rev8-0_Vol1_FT_2011-08-19"中第5章和第23章 •了解PIX V2相关事务: "IHE_IT ...
- 安装VMware-tools出现initctl: Job failed to start
安装VMware-tools中出现: ******* Creating a new initrd boot image for the kernel.update-initramfs: Generat ...
- 第一课、OpenGL绘制直线等等
第一课.OpenGL绘制直线等等 分类: [开发技术]OpenGL 2012-01-18 14:59 5217人阅读 评论(0) 收藏 举报 buffer图形c // // main.c // o ...
- HighChar
chart: { type:'bar', borderWidth:2, borderColor: '#CA5100', backgroundColor: '#90ED7D', shadow: { // ...
- C++的dllexport和dllimport
__declspec(dllexport) 声明一个导出函数,是说这个函数要从本DLL导出.我要给别人用.一般用于dll中省掉在DEF文件中手工定义导出哪些函数的一个方法.当然,如果你的DLL里全是C ...
- codeforces 352D - Jeff and Furik【期望dp】
首先恋人操作过一轮之后逆序对不会变多,所以设f[i]为把i个逆序对消掉的期望次数,f[i]=0.5f[i-2]+0.5f[i]+2,化简然后递推即可 #include<iostream> ...