【Java SE】类和对象(一)

本节目标

  1. 理解面向对象思想,区分面向过程与面向对象
  2. 掌握类的定义、成员变量、成员方法
  3. 掌握类的实例化,使用new创建对象,.访问成员
  4. 深度理解this引用的作用、特性、三种用法
  5. 掌握对象初始化:默认初始化、就地初始化、构造方法
  6. 掌握构造方法重载、构造方法中this(...)调用其他构造
  7. 理解直接打印对象、重写toString()

1. 面向对象初步认知

1.1 什么是面向对象

Java 是面向对象(OOP Object‑Oriented Program) 语言,思想:一切皆对象。 面向对象是一种解决问题的思维方式,依靠对象和对象之间交互来完成业务;更加贴合人类对现实事物认知,适合大型项目开发、扩展、维护。

1.2 面向过程 vs 面向对象(洗衣服案例)

  • 面向过程 :关注每一步执行的过程细节。 洗衣服:找衣服→放水→放洗衣粉→搓洗→漂洗→拧干晾晒。每一步都要自己做,流程固定。

缺点:业务改动(洗鞋子、洗被子),全部流程要重新写,维护扩展麻烦。

  • 面向对象 :关注对象实体,不关心内部实现细节。 洗衣服:把衣服丢进洗衣机对象,加洗衣粉,按下启动按钮,洗衣机对象帮你完成全部工作。

用户不需要关心洗衣机内部齿轮、电机如何转动,只调用对象提供的功能即可。
注意:面向过程、面向对象不是编程语言,是两套解决问题的思想,没有绝对好坏,各有适用场景。C 语言偏向面向过程;Java 以面向对象为主。

2. 类的定义和使用

现实中有洗衣机这个实体,计算机不能直接识别。我们需要对现实事物抽象 :提取事物的属性(特征)、行为(能干什么),这个抽象产物就是

洗衣机实体抽象:

  • 属性:品牌、型号、重量、长宽高、颜色
  • 行为:洗衣服、脱水、定时

2.1 类的语法格式

java 复制代码
class 类名{
    // 成员变量(属性、字段 field)
    // 成员方法(行为 method)
}
  • class:定义类的关键字
  • 类名:大驼峰命名法,每个单词首字母大写
  • 大括号内:类的成员,包含成员变量、成员方法。

现阶段成员统一写public修饰;本节的成员方法不带 static 关键字,是普通实例成员方法

洗衣机类完整示例
java 复制代码
class WashMachine{
    //成员变量(属性)
    public String brand;    //品牌
    public String type;     //型号
    public double weight;   //重量
    public double length;   //长
    public double width;    //宽
    public double height;   //高
    public String color;    //颜色

    //成员方法(行为)
    public void washClothes(){
        System.out.println("洗衣功能");
    }
    public void dryClothes(){
        System.out.println("脱水功能");
    }
    public void setTime(){
        System.out.println("定时功能");
    }
}

2.2 课堂练习

练习 1:Dog 宠物类

属性:名字 name,颜色 color 行为:barks () 叫,wag () 摇尾巴

java 复制代码
class PetDog {
    //成员变量
    public String name;
    public String color;

    //成员方法
    public void barks() {
        System.out.println(name + ": 旺旺旺~~~");
    }
    public void wag() {
        System.out.println(name + ": 摇尾巴~~~");
    }
}
练习 2:Student 学生类

属性:姓名 name、性别 gender、年龄 age、分数 score 行为:上课 DoClass、写作业 DoHomework、考试 Exam

java 复制代码
public class Student{
    public String name;
    public String gender;
    public short age;
    public double score;

    public void DoClass(){}
    public void DoHomework(){}
    public void Exam(){}
}

⚠️类定义注意事项

  1. 一个.java源文件建议只写一个类
  2. 如果类被public修饰,类名必须和文件名完全一致,大小写敏感
  3. 修改 public 类名,使用 IDE 重构修改,不要手动改文件名,避免不匹配。

3. 类的实例化(创建对象)

3.1 什么是实例化

  • class类:相当于设计图纸 ,是自定义新的数据类型,只描述事物有什么,不占用堆内存,没有真实数据
  • 实例化 :使用new + 类名,根据图纸,在堆内存创建真实对象。一张图纸(类)可以造出很多个实物对象。

语法:

java 复制代码
类名 引用变量 = new 类名();

示例,创建多个狗对象:

java 复制代码
public class Main{
    public static void main(String[] args) {
        PetDog dogh = new PetDog(); //实例化对象1
        PetDog dogs = new PetDog(); //实例化对象2
    }
}

3.2 使用.访问对象成员

.点运算符:对象引用.成员变量 / 对象引用.成员方法。

java 复制代码
public class Main{
    public static void main(String[] args) {
        PetDog dogh = new PetDog();
        dogh.name = "阿黄";
        dogh.color = "黑色";
        dogh.barks();
        dogh.wag();

        PetDog dogs = new PetDog();
        dogs.name = "赛虎";
        dogs.color = "黄色";
        dogs.barks();
        dogs.wag();
    }
}

输出:

java 复制代码
阿黄: 旺旺旺~~~
阿黄: 摇尾巴~~~
赛虎: 旺旺旺~~~
赛虎: 摇尾巴~~~

重点理解:

  1. 类是图纸模型,规定有哪些成员;不占堆内存。
  2. new出来的对象实例才占用堆物理内存,存储成员变量真实数据
  3. 一个类可以实例化出多个不同对象,每个对象成员变量互相独立。
  4. 引用变量存堆对象地址,通过.访问对象里面的内容。

4. this 引用(核心重点)

4.1 引出 this 的两个问题

写一个 Date 日期类:

java 复制代码
public class Date {
    public int year;
    public int month;
    public int day;

    public void setDay(int y, int m, int d){
        year = y;
        month = m;
        day = d;
    }
    public void printDate(){
        System.out.println(year + "/" + month + "/" + day);
    }

    public static void main(String[] args) {
        Date d1 = new Date();
        Date d2 = new Date();
        d1.setDay(2020,9,15);
        d2.setDay(2020,9,16);
        d1.printDate();
        d2.printDate();
    }
}

两个疑问:

  1. 如果形参名字和成员变量名字一模一样怎么办
java 复制代码
//形参名和成员变量重名!
public void setDay(int year, int month, int day){
    year = year; //局部变量year赋值给自己,成员变量完全没有修改!
    month = month;
    day = day;
}

就近原则:方法内部优先使用局部形参,成员变量被屏蔽,赋值无效。

  1. d1.printDate()d2.printDate()调用同一个方法,方法代码只有一份,方法怎么区分当前是哪个对象在调用自己?

4.2 this 引用是什么

this成员方法当中隐藏的引用,代表当前调用这个方法的对象 。 哪个对象调用成员方法,this就指向哪一个对象。编译器自动传递,我们看不见传参过程。

修复重名问题,使用this.成员变量

java 复制代码
public void setDay(int year, int month, int day){
    this.year = year;   //this.year 对象的成员变量;右边year是形参
    this.month = month;
    this.day = day;
}
public void printDate(){
    System.out.println(this.year + "/" + this.month + "/" + this.day);
}

4.3 this 引用核心特性

  1. this 的类型:就是当前类的引用类型。哪个对象调用,this 就是哪个对象的引用。
  2. this 只能在实例成员方法、构造方法内部使用,不能在 static 静态方法中使用
  3. this 代表当前对象,不能指向别的对象。
  4. this 是成员方法第一个隐藏参数 。调用d1.setDay(2020,9,15),编译器底层等价setDay(d1,2020,9,15),把对象引用 d1 传给形参 this。我们代码层面看不见这个参数。

4.4 this 的三种用法

  1. this.成员变量:访问当前对象的成员变量,解决局部变量与成员变量名字冲突(最常用)。
  2. this.成员方法():调用本类当中其他的实例成员方法。
  3. this(参数列表)只能写在构造方法第一行,调用本类其他构造方法。

注意:this()这种调用形式只能用于构造器,普通成员方法不能写 this ()

5. 对象的构造与初始化

5.1 局部变量 VS 对象成员变量

  • 局部变量(方法里面定义)不会自动默认初始化,使用前必须手动赋值,否则编译报错
java 复制代码
public static void main(String[] args) {
    int a;
    System.out.println(a); //编译报错:可能尚未初始化变量a
}
  • 类的成员变量(写在类里面,方法外面) :就算不手动赋值,也会有系统默认初始值,可以直接使用。
java 复制代码
Date d = new Date();
System.out.println(d.year); //输出0,有默认值

5.2 默认初始化规则

表格

数据类型 默认初始值
byte、short、int 0
long 0L
float 0.0f
double 0.0
char \u0000
boolean false
所有引用类型 (String、自定义类) null

5.3 就地初始化

在定义成员变量的时候直接写初始值,对象 new 出来就拥有该初始值。

java 复制代码
public class Date {
    public int year = 1900;
    public int month = 1;
    public int day = 1;
}

只要 new 对象,这些成员直接被赋值。后续构造方法还可以覆盖修改这些值。

5.4 构造方法(构造器 constructor)

5.4.1 构造方法概念

构造方法是特殊的成员方法

  1. 方法名字必须和类名完全一模一样,大小写一致
  2. 没有返回值,连 void 都不能写!
  3. new 对象() 的时候编译器自动调用构造方法,对象生命周期中只会执行一次
  4. 作用:对象创建的时候,给成员变量做初始化。

示例:

java 复制代码
public class Date {
    public int year;
    public int month;
    public int day;

    //构造方法
    public Date(int year, int month, int day){
        this.year = year;
        this.month = month;
        this.day = day;
        System.out.println("Date(int,int,int)方法被调用了");
    }

    public void printDate(){
        System.out.println(year + "-" + month + "-" + day);
    }

    public static void main(String[] args) {
        // new的时候自动调用构造方法
        Date d = new Date(1999,6,9);
        d.printDate();
    }
}
5.4.2 构造方法重点注意事项
  1. 名字必须与类名完全相同。
  2. 不许写返回值,写 void 也是错误,不再是构造方法,变成普通成员方法
  3. new 对象时自动调用,对象一生只调用一次。
  4. 构造方法支持重载:方法名相同,参数列表不同,构成重载
java 复制代码
public class Date {
    //无参构造
    public Date(){
        this.year = 1900;
        this.month = 1;
        this.day = 1;
    }
    //三参构造
    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
}
  1. 编译器默认无参构造规则

如果我们一个构造方法都没有手写 ,编译器自动帮我们生成一份无参的默认构造方法 。 ⚠️一旦我们手写了任意一个构造方法(有参构造),编译器不再提供默认无参构造 !此时new Date()直接编译报错。

错误示例:只写有参构造,再想无参实例化对象编译失败

java 复制代码
public class Date {
    public int year;
    public int month;
    public int day;

    //手写有参构造,编译器不再生成无参构造!
    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
    public static void main(String[] args) {
        Date d = new Date(); //编译报错,找不到无参构造方法!
    }
}
  1. 构造方法内部使用this(...)调用本类其他构造方法

语法:this(实参列表) ✅强制规则:必须写在构造方法的第一行!不能放在中间或者末尾;禁止互相循环调用,会编译报错

java 复制代码
public class Date {
    public int year;
    public int month;
    public int day;

    public Date(){
        this(1900,1,1); //调用三参构造,必须第一行
    }
    public Date(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }
}

❌错误循环调用,编译报错

java 复制代码
public Date(){
    this(1900,1,1);
}
public Date(int year, int month, int day) {
    this(); //互相调用,循环,报错
}
  1. 绝大多数场景构造方法使用public;特殊场景使用private(单例模式后续讲解)。

6. 对象打印与 toString ()

直接打印对象引用变量:

java 复制代码
class Person {
    String name;
    String gender;
    int age;
    public Person(String name, String gender, int age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }
}
public static void main(String[] args) {
    Person person = new Person("Jim","男", 18);
    System.out.println(person);
}

输出类似:Person@1b6d3586

格式:类全限定名@哈希码,不是对象里面的数据。

想要直接打印输出对象内部成员属性,重写toString()方法,把对象信息拼接成字符串返回。

java 复制代码
class Person {
    String name;
    String gender;
    int age;
    public Person(String name, String gender, int age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }
    @Override
    public String toString() {
        return "[" + name + "," + gender + "," + age + "]";
    }
}
public static void main(String[] args) {
    Person person = new Person("Jim","男", 18);
    System.out.println(person);
}

输出:[Jim,男,18]

@Override注解表示重写父类方法,继承章节详细讲解。 System.out.println(对象)底层会自动调用对象的toString()得到字符串输出。

7. 课后习题

选择题:找出错误选项

A. 一个类只能实例化一个对象 B. 一个引用可以同时指向多个对象 C. Person p = null; 表示 p 这个引用指向一个空对象 D. 当一个类没有定义构造方法的时候,该类中不会默认生成构造方法

答案:A B C D 全部错误 解析:

  • A 错误:一个类可以 new 出很多个实例对象。
  • B 错误:一个引用同一时刻只能保存一个对象的地址,不能同时指向多个。
  • C 错误:null代表引用不指向任何对象,不存在 "空对象"。
  • D 错误:没有手写任何构造,编译器自动生成默认无参构造。

代码改错题,找出所有编译错误

java 复制代码
class Person {
    public String name;
    public int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static void main(String[] args) {
        Person person1 = new Person();
        person1.name = "zhangsan";
        person1.age = 10;
        System.out.println(person1.name);

        Person person2 = new Person("zhangfei");
        person2.age = 10;
        System.out.println(person2.name);

        Person person3 = new Person("lisi",9);
        System.out.println(person3.name);
    }
}

错误分析:

  1. 手写了两参构造,编译器不再生成无参构造new Person()无参实例化编译报错。
  2. new Person("zhangfei"),没有一个构造是接收单独一个字符串参数,参数列表不匹配编译报错。

修复方案:补充对应重载构造方法。

java 复制代码
//补充无参构造
public Person(){}
//补充单参构造
public Person(String name){
    this.name = name;
}

📔本篇核心考点总结

  1. 面向对象:类是图纸,对象是 new 出来的实物;类描述属性(成员变量)、行为(成员方法)。
  2. 实例化:类名 引用 = new 类名();.访问成员;一个类可以多个对象。
  3. this:实例成员方法内代表当前调用方法的对象this.成员变量解决名字冲突;this(...)调用其他构造,必须放在构造第一行。
  4. 局部变量必须手动初始化;类的成员变量自带默认初始值
  5. 构造方法:类名相同,无返回值,new 自动调用一次;支持重载;
    • 不手写任何构造,编译器提供默认无参构造;
    • 只要手写任意构造,编译器不再生成默认无参构造。
  6. this(其他构造)仅在构造方法内使用,第一行,禁止循环调用。
  7. 直接打印对象输出类名@哈希;重写toString()可以打印对象属性信息。

面试简答 Q:构造方法能不能写 void? A:不能,写 void 之后就不再是构造方法,变成普通成员方法,new 的时候不会自动调用。 Q:this()可以放在普通成员方法里面吗? A:不行,只能写在构造方法第一行。 Q:成员变量和局部变量区别? A:成员变量有默认初始值;局部变量没有,必须手动赋值才能使用。

相关推荐
captain3761 小时前
网络原理(4)-TCP
java·服务器·网络·网络协议·tcp/ip·java-ee
青山木1 小时前
枚举类DP进阶:完全平方数与零钱兑换
java·数据结构·算法·leetcode·动态规划
小七在进步1 小时前
类和对象(二)
java·开发语言
醉古意1 小时前
使用 IntelliJ IDEA 工具创建Spring AI项目
intellij-idea·spring ai
clz13145211 小时前
风险特征平台架构设计与实现
java·flink
写后端的胖头鱼2 小时前
【高频面试题】面试题里常出现的Bitmap是什么(附源码和多种场景)
java·开发语言·面试·位图·bitmap
学习智者2 小时前
《玄》IDE v3.8.2重磅发布:数据外置+全链路优化
开发语言·c++·ide·中文语言 玄
benbenAItalk10 小时前
数字人口播视频的批量生产实践:素材规范、任务编排与质量验收
java·前端·音视频
sunshine22 girl10 小时前
Java学习二 基本语法2, 算术运算符
java·学习