zl程序教程

您现在的位置是:首页 >  后端

当前栏目

《java练级之路》之类和对象,保姆式教学带你深入了解构造方法!!!

JAVA对象 深入 了解 教学 构造方法 之类
2023-09-27 14:29:29 时间

🎇🎇🎇作者:
@小鱼不会骑车
🎆🎆🎆专栏:
《java练级之旅》
🎓🎓🎓个人简介:
一名专科大一在读的小比特,努力学习编程是我唯一的出路😎😎😎
在这里插入图片描述

🙈🙈🙈作者心里话

小鱼一直都是秉承着“开开心心看博客,快快乐乐学知识”这个观点来给大家用一些接地气的话进行讲解,可能会有人觉得小鱼太墨迹了,小鱼这里也很乐意接受大家的意见,会进行采纳,大家也可以指出小鱼的不足,小鱼也会积极的进行改变,总之,愿我们越来越优秀

前言
这次我们讲到了类和对象的第二部分,其中包含的内容会在思维导图中给大家展现出来。
在这里插入图片描述

🍊默认初始化

因为后续会多次用到默认初始化的这个知识点,这里提前给大家讲解一下
在这里插入图片描述
我们经过对比可以清晰的看到,我们的局部变量a在没有初始化的时候,经过使用,编译器是不给通过的,但是我们的变量b却可以,并且还可以正常输出,这就涉及到了关于成员变量的初始化,

要搞清楚这个过程,就需要知道 new 关键字背后所发生的一些事情:

Person person=new Person;//new了一个对象

在程序层面只是简单的一条语句,在JVM层面需要做好多事情,下面简单介绍下:

  1. 检测对象对应的类是否加载了,如果没有加载则加载
  2. 为对象分配内存空间
  3. 处理并发安全问题

比如:多个线程同时申请对象,JVM要保证给对象分配的空间不冲突
大家可以简单理解为,只要我new了这个对象,那么我的成员变量就是被初始化过的了。

初始化所分配的空间
也就是系统默认初始化给赋的值

数据类型默认值
byte0
char'\u0000
short0
int0
long0L
booleanfalse
float0.0f
double0.0

认识一下什么是成员变量和局部变量
在这里插入图片描述

🍊1.0 this引用

🍒1.1 为什么要有this引用

大家先看这段代码,

class Person {
    public int age;//年龄
    public String name;//姓名
    public void set(int a,String b) {
        age = age;
        name = name;
    }
    public void sleep() {
        System.out.println(name+" 在睡觉");
    }
    public void eat() {
        System.out.println(name+" 在吃饭");
    }
}
public class BoKe {
    public static void main(String[] args) {
    // 构造三个人的类型的对象 person1,person2,person3
        Person person1=new Person();//创建对象
        Person person2=new Person();
        Person person3=new Person();
        person1.set(10,"张三");//初始化
        person2.set(11,"李四");
        person3.set(12,"王五");
        person1.eat();//打印
        person2.eat();
        person3.eat();
    }
}

我们创建了一个Person类的方法,并且在main方法里面创建对象并且赋值,这个代码大家看是不是应该没什么问题啊,那我给大家抛出两个疑问
问题1:
如果我的成员变量名和我的形参名一样会发生什么?

 public void set(int age,String name) {
        age = age;
        name = name;
    }

问题2:
我的编译器怎么知道我要赋值的对象是哪个引用的,编译器不会弄混嘛,毕竟我并没有传递可以证明我是谁的对象的信息啊?

在这里插入图片描述

🍒1.2 什么是this引用

  • 第一种:this.成员变量(此时编译器就能分辨出哪个是成员变量)this用来区分局部变量和成员变量;(是this 点 成员量)
  • 第二种:this用来指代对象本身,(类里面的方法要通过对象来调用,即:对象.方法()。此时this就代表调用方法的对象)

🍓1.2.1 解决重名问题

   public void set(int age,String name) {
        this.age = age;//用this.来证明我的这个age是成员变量
        this.name = name;
    }

如果我们不用this去修饰一下这个age,那么就会因为重名的问题出现一些错误,当然编译器是识别不出来的,因为没有语法上的错误。

🍓1.2.2 为什么编译器能识别我是调用的是哪个对象的方法

其实我们的成员方法中是有一个隐藏参数的,该参数的类型是类名,在这里插入图片描述
大家可以看到我在person1中只是传了两个参数,但是我的set方法中有三个参数,为什么没有警告呢?其实是我们的Person this是一个隐藏参数,其中Person是该参数的类型,也就是该类的类名,这个参数我们写不写都是一样的,只不过写出来大家可以更好的对比,如果不写编译器也会自动添加的,大家再看紫色框框里的数,是不是都是483,大家可以粗略的把这个看成一个地址吧,我们的这三个地址都是一样的,那就是说明我调用的这个成员方法就是我person1的这个对象的成员方法,这就是编译器如何识别是谁的对象的原因。

🍓1.2.4 总结

  • 要养成多使用this,不光是增加了代码的可阅读性,也可以避免这些重名的错误
  • this的类型和之前对象的类型是一致的
  • this只能在成员方法中使用,其他方法无法使用
  • 成员方法中,this只能引用当前对象,不能再引用其他对象。
  • 最通俗易懂的话:谁调用这个方法,谁就是这个this

🍊2.0 对象的构造及初始化

🍒2.1 如何初始化对象

class Person {
    public int age;//年龄
    public String name;//姓名
    public void set(Person this,int a,String b) {
        age = a;
        name = b;
    }
    public void sleep() {
        System.out.println(name+" 在睡觉");
    }
    public void eat() {
        System.out.println(name+" 在吃饭");
    }
}
public class BoKe {
    public static void main(String[] args) {
        Person person1=new Person();
        Person person2=new Person();
        Person person3=new Person();
        person1.set(10,"张三");
        person2.set(11,"李四");
        person3.set(12,"王五");
        person1.eat();
        person2.eat();
        person3.eat();
    }
}

大家再来看看这个代码,是不是发现,我每次都需要在new这个对象之后才能进行赋值,是不是好麻烦,我们可不可以在调用这个对象时就把赋值完成呢?请往下看

🍒2.2 构造方法

构造方法(也称为构造器)是一个特殊的成员方法,名字必须与类名相同,在创建对象时,由编译器自动调用,并且
在整个对象的生命周期内只调用一次。

🍓2.2.1 概念

前面讲到了,构造方法时编译器自动调用的,可是我并没有写构造方法啊?那编译器调用的是什么?

  • 问题一:构造方法如何创建
  • 问题二:默认构造方法是什么
  • 问题三:如何实现含有参数的构造方法

🍉2.2.1.1 问题一加问题二

在这里插入图片描述
构造方法只需要参数和类名就可以构建,不需要返回值,void也不可以,如果写void就不是构造函数!!!
并且,如果我们不去自己写这个构造方法,编译器会默认生成一个构造方法,也就是跟图片一样格式。所以这就是为什么我们不写构造函数也不会报错的原因

🍉2.2.1.2 问题三

前面讲到了,如果可以在new对象的时候就把参数输入进去就好了,现在就带大家实现,含有参数的构造方法
在这里插入图片描述
这样我们就可以在创建这个对象时,就将成员变量初始化,构造方法并不负责给对象开辟空间
在这里插入图片描述
我们就可以这样通过new对象时进行传参。

🍓2.2.2 构造方法进阶

注意事项

  1. 名字必须与类名相同
  2. 没有返回值类型,设置为void也不行
  3. 创建对象时由编译器自动调用,并且在对象的生命周期内只调用一次(相当于人的出生,每个人只能出生一次)

🍉2.2.2.1 构造方法的重载

对于重载,大家应该都知道,重载的条件

  • 参数不同(最重要!!!)
  • 方法名相同
  • 与返回类型无关
class Person {
    public int age;//年龄
    public String name;//姓名

    public Person(int age, String name) {//重载构造方法
        this.age = age;
        this.name = name;
    }
    public Person() {//重载构造方法

    }
    public void sleep() {
        System.out.println(name+" 在睡觉");
    }
    public void eat() {
        System.out.println(name+" 在吃饭");
    }
}
public class BoKe {
    public static void main(String[] args) {
        Person person1=new Person(10,"张三");
        Person person2=new Person();
    }
}

大家可以看到,我们写了两个构造方法在类中,相同点就是方法名一样,不同的就是参数,那么这样的话,我们可以选择在初始化时就传参,也可以选择初始化的时候不传参。
有一个需要注意事项!!!
当我们写了构造方法之后,编译器就不会提供了,如果我没有写一个无参的构造方法,但是我却new了一个无参的对象,那么编译器就会报错.
在这里插入图片描述

🍉2.2.2.2 构造方法中,可以通过this调用其他构造方法来简化代码

在这里插入图片描述

this要单独写,不需要去点任何方法或字段,并且
在这里插入图片描述
我们的this要放到第一行,不然会报错!!!
也不可以形成环,例如
在这里插入图片描述
这样就会陷入死循环,当然前提是代码可以成功编译

🍒2.3 就地初始化

最后一个,就地初始化
在声明成员变量时,就直接给出了初始值.

class Person {
    public int age=10;//年龄
    public String name="张三";//姓名
    public Person() {
    }
}
public class BoKe {
    public static void main(String[] args) {
        Person person2=new Person();
    }
}

注意:代码编译完成后,编译器会将所有给成员初始化的这些语句添加到各个构造函数中