Java基础—面向对象之构造方法
一、构造方法的介绍
开发过程中经常需要在创建对象的同时明确对象的属性,比如员工刚入职公司就要明确他的姓名、年龄等属性信息。
那么在创建对象就要明确属性值,如何实现呢?也就是在创建对象的时候就要做的事情,当使用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 }