news 2026/7/19 14:45:54

17. 【Java】类(抽象)与对象:万物皆对象

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
17. 【Java】类(抽象)与对象:万物皆对象

摘要:本文是 Java 面向对象编程的入门指南,旨在帮助初学者理解类与对象的核心概念。文章通过生动的比喻(如“图纸”与“实物”)阐释了类作为蓝图、对象作为实例的关系,详细讲解了如何定义类、创建对象、使用构造方法以及理解内存模型,并通过实战案例展示了如何用面向对象思维重构程序。

关键词:Java, 面向对象编程, 类, 对象, 构造方法


我们已经完成了前两个阶段的学习。掌握了变量、运算符、循环、方法、数组、字符串……现在已经能写出像“命令行计算器”这样实用的程序了。

但我们之前写代码的方式,更像是“按流程办事”:先做 A,再做 B,再做 C。这种思维叫面向过程。它适合解决一些相对简单的问题,比如计算器、排序、数据处理。

可现实世界是复杂的。你不是在“处理流程”,你是在和“人”、“物”、“事”打交道。一个电商系统里有用户、商品、订单;一个学校系统里有学生、老师、课程——这些“东西”都有自己的属性(叫什么、多大了)和行为(能做什么)。

如果只用面向过程的方式去建模,你会发现代码越来越乱,数据和方法散落在各处,修改一个地方可能会影响几十个地方。

我们需要一种更接近人类认知世界的方式来组织代码。这就是面向对象编程(Object-Oriented Programming,简称 OOP)

今天,我们来迈出面向对象的第一步:理解类(Class)对象(Object)


1. 从“流程”到“世界” —— 思维方式的转变

在面向过程的世界里,程序像是一份菜谱:第一步切菜,第二步热油,第三步下锅翻炒……步骤清晰,但所有食材都是“被操作”的,它们本身没有“灵魂”。

在面向对象的世界里,程序更像是一个舞台剧:舞台上有很多“角色”(对象),每个角色都有自己的属性(名字、年龄、外貌)和行为(走路、说话、唱歌)。导演(你的程序)通过给角色发送指令(调用方法),让整个舞台运转起来。

这种思维方式的转变,是学习 Java 最关键的一步。它不只是一个技术问题,更是一个世界观问题。

你可以这样想:面向过程是“我要怎么做”,面向对象是“谁来做这件事”。前者强调步骤,后者强调责任。


2. 类和对象 —— 一个是“图纸”,一个是“实物”

在 Java 里,有两个紧密相连但完全不同的概念:

  • 类(Class):是模板、是蓝图、是设计图。它定义了某类事物应该有什么属性(数据)和行为(方法),但它本身不是具体的东西。
  • 对象(Object):是根据类创建出来的具体实例。它是实实在在存在于内存中的东西,有自己的状态。

打个比方:

  • = 一张“汽车设计图纸”。它上面画了汽车应该有四个轮子、一个方向盘、一个发动机,也画了汽车可以“启动”、“加速”、“刹车”。但图纸本身不是汽车,你不能开着它上路。
  • 对象= 根据这张图纸造出来的一辆真车。它有具体的颜色、具体的车牌号、具体的里程数。你可以坐进去,发动它,开走它。

同一个类可以创建出无数个对象。比如从同一张“学生设计图”可以造出张三、李四、王五——他们都有姓名、年龄、学号,但具体值各不相同。


3. 定义一个类 —— 画出你的“设计图”

在 Java 中,定义类的语法我们其实已经见过无数次了:

publicclassStudent{// 属性(成员变量)Stringname;intage;StringstudentId;// 行为(成员方法)publicvoidstudy(){System.out.println(name+" 正在学习...");}publicvoidsayHello(){System.out.println("你好,我是 "+name+",今年 "+age+" 岁。");}}

这是一个最简单的类定义。它描述了“学生”这个概念:

  • 学生有属性name(姓名)、age(年龄)、studentId(学号)
  • 学生有行为study()(学习)、sayHello()(打招呼)

我们还没有加privatepublic这些修饰符——那是“封装”的内容,我们下一篇再讲。现在先让所有属性都是默认的(包可见),一切从简。

注意:一个 Java 文件可以定义多个类,但public修饰的类必须和文件名一致。我们通常一个文件只写一个类。


4. 创建对象 —— 把“图纸”变成“实物”

有了类这个“设计图”,我们就可以用它来创建具体的对象了。创建对象使用new关键字:

publicclassMain{publicstaticvoidmain(String[]args){// 根据 Student 类,创建一个具体的学生对象Students1=newStudent();// 给对象的属性赋值s1.name="张三";s1.age=20;s1.studentId="2024001";// 调用对象的行为s1.sayHello();// 输出:你好,我是 张三,今年 20 岁。s1.study();// 输出:张三 正在学习...// 创建另一个学生对象Students2=newStudent();s2.name="李四";s2.age=22;s2.studentId="2024002";s2.sayHello();// 输出:你好,我是 李四,今年 22 岁。}}

看到了吗?s1s2是两个完全独立的对象。它们都来自同一个Student类,但各自有各自的nameagestudentId。修改s1name不会影响s2


5. 构造方法 —— 对象创建的“生产线”

刚才我们创建对象的方式是两步走:

Students1=newStudent();// 1. 先创建空对象s1.name="张三";// 2. 再手动赋值

这样有点麻烦。更好的方式是在创建对象的同时就把属性设置好。这就要用到构造方法(Constructor)

构造方法是一种特殊的方法,它的名字必须和类名完全一样,并且没有返回值类型(连void都不写)。它会在new的时候自动被调用,用来初始化对象。

publicclassStudent{Stringname;intage;StringstudentId;// 无参构造方法publicStudent(){// 可以什么都不做,或者给默认值}// 有参构造方法:创建对象的同时传入姓名、年龄、学号publicStudent(Stringname,intage,StringstudentId){this.name=name;// this.name 是成员变量,name 是参数this.age=age;this.studentId=studentId;}publicvoidsayHello(){System.out.println("你好,我是 "+name+",今年 "+age+" 岁。");}}

然后创建对象就变得很简洁了:

Students1=newStudent("张三",20,"2024001");s1.sayHello();// 直接就有值了,不需要再一行行赋值
关于this

在构造方法(以及后面的 setter 方法)中,我们经常看到this.name = name;这种写法。

  • this是一个关键字,它表示“当前对象本身”。
  • 当成员变量和局部变量(比如构造方法的参数)重名时,this.name明确表示“这个对象的name字段”,而name表示参数。
  • 如果你不写this,编译器会优先使用局部变量(参数),导致成员变量没有被赋值,这是一个很隐蔽的 bug。
// 错误写法(没有 this)publicStudent(Stringname,intage,StringstudentId){name=name;// 两边都是参数,成员变量没被赋值!}

所以this在构造方法和 setter 中几乎是必须的。养成习惯,只要成员变量和参数同名,就用this区分。

构造方法的注意事项
  • 如果你没有定义任何构造方法,Java 会默认给你一个无参构造方法
  • 但如果你定义了任何一个有参构造方法,Java不会再给你默认的无参构造方法。如果你还需要无参的,必须手动写出来。
  • 构造方法可以重载(多个构造方法参数不同),就像普通方法一样。

6. 类与对象的内存模型 —— “图纸”和“实物”在哪儿?

我们粗略了解一下内存分配,这对理解“引用类型”很有帮助。

当你写Student s1 = new Student("张三", 20, "2024001");时,内存里发生了两件事:

  1. 在堆内存(Heap)中:创建了一个Student对象,里面存储了name="张三"age=20studentId="2024001"这些数据。
  2. 在栈内存(Stack)中:创建了一个局部变量s1,它里面存储的不是对象本身,而是对象的地址(一个指向堆内存中那个对象的引用)。

所以,s1就像是一个“遥控器”,它指向真正的对象。当你用s1.sayHello()时,Java 会通过这个遥控器找到堆中的对象,然后执行它的方法。

这也解释了为什么:

Students1=newStudent("张三",20,"2024001");Students2=s1;// s2 指向同一个对象s2.name="李四";System.out.println(s1.name);// 输出 "李四"

因为s1s2指向的是同一个对象,通过s2修改了对象的属性,s1看到的内容自然也跟着变了。


7. 实战:用面向对象的方式重构“个人名片生成器”

还记得我们在第 6 篇写的“个人名片生成器”吗?那时候我们用数组来传递信息,不够优雅。现在学了面向对象,我们可以用来封装这些信息了。

// 文件:Person.javapublicclassPerson{Stringname;intage;Stringcity;Stringmotto;// 无参构造publicPerson(){}// 全参构造publicPerson(Stringname,intage,Stringcity,Stringmotto){this.name=name;this.age=age;this.city=city;this.motto=motto;}// 行为:打印名片publicvoidprintCard(){System.out.println("\n===== 你的专属名片 =====");System.out.println("姓名:"+name);System.out.println("年龄:"+age+"岁");System.out.println("城市:"+city);System.out.println("座右铭:\""+motto+"\"");System.out.println("------------------------");System.out.println("愿你如座右铭所言,活出精彩!");}}
// 文件:Main.javaimportjava.util.Scanner;publicclassMain{publicstaticvoidmain(String[]args){Scannerscanner=newScanner(System.in);System.out.println("===== 欢迎来到「个人名片生成器」 =====");System.out.print("请输入你的姓名:");Stringname=scanner.nextLine();System.out.print("请输入你的年龄:");intage=Integer.parseInt(scanner.nextLine());System.out.print("请输入你所在的城市:");Stringcity=scanner.nextLine();System.out.print("请输入你的座右铭:");Stringmotto=scanner.nextLine();// 用类来封装数据,而不是数组Personperson=newPerson(name,age,city,motto);person.printCard();scanner.close();}}

看到了吗?代码变得更清晰、更可读了。Person类把数据和操作数据的方法放在了一起,这就是面向对象的封装思想。我们下一篇会深入讲它。


8. 面向对象的核心思想

今天的内容其实已经触及了面向对象编程的三个核心特性之一——封装(把数据和操作数据的方法放在一起)。另外两个是继承多态,我们会在后面的文章中慢慢展开。

面向对象的四个核心概念:

  1. 抽象(Abstraction):从具体事物中提取出共同的、本质的特征,形成类的过程。比如从张三、李四、王五中抽象出“学生”这个概念。
  2. 封装(Encapsulation):把数据和操作数据的方法绑定在一起,并对外隐藏内部细节。比如你把手机的内部电路封装起来,用户只需要按键(调用方法),不需要知道电路怎么工作的。
  3. 继承(Inheritance):一个类可以基于另一个类来定义,复用父类的属性和方法。
  4. 多态(Polymorphism):同一个行为(比如“叫”),不同对象可以有不同的实现方式(猫叫、狗叫、狮子叫)。

这些概念我们接下来会逐一展开。


9. 给初学者的几个小建议

  • 不要试图一下就理解所有面向对象的概念。今天先理解“类就是图纸,对象就是实物”,把这个比喻刻在脑子里。
  • 多定义自己的类。看到任何一个现实中的事物(书、汽车、员工、课程),试着用类去描述它有哪些属性、哪些行为。
  • 学会区分“谁做”和“怎么做”:面向对象的核心是把责任分配到对象上,而不是集中在主方法里。

今天的总结

今天我们跨过了面向对象的第一道门槛:

  • :是模板、是蓝图,定义了一类事物的属性和行为。
  • 对象:是根据类创建的具体实例,有自己独立的状态。
  • 构造方法:用来在创建对象时初始化属性,名字与类名相同,无返回值。
  • this:指向当前对象本身,用来区分成员变量和参数。
  • 内存模型:对象在堆中,引用在栈中。
  • 我们用面向对象的方式重构了“个人名片生成器”,感受到了类带来的清晰和便利。

面向对象不仅仅是一种编程技术,更是一种思维方式。它帮助你从“我需要做什么”的视角,转变为“谁来做这件事”的视角。这个转变一旦完成,你写程序的方式就再也回不去了。


动手试试

  1. 定义一个Book类,包含title(书名)、author(作者)、price(价格)三个属性,和一个displayInfo()方法打印书籍信息。然后在main中创建两个Book对象,调用方法显示它们的信息。
  2. Book类添加构造方法,在创建对象时直接初始化所有属性。
  3. 定义一个Car类,包含brandcolorspeed属性,以及accelerate()(加速,速度 +10)、brake()(刹车,速度 -10)、displayStatus()(显示当前速度)三个方法。在main中创建一辆车,加速几次、刹车几次,观察状态变化。
  4. 用面向对象的方式重新实现“猜数字游戏”:把游戏逻辑封装成一个GuessGame类,包含targetattemptsguessed等属性,以及guess(int num)isGuessed()getAttempts()等方法。

面向对象的练习非常关键——它不是在练语法,而是在练思维。多写几个类,你会越来越有感觉。

我们下一篇见。😃

📌 获取本系列示例代码请访问 GitCode。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/19 14:45:12

pgagroal常见问题排查:连接泄漏、性能瓶颈和故障诊断全指南

pgagroal常见问题排查:连接泄漏、性能瓶颈和故障诊断全指南 【免费下载链接】pgagroal High-performance connection pool for PostgreSQL 项目地址: https://gitcode.com/gh_mirrors/pg/pgagroal pgagroal作为PostgreSQL的高性能连接池,在实际应…

作者头像 李华
网站建设 2026/7/19 14:42:39

终极Citra模拟器指南:5分钟在电脑畅玩任天堂3DS游戏的完整教程

终极Citra模拟器指南:5分钟在电脑畅玩任天堂3DS游戏的完整教程 【免费下载链接】citra A Nintendo 3DS Emulator 项目地址: https://gitcode.com/GitHub_Trending/ci/citra 还在寻找在电脑上重温《精灵宝可梦》、《塞尔达传说》等任天堂3DS经典游戏的最佳方式…

作者头像 李华
网站建设 2026/7/19 14:42:35

GIMP秒变Photoshop:3分钟完成界面转换的终极免费方案

GIMP秒变Photoshop:3分钟完成界面转换的终极免费方案 【免费下载链接】GimpPs Gimp Theme to be more photoshop like 项目地址: https://gitcode.com/gh_mirrors/gi/GimpPs 你是否曾因GIMP的界面与Photoshop差异太大而感到困扰?现在,…

作者头像 李华
网站建设 2026/7/19 14:42:32

Excel 函数大全

一、逻辑判断函数函数语法核心功能IFIF(条件, 满足时返回, 不满足时返回)单条件判断,最基础的分支函数ANDAND(条件1,条件2,...)所有条件同时成立返回 TRUEOROR(条件1,条件2,...)任一条件成立返回 TRUENOTNOT(条件)对条件结果取反IFSIFS(条件1,结果1,条件2,结果2,...…

作者头像 李华
网站建设 2026/7/19 14:41:58

CapTipper核心组件揭秘:从pcap解析到HTTP流量可视化的实现原理

CapTipper核心组件揭秘:从pcap解析到HTTP流量可视化的实现原理 【免费下载链接】CapTipper Malicious HTTP traffic explorer 项目地址: https://gitcode.com/gh_mirrors/ca/CapTipper CapTipper是一款强大的恶意HTTP流量探索工具,能够帮助安全分…

作者头像 李华