• 【Java SE】类和对象


    篮球哥温馨提示:编程的同时不要忘记锻炼哦!

    如果没有头绪,那就来杯咖啡吧


    目录

    1、面向对象的初识

    1.1 面向对象和面向过程的区别

    2、类的定义和使用

    2.1 什么是类?

    2.2 类的定义

    3、类的实例化

    3.1 什么是实例化 

    3.2 使用类实例化对象:

    3.3 类和对象的简单说明

    4、this 引用的认识

    4.1 为什么需要 this 引用

    4.2 什么是 this 引用?

    5、对象的构造和初始化

    5.1 如何初始化对象 

    5.2 构造方法

    5.3 默认初始化

    5.4 就地初始化


    1、面向对象的初识

    1.1 面向对象和面向过程的区别

    从本期开始,欢迎各位正式开始面向对象编程,Java 一门纯面向对象编程的语言,在它的世界里,一切皆为对象,面向对象和面向过程其实都是一种解决问题的思路,而面向对象主要是各个对象之间互相交互去完成一件事情。

    如果之前学习过C语言的小伙伴可能就知道,什么东西都需要自己造,要链表没有,要排序没有,要啥啥没有,而Java中你就不用担心这些,都给你准备好了,但是为了提高代码水平,后续我还是会带大家实现Java数据结构的。

    如果说拿洗衣服这件事情来说:

    面向过程的思路去解决的话可能就是,拿盆,放衣服,洗衣粉,接水,开始手搓,倒掉水,再接水,再次清洗,在倒掉水,接着拧干,洗衣服完毕。这就是面向过程。

    面向对象的思路去解决的话可能就是,把衣服扔进洗衣机,倒入洗衣粉,按下开始按钮,至于洗衣机如何洗我们不必关心,只关心最后把衣服洗完了。这就是面向对象。

    本质上他们只是解决问题的方法不同而已,我们不要存在偏见,各有各的应用场景!


    2、类的定义和使用

    2.1 什么是类?

    就拿冰箱举例吧,一个冰箱,有外观,有品牌,有尺寸大小,还有它的功能,比如杀菌,保鲜,冷藏等等 

    可以简单理解成冰箱的属性是:外观,品牌,大小....,功能是:杀菌,保险,冷藏....

    这些就可以理解成是一个类,类是用来对一个实体(对象)进行描述的,我们把上述对冰箱的描述可以称为对冰箱这个对象进行抽象,然后就可以采用Java来进行描述,当我们用类描述了一个对象,计算机就可以进行识别了,如何定义一个类呢?我们接着往下看:

    2.2 类的定义

    假设我们这里要定义一个学生类,我们需要先简单把这个对象给抽象出来,比如学生可以有:姓名,年龄,分数,课程(假设就一门),接着我们这个学生还有什么行为也可以抽象出来:比如说某某学生正在学习某某课程,或者某某学生正在睡觉,这些行为也可以抽象出来,然后就可以去定义一个类了:

    1. public class Student {
    2. //成员变量【属性】
    3. public String name; //姓名
    4. public int age; //年龄
    5. public float score; //分数
    6. public String subject; //课程
    7. //成员方法【行为】
    8. public void studySubject() {
    9. System.out.println(name + "正在学习" + subject);
    10. }
    11. }

    class 为定义类的关键字,后面跟着的是类型名:Student(统一采用大驼峰),class前面的是修饰符,我们目前用public,后续会讲到的,{ } 为类的主题,像上面代码注释中写的,类包含类的成员,和成员方法,可以有参无参,有返回值无返回值,都行,但是,此处的成员方法目前我们统一不带 static 关键字,后续也会讲,目前只是先初步学习。

    以上就是我们简单的定义了一个学生类,这里有几点要注意:

    • 我们建议一个文件中只定义一个类
    • 如果那个类中有 main 方法,一般使用 public 修饰(等学到修饰符就明白了)
    • public 修饰的类,类名必须跟文件名相同!
    • 如果要修改public修饰类的类名,请修改文件名,编译器会自动帮你更换

    类的定义中,只允许存在以下:

    成员变量,构造方法,代码块,成员方法,内部类


    3、类的实例化

    3.1 什么是实例化 

    到现在我们只是简单的认识了一下类和定义,那如何使用这个类呢?这就需要实例化,之前的学习中,我们定义一个变量 int a = 10;其实用的是 Java 中内置类型定义的,而当我们定义了一个类之后,就可以理解成是定义了一个新的类型,也就是自定义了一个类型。

    实例化本质就是用类去创建一个对象的过程,被称为类的实例化,再 Java 中我们使用 new 关键字配合类名来实例化对象,之前数组也见到过,经常说 new 一个对象,没毛病,就是这个道理,同理 new 出来的对象都是在堆上开辟空间的!

    3.2 使用类实例化对象:

    如何使用它呢?就拿我们上面定义的一个学生类来举例:

    1. public static void main(String[] args) {
    2. Student student = new Student();
    3. student.name = "张三";
    4. student.age = 20;
    5. student.score = 59.9f;
    6. student.subject = "Linux";
    7. }

    简单理解这里我们通过一个 Student 类来定义一个 student 变量而这个变量的类型是引用类型,引用了一个对象,这个对象是由 Student类 实例化出来的,所以这个引用里存的就是 new 出来对象的地址,同时我们通过 . 来调用对象里面的变量或者方法

    我们可以使用 java.lang.System 类的方法 identityHashCode() 可以返回对象的哈希码,在一定程度上反应真实的对象内存地址。

    System.out.println(System.identityHashCode(student));

    那么这里我们就简单来画个图,理解下在内存中的布局:

    当然我们也可以通过引用 . 去调用这个对象里面的方法,方法是在被调用的时候建立栈帧,所以是在JVM栈上开辟空间的,那我们就来通过上面的 student 来调用下对象里面的方法吧:

    这里我们只是创建了一个对象,当然一个类可以创建多个实例,也可以不用给每个成员变量都赋值,比如:

    1. public static void main(String[] args) {
    2. Student student1 = new Student();
    3. student1.name = "张三";
    4. student1.subject = "Linux";
    5. Student student2 = new Student();
    6. student2.name = "李四";
    7. student2.subject = "Java";
    8. student1.studySubject();
    9. student2.studySubject();
    10. }

    注意: 

    • new 关键字用于创建一个对象的实例
    • 使用 . 可以来访问对象中的属性和方法
    • 同一个类可以创建多个实例
    • 每次 new 一个对象,都会新开辟空间 

    3.3 类和对象的简单说明

    1. 类可以把它想象成一个模型,它是对一个实体的描述

    2. 类是一种自定义的类型,可以用来定义变量

    3. 一个类可以实例化出多个对象,实例化出的对象占实际的物理空间


    4、this 引用的认识

    4.1 为什么需要 this 引用

    假设这里我们要对前面的 Student 类进行修改,如果跟上面一样一个个初始化姓名年龄分数等太麻了,能不能在类中写一个方法可以用来一次性初始化里面的成员变量呢?当然是可以的:

    1. public class Student {
    2. //成员变量【属性】
    3. public String name; //姓名
    4. public int age; //年龄
    5. public float score; //分数
    6. public String subject; //课程
    7. //成员方法【行为】
    8. public void studySubject() {
    9. System.out.println(name + "正在学习" + subject);
    10. }
    11. public void setStudentData(String n, int a, float c, String s) {
    12. n = name;
    13. a = age;
    14. c = score;
    15. s = subject;
    16. }
    17. public static void main(String[] args) {
    18. Student student1 = new Student();
    19. student1.setStudentData("张三", 20, 59.9f, "Linux");
    20. Student student2 = new Student();
    21. student2.setStudentData("李四", 22, 89.8f, "Java");
    22. student1.studySubject();
    23. student2.studySubject();
    24. }
    25. }

    但是这里细心的小伙伴可能就发现了,你这个成员方法里面的形参名取得很随意啊,就不能跟成员变量名一样吗?如果我的形参名跟成员变量名一样了,那方法体中,是谁给谁赋值呢?成员变量给成员变量,还是形参给形参?但是在实际中,如果形参和成员变量名一样,则会是局部变量优先,所以也就是形参给自己赋值!

    第二个问题,我们 new 了两个对象,student1和student2分别引用了他们,这两个对象都在调用studySubject方法,这两个方法又是如何知道打印的是哪个对象的数据呢?

    如果想弄清楚这几个问题,请往后看:

    4.2 什么是 this 引用?

    this 引用是指向当前对象的!也就是在方法运行的时候调用该成员方法的对象,我们在成员方法中所有对成员变量的操作,本质是通过 this 引用去访问的!不过这些操作编译器帮我们做了,对于我们来说是透明的,也就是用户不需要传递,编译器自己搞定

    所以我们上面的 studySubject() 这个成员方法实际上是这样的:

    1. public void studySubject(Student this) {
    2. System.out.println(this.name + "正在学习" + this.subject);
    3. }

    这个地方,this 引用的是什么呢?其实就是哪个对象调用了这个成员方法,它引用的就是谁!this 代表了当前对象的引用

    如果是 student1.studySubject(),那么 this 接收的就是 student1,也就是说 this 在这里是成员方法第一个隐藏参数,编译器会自动传递,在成员方法执行的时候,编译器会负责将调用成员方法对象的引用传递给该成员方法,this 负责来接收,所以这就是为什么在成员方法内部我们能使用 this.成员变量 的操作了!

    现在使用 this 来解决我们上面成员方法命名的问题:

    1. public void setStudentData(String name, int age, float score, String subject) {
    2. this.name = name;
    3. this.age = age;
    4. this.score = score;
    5. this.subject = subject;
    6. }

    那我们在以后写代码在成员方法内部访问成员变量要不要加上 this 呢,虽然编译器会自动加上,但我们最好加上,不仅语义更明确,也可以避免形参与成员变量重名的情况

    所以目前我们知道了 this 引用的三个用法:

    • this 访问当前成员变量 this.
    • this 访问成员方法(在成员方法中,嵌套其他成员方法) this.
    • this 访问构造方法 this();

    5、对象的构造和初始化

    5.1 如何初始化对象 

    这个相信大家都在前面见到过了,可以使用 引用.成员变量  进行初始化,同时呢也可以像我们上面一样写一个成员方法来初始化,但是像以上两种做法还是比较麻烦的,因为每次都要实例化对象之后才能进行初始化,能不能做到在创建对象的同时给成员变量初始化呢?

    我们还知道一个点,变量不初始化是不能使用的,但是如果是对象的话,不初始化里面的成员变量是会有默认值的!这是为什么呢?

    5.2 构造方法

    构造方法是一种特殊的成员方法,也被称作为构造器,它特殊在哪呢?

    首先它的方法名必须与类名相同!没有返回类型!设置成void也不行,一般用public修饰,并且在创建对象的时候,自动调用,而且在整个对象的生命周期中只能调用一次!

    那么我们现在就在我们原有的 Student 类中添加一个构造方法:

    1. public class Student {
    2. //成员变量【属性】
    3. public String name; //姓名
    4. public int age; //年龄
    5. public float score; //分数
    6. public String subject; //课程
    7. //构造方法
    8. public Student(String name, int age, float score, String subject) {
    9. this.name = name;
    10. this.age = age;
    11. this.score = score;
    12. this.subject = subject;
    13. }
    14. //成员方法【行为】
    15. public void studySubject() {
    16. System.out.println(this.name + "正在学习" + this.subject);
    17. }
    18. public static void main(String[] args) {
    19. Student student1 = new Student("李四", 22, 89.8f, "Java");
    20. student1.studySubject();
    21. }
    22. }

    这里我们通过增加了一个带有参数的构造方法,可以看到,在创建对象的时候,就可以调用构造方法初始化了, 看到这,有的小伙伴大吃一惊,原来我们之前创建方法的时候不都是在调用一个无参的构造方法吗?是的!但是我们之气明明没有写构造方法啊,这是怎么回事?

    当我们没有任何构造方法的时候,编译器会给我们提供一个不带参数的构造方法!

    那我们现在写了一个构造方法,那如果下次再创建对象的时候,不传参呢?不行!因为只有在没有任何构造方法的时候,编译器才会提供,如果有了,我们在创建的时候不需要参数还得自己写一个无参的构造方法!而且构造方法的作用主要是给对象中成员进行初始化的!不负责给成员开辟空间! 

    上面这么一解释,我们既然可以有多个构造方法,但是构造方法的方法名必须与类名一样,那是不是说明构造方法支持重载!是的!构造方法支持重载!

    构造方法中,可以用 this 调用其他的构造方法,但是必须是第一条语句,而且不能成环调用,也就 this 调用的方法里不能还有 this 调用:

    1. public Student(String name, int age, float score, String subject) {
    2. this(name);
    3. this.name = name;
    4. this.age = age;
    5. this.score = score;
    6. this.subject = subject;
    7. }
    8. public Student(String name) {
    9. System.out.println(name + "构造成功!");
    10. }

    所以到现在我们就明白了一个点:当构造方法调用完成之后,对象才正真产生了! 

    5.3 默认初始化

    前面说过,没初始化对象中的成员变量是有默认值的,为啥呢?简单说一下,在JVM层面上,我们new一个对象,首先要检查类是否被加载,然后为对象分配空间,接着处理并发问题,为了保证分配的空间不冲突,再就是初始化所分配的空间,也就是初始化成默认值,再然后就是设置对象头信息这个后期讲,接着才是调用构造方法。

    那么他们的默认值是什么呢?这个参考我上期文章,里面有一个表格,写的很清楚。引用类型的默认值是 null。

    5.4 就地初始化

    就地初始化是什么意思呢?就是在我们定义类里面成员变量的时候就直接给初始值了,比如:

    1. public class Student {
    2. //成员变量【属性】
    3. public String name = "张三"; //姓名
    4. public int age = 20; //年龄
    5. public float score = 60.0f; //分数
    6. public String subject = "Linux"; //课程
    7. }

    这种会在编译完成后,编译器会将所有的成员初始化的这些语句添加到各个构造函数中,每个构造函数中默认会添加这些语句!


     

    下期预告:【Java SE】封装

  • 相关阅读:
    CodeWhisperer 的安装及体验
    绕圆旋转动画组件,拿过来直接用
    pdf增强插件 Enfocus PitStop Pro 2022 mac中文版功能介绍
    谈论 ModSecurity 和新的 Coraza WAF
    Uniapp 解决组件在官方文档不支持的事件上,接收小程序原生组件事件
    Java责任链模式源码剖析及使用场景
    如何将48位立即数加载到ARM通用寄存器中?
    通过Power Platform自定义D365CE业务需求 - 1. Microsoft Power Apps 简介
    循环冗余校验(CRC)原理及python实现
    day-01 Docker
  • 原文地址:https://blog.csdn.net/m0_61784621/article/details/126191310