第9章 类和对象把数据和行为放在一起第一阶段的项目“成绩统计器”已经能处理多个成绩。但它有一个明显问题我们只保存了分数没有保存学生是谁。如果继续用基础写法可能会变成这样String[]names{Tom,Jack,Lucy};int[]scores{90,58,76};这看起来能用但问题很多姓名和成绩靠下标关联顺序一乱数据就错。想给学生加年龄、学号、班级要继续增加数组。判断某个学生是否及格只能写外部工具逻辑。数据和行为是分散的。面向对象的第一步就是把属于同一个事物的数据和行为放在一起。一、从“多个数组”到“一个对象”一个学生应该是一个整体学生 学号 姓名 分数 是否及格用 Java 类表达publicclassStudent{Stringid;Stringname;intscore;booleanisPassed(){returnscore60;}}创建对象StudentstudentnewStudent();student.idS001;student.nameTom;student.score90;System.out.println(student.name);System.out.println(student.isPassed());这里Student是类。student是对象。id、name、score是字段。isPassed是方法。二、类是模板对象是具体实例类像模板规定这种对象有什么数据和行为。publicclassStudent{Stringid;Stringname;intscore;}对象是根据模板创建出来的具体东西。StudenttomnewStudent();tom.nameTom;StudentjacknewStudent();jack.nameJack;tom和jack是两个不同对象。Student类id/name/scoretom对象Tom,90jack对象Jack,58类只有一份定义但对象可以创建很多个。三、字段对象自己的状态字段也叫成员变量。publicclassStudent{Stringid;Stringname;intscore;}每个对象有自己的字段值StudenttomnewStudent();tom.nameTom;tom.score90;StudentjacknewStudent();jack.nameJack;jack.score58;tom.score和jack.score互不影响。字段表示对象状态。状态变化意味着对象当前情况变了。比如jack.score65;Jack 从不及格变成及格。四、方法对象自己的行为把是否及格写在对象内部publicclassStudent{Stringid;Stringname;intscore;booleanisPassed(){returnscore60;}}调用System.out.println(tom.isPassed());System.out.println(jack.isPassed());同一个isPassed方法在不同对象上使用不同对象的 score。这和 static 工具方法不同publicstaticbooleanisPassed(intscore){returnscore60;}工具方法需要你把 score 传进去。对象方法直接使用对象自己的 score。对象方法的好处是行为和数据靠在一起。五、构造方法创建对象时初始化数据前面的创建方式太啰嗦StudentstudentnewStudent();student.idS001;student.nameTom;student.score90;而且可能忘记设置某个字段。构造方法可以让对象创建时就带上必要数据publicclassStudent{Stringid;Stringname;intscore;publicStudent(Stringid,Stringname,intscore){this.idid;this.namename;this.scorescore;}booleanisPassed(){returnscore60;}}使用StudenttomnewStudent(S001,Tom,90);构造方法特点名字和类名一样。没有返回值类型。创建对象时自动调用。用来初始化对象。六、this当前对象publicStudent(Stringid,Stringname,intscore){this.idid;this.namename;this.scorescore;}左边this.id是对象字段。右边id是构造方法参数。this表示当前对象。如果不用 thispublicStudent(Stringid,Stringname,intscore){idid;namename;scorescore;}这段代码没有把参数赋给字段。它只是参数自己赋给自己。当字段名和参数名相同时要用this区分。七、默认构造方法如果你没有写任何构造方法publicclassStudent{Stringname;}Java 会提供一个默认无参构造newStudent();但如果你写了有参构造publicStudent(Stringname){this.namename;}Java 就不会再自动提供无参构造。此时newStudent();会编译失败除非你自己写publicStudent(){}八、对象引用变量里保存的是引用StudenttomnewStudent(S001,Tom,90);Studentanothertom;another.score60;System.out.println(tom.score);输出60因为tom和another指向同一个对象。tomStudent对象another引用类型变量保存的不是对象本身而是对象的引用。理解这一点后面学习集合、参数传递、对象比较非常重要。九、对象数组和对象列表对象可以放进数组Student[]students{newStudent(S001,Tom,90),newStudent(S002,Jack,58),newStudent(S003,Lucy,76)};遍历for(Studentstudent:students){System.out.println(student.namestudent.score);}也可以放进 Listimportjava.util.ArrayList;importjava.util.List;ListStudentstudentsnewArrayList();students.add(newStudent(S001,Tom,90));students.add(newStudent(S002,Jack,58));List 更适合动态增删。十、用对象改造成绩统计publicclassStudentApp{publicstaticvoidmain(String[]args){Student[]students{newStudent(S001,Tom,90),newStudent(S002,Jack,58),newStudent(S003,Lucy,76)};intsum0;intpassCount0;for(Studentstudent:students){System.out.println(student.namestudent.score);sumstudent.score;if(student.isPassed()){passCount;}}doubleaveragesum*1.0/students.length;System.out.println(平均分average);System.out.println(及格人数passCount);}}现在每个学生的数据聚合到一个对象里不再靠多个数组下标硬凑。十一、常见错误1. 忘记 newStudentstudent;student.nameTom;这里只声明了变量没有创建对象。正确StudentstudentnewStudent(S001,Tom,90);2. 空引用调用字段或方法Studentstudentnull;System.out.println(student.name);会空指针。3. 构造方法写了返回值publicvoidStudent(Stringname){}这不是构造方法而是一个普通方法。构造方法没有返回值类型。4. 参数和字段混淆字段名和参数名一样时用this。5. 类只装数据没有行为如果 Student 只有字段没有isPassed这类行为对象价值会变低。面向对象不是把 Map 换成 class而是把数据和行为放在一起。十二、本章练习定义Book类字段包括id、title、priceCent。给 Book 写构造方法。给 Book 写isExpensive()方法价格超过 10000 分返回 true。创建 3 个 Book 对象放进数组输出书名和价格。定义Product类包含商品名、库存、单价并写hasStock()方法。十三、本章总结本章要掌握类是模板对象是实例。字段表示对象状态。方法表示对象行为。构造方法用于创建对象时初始化数据。this表示当前对象。引用类型变量保存对象引用。多个变量可以指向同一个对象。对象可以放进数组和集合。面向对象的第一步是把相关数据和行为放在一起。下一章讲封装。现在的 Student 字段还能被外部随便改这会破坏对象规则。封装要解决的就是这个问题。