构造方法
在开发中经常要在创建对象的时候明确其属性值, 比如员工一入职公司就要明确他的 姓名年龄等信息.
构造方法就是对象创建时要执行的方法
修饰符 构造方法名(参数列表){
}
构造方法没有返回值类型也不需要写返回值, 因为他是为了构建对象的, 对象构建完, 方法就执行结束. 构造方法名必须和类型保持一致, 没有具体的返回值.
- class Person {
- // Person 的成员属性 age 和 name
- private int age;
- private String name;
- // Person 的构造方法, 拥有参数列表
- Person(int a, String nm) {
- // 接受到创建对象时传递进来的值, 将值赋给成员属性
- age = a;
- name = nm;
- }
- }
构造方法调用和内存图解
构造方法是专门用来创建对象的, 也就是在 new 对象是要调用构造方法.
- class person{
- //person 的成员属性 name 和 age
- Private int age;
- Private String name;
- //person 的构造方法
- person(int a,String nm){
- age=a;
- name=nm;
- }
- public void speak() {
- System.out.println("name=" + name + ",age=" + age);
- }
- }
- class PersonDemo {
- public static void main(String[] args) {
- // 创建 Person 对象, 并明确对象的年龄和姓名
- Person p2 = new Person(23, "张三");
- p2.speak();
- }
- }
- // 上述代码演示了创建对象时构造方法的调用. 即在创建对象时, 会调用与参数列表对应的构造方法.
l 图解说明:
1, 首先会将 main 方法压入栈中, 执行 main 方法中的 new Person(23,"张三");
2, 在堆内存中分配一片区域, 用来存放创建的 Person 对象, 这片内存区域会有属于自己的内存地址(0x88). 然后给成员变量进行默认初始化(name=null,age=0).
3, 执行构造方法中的代码(age = a ; name = nm;), 将变量 a 对应的 23 赋值给 age, 将变量 nm 对应的 " 张三赋值给 name, 这段代码执行结束后, 成员变量 age 和 name 的值已经改变. 执行结束之后构造方法弹栈, Person 对象创建完成. 将 Person 对象的内存地址 0x88 赋值给 p2.
默认构造方法和细节
在没有学习构造方法之前, 我们也可以通过 new 关键字创建对象, 并调用相应的方法, 同时在描述事物时也没有写构造方法. 这是为什么呢?
在之前学习的过程中, 描述事物时, 并没有显示指定构造方法, 当在编译 Java 文件时, 编译器会自动给 class 文件中添加默认的构造方法. 如果在描述类时, 我们显示指定了构造方法, 那么, 当在编译 Java 源文件时, 编译器就不会再给 class 文件中添加默认构造方法.
当在描述事物时, 要不要在类中写构造方法呢? 这时要根据描述事物的特点来确定, 当描述的事物在创建其对象时就要明确属性的值, 这时就需要在定义类的时候书写带参数的构造方法. 若创建对象时不需要明确具体的数据, 这时可以不用书写构造方法(不书写也有默认的构造方法).
构造方法的细节:
一个人类中可以有多个构造方法, 多个构造方法是以重载的形式存在
构造方法是可以被 private 修饰的, 作用: 其他程序无法创建该类对象
- class Person {
- private int age;
- private String name;
- // 私有无参数的构造方法, 即外界不能通过 new Person(); 语句创建本类对象
- private Person() {
- }
- // 多个构造方法是以重载的形式存在
- Person(int a) {
- age = a;
- }
- Person(String nm, int a) {
- name = nm;
- age = a;
- }
- }
构造方法和一般方法区别
构造方法在对象创建时就执行了, 且只执行一次
一般方法在对象创建后 需要使用时才被对象调用, 可以被多次调用
有了构造方法之后可以对对象的属性进行初始化, 那么还需要对应的 set 和 get 方法吗?
需要相应的 set 和 get 方法, 因为对象在创建之后需要修改和访问相应的属性值时, 在这时只能通过 set 或者 get 方法来操作.
this 关键字
在之前学习方法之间调用时, 可以通过方法名进行调用. 可是针对构造方法, 无法通过构造方法名来相互调用.
构造方法之间的调用, 可以通过 this 关键字来完成.
l 构造方法调用格式:
- this(参数列表);
- class Person {
- // Person 的成员属性
- private int age;
- private String name;
- // 无参数的构造方法
- Person() {
- }
- // 给姓名初始化的构造方法
- Person(String nm) {
- name = nm;
- }
- // 给姓名和年龄初始化的构造方法
- Person(String nm, int a) {
- // 由于已经存在给姓名进行初始化的构造方法 name = nm; 因此只需要调用即可
- // 调用其他构造方法, 需要通过 this 关键字来调用
- this(nm);
- // 给年龄初始化
- age = a;
- }
- }
内存图解 this 调用构造方法
l 图列说明:
1, 先执行 main 方法, main 方法压栈, 执行其中的 new Person("张三",23);
2, 堆内存中开辟空间, 并为其分配内存地址 0x33,, 紧接着成员变量默认初始化(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 引用变量.
l 注意:
this 代表的是对象, 哪个对象调用了 this 所在的方法, this 就代表哪个对象.
调用其他构造方法的语句必须定义在构造方法的第一行, 原因是初始化动作要最先执行.
可以在成员变量名前面加上 this. 来区别成员变量和局部变量
- class Person {
- private int age;
- private String name;
- // 给姓名和年龄初始化的构造方法
- Person(String name, int age) {
- // 当需要访问成员变量是, 只需要在成员变量前面加上 this. 即可
- this.name = name;
- this.age = age;
- }
- public void speak() {
- System.out.println("name=" + this.name + ",age=" + this.age);
- }
- }
- class PersonDemo {
- public static void main(String[] args) {
- Person p = new Person("张三", 23);
- p.speak();
- }
- }
在 Person 类中定义功能, 判断两个人是否是同龄人
- class Person {
- private int age;
- private String name;
- // 给姓名和年龄初始化的构造方法
- Person(String name, int age) {
- // 当需要访问成员变量是, 只需要在成员变量前面加上 this. 即可
- this.name = name;
- this.age = age;
- }
- public void speak() {
- System.out.println("name=" + this.name + ",age=" + this.age);
- }
- // 判断是否为同龄人
- public boolean equalsAge(Person p) {
- // 使用当前调用该 equalsAge 方法对象的 age 和传递进来 p 的 age 进行比较
- // 由于无法确定具体是哪一个对象调用 equalsAge 方法, 这里就可以使用 this 来代替
- /*
- * if(this.age == p.age) { return true; } return false;
- */
- return this.age = p.age;
- }
- }
Super 关键字:
子父类中构造方法的调用
在创建子类对象时, 父类的构造方法会先执行, 因为子类中所有构造方法的第一行有默认的隐式 super(); 语句.
格式:
调用本类中的构造方法
this(实参列表);
调用父类中的空参数构造方法
super();
调用父类中的有参数构造方法
super(实参列表);
为什么子类对象创建都要访问父类中的构造方法? 因为子类继承了父类的内容, 所以创建对象时, 必须要先看父类是如何对其内容进行初始化的,
- public class Test {
- public static void main(String[] args) {
- new Zi();
- }
- }
- class Fu{
- int num ;
- Fu(){
- System.out.println("Fu 构造方法"+num);
- num = 4;
- }
- }
- class Zi extends Fu{
- Zi(){
- //super(); 调用父类空参数构造方法
- System.out.println("Zi 构造方法"+num);
- }
- }
执行结果:
Fu 构造方法 0
Zi 构造方法 4
通过结果发现, 子类构造方法执行时中, 调用了父类构造方法, 这说明, 子类构造方法中有一句 super().
那么, 子类中的构造方法为什么会有一句隐式的 super()呢?
原因: 子类会继承父类中的内容, 所以子类在初始化时, 必须先到父类中去执行父类的初始化动作. 这样, 才可以使用父类中的内容.
当父类中没有空参数构造方法时, 子类的构造方法必须有显示的 super 语句, 指定要访问的父类有参数构造方法.
类对象创建的过程
如果子类的构造方法第一行写了 this 调用了本类其他构造方法, 那么 super 调用父类的语句就没有了
因为 this()或者 super(), 只能定义在构造方法的第一行, 因为初始化动作要先执行.
父类构造方法中是否有隐式的 super 呢?
也是有的. 记住: 只要是构造方法默认第一行都是 super();
父类的父类是谁呢? super 调用的到底是谁的构造方法呢?
Java 体系在设计, 定义了一个所有对象的父类 Object
类中的构造方法默认第一行都有隐式的 super()语句, 在访问父类中的空参数构造方法. 所以父类的构造方法既可以给自己的对象初始化, 也可以给自己的子类对象初始化.
如果默认的隐式 super()语句在父类中没有对应的构造方法, 那么必须在构造方法中通过 this 或者 super 的形式明确要调用的构造方法.
描述学生和工人这两个类, 将他们的共性 name 和 age 抽取出来存放在父类中, 并提供相应的 get 和 set 方法, 同时需要在创建学生和工人对象就必须明确姓名和年龄
- // 定义 Person 类, 将 Student 和 Worker 共性抽取出来
- class Person {
- private String name;
- private int age;
- public Person(String name, int age) {
- // super();
- this.name = name;
- this.age = age;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- }
- class Student extends Person {
- // Student 类的构造方法
- Student(String name, int age) {
- // 使用 super 关键字调用父类构造方法, 进行相应的初始化动作
- super(name, age);
- }
- public void study() {// Studnet 中特有的方法
- System.out.println(this.getName() + "同学在学习");
- }
- }
- class Worker extends Person {
- Worker(String name, int age) {
- // 使用 super 关键字调用父类构造方法, 进行相应的初始化动作
- super(name, age);
- }
- public void work() {// Worker 中特有的方法
- System.out.println(this.getName() + "工人在工作");
- }
- }
- public class Test {
- public static void main(String[] args) {
- Student stu = new Student("小明",23);
- stu.study();
- Worker w = new Worker("小李",45);
- w.work();
- }
- }
来源: http://www.bubuko.com/infodetail-2655517.html