• 【JavaSE】类与对象


    前言

    Java是一门纯面向对象的语言,在面向对象的世界里,一切都为对象。它是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。类与对象是我们学习面向对象最基础的知识,是面向对象实现的基石,可见它是有多么重要

    1. 面向对象的含义

    面向对象是一种编程思想,与之相对的还有面向过程,我们就拿炒菜这件事来解释一下这两者之间的区别

    面向过程:准备食材 — 打开油烟机 — 热锅加油 — 油热放入食材翻炒 — 加入调味品 — 出锅

    面向对象:食材、自动炒菜机、人、调味品,由这几个对象,我们就能完成炒菜这一件事

    在这个例子中,我们能够看出来面向过程跟面向对象,是两种不同的思维方式,处理问题的思考的角度不一样。面向过程中,我们注重的是炒菜这个过程是如何进行的;但在面向对象中,我们只需要注重完成炒菜需要哪些对象,通过对象之间的交互来完成,将它们组合在一起就行,完全不需要管具体的实现过程

    在Java中,一切皆对象,一切都围绕对象进行,我们只需要关心找对象、建对象,用对象等

    2. 类的定义和使用

    类:是用来对一个物体的属性和功能进行描述的。像生活中我们经常使用的手机,在Java中就可以看成一个类,手机品牌,型号,外观,材料都是它的属性;而打电话,上网,刷视频就是它的功能;这样我们就可以在Java中创建一个手机类

    对象:某个类的一个实体。我们可以用手机类创建出一部华为手机,此时这部手机就可以称之为一个对象,创建好了对象后,我们就可以来操作手机的属性和功能

    2.1 类的定义格式

    1. // 创建类
    2. class ClassName{
    3. field; // 成员变量/字段/属性
    4. method; // 成员方法/行为
    5. }
    • class是定义类的关键字,ClassName是类的名字,可以根据需求自己命名,取的尽量要有意义
    • 类中包含的内容称为类的成员,成员变量是用来描述类的,成员方法是用来说明类具有哪些功能

    注意事项:

    1. 类名要采用大驼峰单词命名法,即每个单词的首字母都要大写
    2. 一个源文件中只能存在唯一一个主类(用public修饰的类)
    3. 类的成员变量都有默认值:引用数据类型为null,基本数据类型为各自的0值,boolean类型为false

    2.2 类的实例化

    类的实例化指的就是用类创建对应的对象,在Java中我们采用new关键字,配合类来实例化对象

    1. 类名称 引用名称 = new 类名称( )
    2. 例如:
    3. Person person = new Person( );

    在上面的例子中,我们使用Person这个类创建了一个person对象,要注意的是,所有类的对象都是引用数据类型。所以person就是引用变量,变量名可以根据自己的需求命名

    我们可以把上面的例子再扩充一下,想一下人会有什么属性,有什么行为?

    1. class Person{
    2. //成员变量
    3. String name; //姓名
    4. int age; //年龄
    5. String gender; //性别
    6. //成员方法
    7. void run(){
    8. System.out.println(name+"在跑步~~~");
    9. }
    10. void print(){
    11. System.out.println("姓名:"+name+" 年龄:"+age+" 性别:"+gender);
    12. }
    13. }
    14. public class Test {
    15. public static void main(String[] args) {
    16. //创建一个实例化对象
    17. Person A = new Person();
    18. //通过对象来给对象的成员变量进行赋值,并使用成员方法
    19. A.name = "小A";
    20. A.age = 18;
    21. A.gender = "男";
    22. A.print();
    23. A.run();
    24. System.out.println("=========");
    25. //创建对象后不给成员变量赋值
    26. Person B = new Person();
    27. B.print();
    28. }
    29. }

    输出结果如下:

    我们可以用一个图来理解上面的代码

    从上面的例子中可以看到:在创建好类后,我们可以通过new来实例化多个对象,使用“对象名.”给成员变量一一赋值,也可以调用类中的成员方法实现各种功能;当我们没有初始化对象时,成员变量都会有各自类型对应的默认值

    2.3 类和对象的关系

    我们可以把类看成一张产品设计图,在设计图上面有产品的各种属性,还有产品附带的各种功能

    有了设计图,我们就可以根据设计图生产大量产品,生产出来的产品也附带有各种功能

    这种拿产品设计图来生产产品就等同于类实例化对象,一个类可以实例化出多个对象,而且实例化出来的对象也要占据内存空间,用来存储各自的成员变量

    补充说明

    下图展示的就是创建对象以及使用对象在计算机中的执行原理

    从图中我们可以得知:

    • 我们创建出来的对象在栈内存当中,变量里面记住的是对象的地址
    • 每次new对象,就是在堆内存中开辟一块内存区域代表一个对象
    • 类存在于方法区中

    3. this关键字

    3.1 什么是this

    this就是一个变量,可以用在方法中,来拿到当前对象;哪个对象调用方法,this就指向哪个对象,也就是拿到哪个对象。我们来看一下具体的例子

    1. class Student {
    2. public void printThis() {
    3. System.out.println(this);
    4. }
    5. }
    6. public class Test {
    7. public static void main(String[] args) {
    8. Student student = new Student();
    9. System.out.println(student);
    10. student.printThis();
    11. }
    12. }

    在上面的代码中,我们创建了一个学生类,并在里面定义了printThis方法,打印this的值;在Test主类中我们new了一个学生对象student,直接打印了student,同时也调用了printThis方法。

    在前面我们有讲到“创建出来的对象在栈内存当中,变量里面记住的是对象的地址”,那现在student里面装的就是对象的地址,我们来看一下运行结果

    通过结果我们可以看到:student和this打印出来的结果一模一样,都是对象的地址,也就是说:this指向的就是对象,它就是对象在方法中的分身

    3.2 this有什么作用

    • this主要用来解决:变量名称的冲突问题

    我们还是用上面的学生类来举例子,假设有一个学生,他在一次考试中考了59分,而及格分数要求不小于60分,我们用代码来实现一下这个情景

    1. class Student {
    2. double score;
    3. public void printfPass(double score) {
    4. if(score >= score) {
    5. System.out.println("通过考试~~~");
    6. } else {
    7. System.out.println("考试不及格~~~");
    8. }
    9. }
    10. }
    11. public class Test {
    12. public static void main(String[] args) {
    13. Student student = new Student();
    14. student.score = 59; //考试成绩
    15. student.printfPass(60); //及格分数
    16. }
    17. }

    运行结果如下

    为什么会出现这种情况呢?

    原因在于:我们的成员变量名和方法的形参名相同,导致考试成绩59压根就没有进入到方法里,本质上是及格分数60分在自己和自己比较,60肯定是不小于60,故输出“通过考试~~~”

    因此,我们需要在第一个score前面加上“this.”,这样就是避免变量名冲突产生的问题

    1. class Student {
    2. double score;
    3. public void printfPass(double score) {
    4. if(this.score >= score) { //第一个score前面加上this.
    5. System.out.println("通过考试~~~");
    6. } else {
    7. System.out.println("考试不及格~~~");
    8. }
    9. }
    10. }
    11. public class Test {
    12. public static void main(String[] args) {
    13. Student student = new Student();
    14. student.score = 59; //考试成绩
    15. student.printfPass(60); //及格分数
    16. }
    17. }

    这就是this引用所发挥的作用,除了this引用成员变量外,this还可以引用成员方法。当我们创建多个对象后,它们要使用同一个方法时,就可以在前面加上this引用,这样可以让编译器知道是哪个对象调用的方法

    总结一下:

    1. this就是一个变量,它指向的就是对象,它就是对象在方法中的分身
    2. this只能在成员方法中使用,不能再类(用static修饰的)方法中使用——这个在后面我们会详细讲解
    3. 在成员方法中,this只能引用当前一个对象
    4. 我们在写代码的过程中要习惯性地加上this,这样可以避免访问冲突的问题,减少不必要的麻烦

    4. 构造方法

    在前面的学习中,我们明白了如何去创建一个对象,但是在初始化对象的时候,我们使用对象引用成员变量一个一个初始化的,这未免有些麻烦

    1. //创建一个实例化对象
    2. Person A = new Person();
    3. //通过对象来给对象的成员变量进行赋值,并使用成员方法
    4. A.name = "小A";
    5. A.age = 18;
    6. A.gender = "男";
    7. A.print();
    8. A.run();

    哎,这时候,构造方法就能发挥作用了

    4.1 构造方法的定义

    构造方法,也叫做构造器。它是一种特殊的成员方法,它可以帮助我们更加方便地去初始化对象。而且构造方法的名字必须跟类名一样,我们在使用new创建对象时,实际上就是调用了当前类的构造方法。下面就是一个Student类的构造方法

    1. class Student {
    2. double score;
    3. //构造方法
    4. public Student(double score) {
    5. this.score = score;
    6. }
    7. }

    4.2 构造方法的语法规则

    1. 方法名和类名完全相同
    2. 构造方法没有返回值(也不能写void)
    3. 在一个类中至少存在一个构造方法,如果没有显示定义,那么编译器就会生成一个默认的无参构造
    4. 构造方法可以重载(我们可以根据需求来创建不同参数的构造方法)
    1. class Student {
    2. String name;
    3. int age;
    4. String gender;
    5. //编译器默认给的无参构造方法
    6. public Student() {
    7. }
    8. //自己创建的有参构造方法
    9. public Student(String name, int age, String gender) {
    10. this.name = name;
    11. this.age = age;
    12. this.gender = gender;
    13. }
    14. }
    15. public class Test {
    16. public static void main(String[] args) {
    17. Student student = new Student();
    18. Student student1 = new Student("张三",19,"男");
    19. }
    20. }

    通过构造方法,我们就可以在创建对象的时候边给它赋值,省去了一个一个变量赋值的麻烦

    如果我们不自己定义构造方法,那么编译器就会生成一份默认的无参构造方法,但如果我们自己定义了构造方法,编译器就不会生成了,说白了就是“救急不救穷”

    4.3 构造方法的重载

    关于构造方法的重载,我们得先来认识什么是重载?

    重载:就是方法名称相同,但是参数列表不相同(顺序、个数、类型)的情形,这样的同名不同参数的方法之间,就称之为方法的重载

    1. //编译器默认给的无参构造方法
    2. public Student() {
    3. }
    4. //自己创建的有参构造方法
    5. public Student(String name, int age, String gender) {
    6. this.name = name;
    7. this.age = age;
    8. this.gender = gender;
    9. }

    重载的好处在于:它方便了程序员可以根据不同的参数顺序、个数、类型来自动匹配方法,减少写多个方法名的重复步骤。所以我们在创建对象时,可以根据需要选择是否要初始化对象

    小技巧

    在idea中,它给我们提供了快速生成构造方法的途径

    这样就能让idea自动帮你生成有参构造方法啦

    5. 封装

    封装是面向对象的三大特征之一,其余两项分别是继承和多态,今天我们着重讲一下封装

    5.1 封装的定义

    封装:就是当我们用类去设计对象去处理某一个事物的数据时,应该把要处理的数据,以及处理数据的方法,设计到应该对象中去。简单来说——将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行交互,就是封装

    5.2 封装的设计规范

    合理隐藏、合理暴露。我们在设计封装的时候要牢记这“八字真言”。就像一辆汽车,它的内部是由很多成员的,比如发动机、油箱等器件,汽车设计者会用外壳把这些内部元器件都隐藏起来,只暴露出方向盘、刹车、油门这些器件供司机使用。这就是所谓的合理隐藏、合理暴露

    5.3 设计封装的示例

    如果我们想要公开成员,可以使用public来修饰,如果想要隐藏成员,可以使用private来修饰

    我们可以发现,成员变量name是用public修饰的,那在我们创建好student对象后,可以用对象引用直接调用它并赋值;而成员变量age是用private修饰的,我们用同样的方法却会报错。这是因为,public是公开的,面向任意包的任意类;而private就只能在当前类使用

    如果我们就是想要调用成员变量age,那要怎么做呢?

    我们可以在Student类里定义getAge和setAge方法,用来得到age和给age赋值。这两个方法使用public修饰的,相当于age的经纪人,它们可以让对象间接的接触到age,这样就能解决上面的问题了。而成员方法也是同理,用public就表示公开,用private就表示隐藏

    在一般情况下,我们会将成员变量设置为private,成员方法设置为public。诚然,实际情况还得根据业务需求来定,这里只是提供参考

    小技巧

    在idea中,它也给我们提供了快速get和set方法的途径

    这样就能让idea自动帮你生成get和set方法啦

    结语

    今天我们一起学习了Java当中的类与对象,还讲解了this关键字、构造方法以及封装的知识,希望大家能喜欢这篇文章,有总结不到位的地方还请多多谅解,若有出现纰漏,希望大佬们看到错误之后能够在私信或评论区指正,博主会及时改正,共同进步!

  • 相关阅读:
    基于ASP.NET的宠物寄养系统
    【百度AI_文字识别】示例身份证图片识别(代码官方文档完整,只需获得修改参数、下载类)
    关于我对axios的源码理解
    车载软件架构 --- SOA设计与应用(中)
    如何实现将拖动物体限制在某个圆形内--实现方式vue3.0
    优秀案例 | 三峡游客中心AI交互数字人“鲟侠船长”,数实融合赋能景区沉浸游玩体验
    导航守卫和拦截器
    抽象轻松java
    秋招面经第五弹:一家上市小公司二面-大数据开发工程师
    企业电子招投标系统源码之电子招投标系统建设的重点和未来趋势
  • 原文地址:https://blog.csdn.net/flmz_Kk/article/details/136546758