一、构造方法的介绍
开发过程中经常需要在创建对象的同时明确对象的属性,比如员工刚入职公司就要明确他的姓名、年龄等属性信息。
那么在创建对象就要明确属性值,如何实现呢?也就是在创建对象的时候就要做的事情,当使用new关键字创建对象时,怎么给对象属性初始化值呢?这里就要用到Java的构造方法。
那么什么是构造方法?从字面理解即为构建创造时用的方法,既对象创建时要执行的方法。既然是对象创建时候要执行的方法,那么只要在new对象时,知道其执行的构造方法是什么,就可以在执行这个方法的时候给对象进行属性赋值。
构造方法定义语法的格式:
修饰符 构造方法名(参数列表){}
构造方法的特点:
1、构造方法无返回值类型,如:void等。也不需要写返回值,因为它是为构建对象的,对象创建完,方法就执行结束。
2、构造方法名称必须和本类的名称保持一致。
构造方法的代码体现:
1 public class Person {
2 private String name;
3 private int age;
4
5 /*
6 * 定义出Person类无参的构造方法
7 */
8 public Person() {
9
10 }
11
12 /*
13 * 定义出Person类含有参数的构造方法
14 */
15 public Person(String name,int age) {
16 //System.out.println("我是一个空参数的构造方法");
17 this.name = name;
18 this.age = age;
19 }
二、构造方法的调用和图解说明
首先看构造方法是如何执行的呢?在创建对象的时候是如何初始化的呢?
构造方法是专门用来创建对象,也就是在new对象的时要调用构造方法,如下面的代码体现:
1 public class Person {
2 // Person的成员属性age和name
3 private int age;
4 private String name;
5
6 // Person的构造方法,拥有参数列表
7 Person(int a, String nm) {
8 // 接受到创建对象时传递进来的值,将值赋给成员属性
9 this.age = a;
10 this.name = nm;
11 }
12
13 public void speak() {
14 System.out.println("name=" + name + ",age=" + age);
15 }
16 }
17 /*
18 * 测试类PersonDemo
19 * */
20 class PersonDemo {
21 public static void main(String[] args) {
22 // 创建Person对象,并明确对象的年龄和姓名
23 Person p = new Person(23, "张三");
24 p.speak();
25 }
上述代码对创建对象时,对构造方法的调用。既在创建对象时,会调用与参数列表对应的构造方法。
上述代码的构造方法原理图:
上述原理图说明:
内存加载的过程:
有一个Person类, 创建Person 对象new Person()
1、首先会将main方法压入栈中,执行main方法中的 new Person(23,"张三");
2、在堆内存中分配一片区域,用来存放创建的Person对象,这片内存区域会有属于自己的内存地址(0x001)。然后给成员变量进行默认初始化(name=null,age=0)。
3、执行构造方法中的代码(age = a ; name = name;),将变量a对应的23赋值给age,将变量name对应的”张三赋值给name,这段代码执行结束后,成员变量age和name的值已经改变。执行结束之后构造方法弹栈,Person对象创建完成。将Person对象的内存地址0x001赋值给p。
三、默认构造方法和细节描述
在描述事物的场景下,并没有显示指定构造方法,当在Java编译的时候,编译器会自动给class文件中添加默认的构造方法。如果描述类时,指定了构造方法,那么在编译器在编译Java源文件时,编译器就不会再给class文件中添加默认的构造方法。
代码显示如下:
1 public class Person {
2 //如果没有显示指定构造方法,编译会在编译时自动添加默认的构造方法
3 //空参数的默认构造方法
4 public Person(){}
5 // 有参构造方法
6 public Person(String name,int age){
7 this.name = name;
8 this.age = age;
9 }
10 }
什么样的场景下,需要用到构造方法?
这种情况下根据事物的描述特点来定,当描述的对象在创建的同时必须要明确其属性值,这个时候就要在定义类的时候写上带参数的构造方法,若创建对象不需要明确的具体数据,这时不需要书写构造方法。
构造方法的细节有哪些呢?
1、一个类中可以有多个构造方法,构造方法都是以重载的形式存在
2、构造方法是可以被private修饰的,作用:其它程序无法创建该类的对象
1 class Person {
2 private int age;
3 private String name;
4
5 // 私有无参数的构造方法,即外界不能通过new Person();语句创建本类对象
6 private Person() {
7 }
8
9 // 多个构造方法是以重载的形式存在
10 Person(int a) {
11 age = a;
12 }
13
14 Person(String nm, int a) {
15 name = nm;
16 age = a;
17 }
18 }
四、构造方法和一般方法的区别
构造方法和一般方法有什么异同呢?
1、构造方法在对象创建时就执行,而且只执行一次
2、一般方法是在创建对象后,需要使用时候才被调用,并可以被多次调用
3、格式不同
构造方法:修饰符 类名 (参数类型 参数){}
一般方法:修饰符 返回值类型 方法名(参数类型 参数){}
4、调用方法不同
构造方法创建对象时候就默认调用,或this()、super()调用
普通方法需要对象调用或静态方法直接调用静态方法
5、作用不同
构造方法一般是用来给成员变量进行初始化
一般方法根据需要而定
有了构造方法,还需要一般方法中的set、get方法吗?
答案是毋庸置疑的需要,因为在创建对象后,当需要对属性值进行修改或访问时,就需要set和get方法来操作。
五、this调用构造方法
一般方法可以根据方法名调用,而构造方法可以通过this关键字来完成构造方法之间的调用。
构造方法调用格式:
this(参数列表);
构造方法之间的调用:
1 public class Person {
2 // Person的成员属性
3 private int age;
4 private String name;
5
6 // 无参数的构造方法
7 public Person() {
8 }
9
10 // 给姓名初始化的构造方法
11 public Person(String nm) {
12 this.name = nm;
13 }
14
15 // 给姓名和年龄初始化的构造方法
16 public Person(String nm, int a) {
17 // 由于已经存在给姓名进行初始化的构造方法 name = nm;因此只需要调用即可
18 // 调用其他构造方法,需要通过this关键字来调用
19 this(nm);
20 // 给年龄初始化
21 this.age = a;
22 }
23 }
六、this调用构造方法的原理图
首先来上一段代码:
1 public class Person {
2 private String name;
3 private int age;
4
5 // 无参构造方法
6 public Person() {
7 // 调用了有参的构造方法
8 // 参数李斯,20传递给了变量name,age
9 this("李四", 20);
10 }
11 // 有参构造方法
12 /*
13 * 构造方法,传递String,int
14 * 在创建对象的同时为成员变量赋值
15 * */
16 public Person(String name,int age) {
17 this.name = name;
18 this.age = age;
19 }
20 }
21
22 // 测试代码
23 public class Test {
24 public static void main(String[] args) {
25 // 创建Person的对象,调用空参数的构造方法
26 // 运行的结果是默认的null和0
27 Person p = new Person();
28
29 System.out.println(p.getAge());
30 System.out.println(p.getName());
31 }
32 }
原理图:
分析:
1、先执行main方法,main方法压栈,执行其中的new Person(“李四”,20);
2、堆内存中开辟空间,并为其分配内存地址0x01,,紧接着成员变量默认初始化(name=null age = 0);
3、拥有两个参数的构造方法(Person(String nm , int a))压栈,在这个构造方法中有一个隐式的this,因为构造方法是给对象初始化的,那个对象调用到这个构造方法,this就指向堆中的那个对象。
4、由于Person(String nm , int a)构造方法中使用了this(nm);构造方法Person(String nm)就会压栈,并将“张三”传递给nm。在Person(String nm , int a)构造方法中同样也有隐式的this,this的值同样也为0x33,这时会执行其中name = nm,即把“张三”赋值给成员的name。当赋值结束后Person(String nm , int a)构造方法弹栈。
5、程序继续执行构造方法(Person(String nm , int a)中的age = a;这时会将23赋值给成员属性age。赋值结束构造方法(Person(String nm , int a)弹栈。
6、当构造方法(Person(String nm , int a)弹栈结束后,Person对象在内存中创建完成,并将0x33赋值给main方法中的p引用变量
七、成员变量和局部变量的同名问题
在平时的场景中,当方法中出现局部变量和成员变量同名的时候,那么在方法中怎么区分?
可以在成员变量前面加上this来区分和局部变量
1 public class Person {
2 private int age;
3 private String name;
4
5 // 给姓名和年龄初始化的构造方法
6 public Person(String name, int age) {
7 // 当需要访问成员变量是,只需要在成员变量前面加上this.即可
8 this.name = name;
9 this.age = age;
10 }
11
12 public void speak() {
13 System.out.println("name=" + this.name + ",age=" + this.age);
14 }
15 }
16
17 class PersonDemo {
18 public static void main(String[] args) {
19 Person p = new Person("张三", 23);
20 p.speak();
21 }
22 }
八、this的应用
需求:在Person类中定义功能,判断两个人是否是同龄人
1 public class Person {
2 private int age;
3 private String name;
4
5 // 给姓名和年龄初始化的构造方法
6 public Person(String name, int age) {
7 // 当需要访问成员变量是,只需要在成员变量前面加上this.即可
8 this.name = name;
9 this.age = age;
10 }
11
12 public void speak() {
13 System.out.println("name=" + this.name + ",age=" + this.age);
14 }
15
16 // 判断是否为同龄人
17 public boolean equalsAge(Person p) {
18 // 使用当前调用该equalsAge方法对象的age和传递进来p的age进行比较
19 // 由于无法确定具体是哪一个对象调用equalsAge方法,这里就可以使用this来代替
20 /*
21 * if(this.age == p.age) { return true; } return false;
22 */
23 return this.age = p.age;
24 }
25 }