1. 为什么需要面向对象
在面向过程编程中,我们把程序拆成一个个函数,数据与操作数据的逻辑往往是分离的。随着项目变复杂,这种方式会带来两个问题:
- 数据的状态散落在各处,难以维护;
- 代码复用困难,修改一处可能影响全局。
面向对象(Object-Oriented Programming,OOP)的核心思想是:把数据和对数据的操作捆绑在一起,用“对象”来模拟现实世界的事物。这样写出来的代码更接近人类的思维方式,也更容易维护和扩展。
本文是面向对象系列的第一篇,我们从最基础的两个概念开始:类和对象。
2. 类与对象的关系
2.1 什么是类
类是对象的模板或蓝图,它描述了一类事物共有的属性和行为。
- 属性:描述事物的特征,对应代码中的变量;
- 行为:描述事物能做什么,对应代码中的方法。
2.2 什么是对象
对象是类的具体实例。类是抽象的,对象是具体的。
以“学生”为例:
Student是类,它描述了所有学生都有姓名、学号等属性,以及上课、考试等行为;- 具体某个学生(如“张三”)就是一个对象。
用一句话总结:类是模板,对象是按模板造出来的具体实例。
2.3 代码示例
下面用 Java 定义一个最简单的学生类,并创建两个对象:
publicclassStudent{// 属性Stringname;StringstudentId;// 行为publicvoidstudy(){System.out.println(name+" 正在学习");}}创建对象并使用:
publicclassMain{publicstaticvoidmain(String[]args){// 使用 new 关键字创建对象Studentzhangsan=newStudent();zhangsan.name="张三";zhangsan.studentId="2024001";zhangsan.study();Studentlisi=newStudent();lisi.name="李四";lisi.studentId="2024002";lisi.study();}}运行结果:
张三 正在学习 李四 正在学习可以看到,同一个类可以创建出多个对象,每个对象都有自己独立的数据。
3. 封装:把数据保护起来
上面的写法有一个明显的问题:name和studentId被声明为公开的,外部代码可以随意修改。比如:
zhangsan.name="";用面向对象的第二个重要概念——封装,可以解决这个问题。封装的思路是:
- 把属性设置为私有(
private); - 提供公开的
getter和setter方法,在方法里做数据校验。
改写后的Student类:
publicclassStudent{// 属性私有化privateStringname;privateStringstudentId;publicStringgetName(){returnname;}publicvoidsetName(Stringname){if(name==null||name.isEmpty()){thrownewIllegalArgumentException("姓名不能为空");}this.name=name;}publicStringgetStudentId(){returnstudentId;}publicvoidsetStudentId(StringstudentId){this.studentId=studentId;}publicvoidstudy(){System.out.println(name+" 正在学习");}}封装带来的好处:
- 数据更安全,外部无法绕过校验直接修改;
- 修改内部实现时,不影响使用该类的代码;
- 代码职责更清晰。
4. 构造方法:简化对象初始化
创建对象后还要一个个调用setter很麻烦,我们可以引入构造方法。构造方法在创建对象时自动调用,用于完成初始化。
publicclassStudent{privateStringname;privateStringstudentId;// 无参构造方法publicStudent(){}// 带参构造方法publicStudent(Stringname,StringstudentId){this.name=name;this.studentId=studentId;}publicvoidstudy(){System.out.println(name+" 正在学习");}}创建对象时就简洁多了:
Studentzhangsan=newStudent("张三","2024001");zhangsan.study();构造方法的特点:
- 方法名必须与类名相同;
- 没有返回值类型;
- 如果不写构造方法,编译器会提供一个默认的无参构造方法;一旦写了任何构造方法,默认的无参构造方法就不再自动提供。
5. 完整的入门示例
综合以上内容,一个完整的Student类如下:
publicclassStudent{privateStringname;privateStringstudentId;publicStudent(){}publicStudent(Stringname,StringstudentId){if(name==null||name.isEmpty()){thrownewIllegalArgumentException("姓名不能为空");}this.name=name;this.studentId=studentId;}publicStringgetName(){returnname;}publicStringgetStudentId(){returnstudentId;}publicvoidstudy(){System.out.println(name+"("+studentId+") 正在学习");}}测试代码:
publicclassMain{publicstaticvoidmain(String[]args){Studentzhangsan=newStudent("张三","2024001");Studentlisi=newStudent("李四","2024002");zhangsan.study();lisi.study();}}这是一个典型的面向对象写法:数据(属性)被封装在类内部,通过构造方法和行为对外提供有限的访问方式。
6. 小结
本篇我们掌握了三个核心内容:
- 类与对象:类是模板,对象是实例;
- 封装:属性私有化,通过
getter/setter访问,保护数据安全; - 构造方法:在创建对象时完成初始化。