jmu-Java-PTA题解 (jmu-Java-03面向对象-06-继承覆盖综合练习-Person、Student、Employee、Company) 网安2312陈卓
问题要求
定义Person抽象类,Student类、Company类,Employee类。
Person类的属性:String name, int age, boolean gender
Person类的方法:
public Person(String name, int age, boolean gender);
public String toString(); //返回"name-age-gender"格式的字符串
public boolean equals(Object obj);//比较name、age、gender,都相同返回true,否则返回false
Student类继承自Person,属性:String stuNo, String clazz
Student类的方法:
//建议使用super复用Person类的相关有参构造函数
public Student(String name, int age, boolean gender, String stuNo, String clazz);
public String toString(); //返回 “Student:person的toString-stuNo-clazz”格式的字符串
public boolean equals(Object obj);//首先调用父类的equals方法,如果返回true,则继续比较stuNo与clazz。
Company类属性:String name
Company类方法:
public Company(String name);
public String toString(); //直接返回name
public boolean equals(Object obj);//name相同返回true
Employee类继承自Person,属性:Company company, double salary
Employee类方法:
//建议使用super复用Person类的相关有参构造函数
public Employee(String name, int age, boolean gender, double salary, Company company);
public String toString(); //返回"Employee:person的toString-company-salary"格式的字符串
public boolean equals(Object obj);//首先调用父类的equals方法,如果返回true。再比较company与salary。
//比较salary属性时,使用DecimalFormat df = new DecimalFormat("#.#");保留1位小数
编写equals方法重要说明:
- 对Employee的company属性的比较。要考虑传入为null的情况。如果company不为null且传入为null,返回false
- 对所有String字符类型比较时,也要考虑null情况。
提示
- 排序可使用Collections.sort
- equals方法要考虑周全
main方法说明
-
创建若干Student对象、Employee对象。
输入s,然后依次输入name age gender stuNo clazz创建Student对象。
输入e,然后依次输入name age gender salary company创建Employee对象。
然后将创建好的对象放入ListpersonList。输入其他字符,则结束创建。
创建说明: 对于String类型,如果为null则不创建对象,而赋值为null。对于company属性,如果为null则赋值为null,否则创建相应的Company对象。 -
对personList中的元素实现先按照姓名升序排序,姓名相同再按照年龄升序排序。提示:可使用Comparable
或Comparator -
接受输入,如果输入为exit则return退出程序,否则继续下面步骤。
-
将personList中的元素按照类型分别放到stuList与empList。注意:不要将两个内容相同的对象放入列表(是否相同是根据equals返回结果进行判定)。
-
输出字符串stuList,然后输出stuList中的每个对象。
-
输出字符串empList,然后输出empList中的每个对象。
1-3为一个测试点
4-6为一个测试点
输入样例:
s zhang 23 false 001 net15
e wang 18 true 3000.51 IBM
s zhang 23 false 001 net15
e bo 25 true 5000.51 IBM
e bo 25 true 5000.52 IBM
e bo 18 true 5000.54 IBM
e tan 25 true 5000.56 IBM
e tan 25 true 5000.51 IBM
s wang 17 false 002 null
s wang 17 false 002 null
e hua 16 false 1000 null
s wang 17 false 002 net16
e hua 16 false 1000 null
e hua 18 false 1234 MicroSoft
!
continue
输出样例:
Employee:bo-18-true-IBM-5000.54
Employee:bo-25-true-IBM-5000.51
Employee:bo-25-true-IBM-5000.52
Employee:hua-16-false-null-1000.0
Employee:hua-16-false-null-1000.0
Employee:hua-18-false-MicroSoft-1234.0
Employee:tan-25-true-IBM-5000.56
Employee:tan-25-true-IBM-5000.51
Student:wang-17-false-002-null
Student:wang-17-false-002-null
Student:wang-17-false-002-net16
Employee:wang-18-true-IBM-3000.51
Student:zhang-23-false-001-net15
Student:zhang-23-false-001-net15
stuList
Student:wang-17-false-002-null
Student:wang-17-false-002-net16
Student:zhang-23-false-001-net15
empList
Employee:bo-18-true-IBM-5000.54
Employee:bo-25-true-IBM-5000.51
Employee:hua-16-false-null-1000.0
Employee:hua-18-false-MicroSoft-1234.0
Employee:tan-25-true-IBM-5000.56
Employee:tan-25-true-IBM-5000.51
Employee:wang-18-true-IBM-3000.51
关键点
- 继承与多态:通过 Person 抽象类定义统一接口,Student 和 Employee 继承并实现子类特有逻辑,父类引用(List
)存储子类对象,利用多态实现统一处理. - equals 方法设计:父类 equals 仅比较自身属性,子类先调用父类 equals,再比较新增属性,+处理 String 和 Company 的 null 比较,避免 NullPointerException,Employee 中对 salary 保留 1 位小数后比较,确保精度一致.
- 输入处理与空值判断:输入为 null 时,直接赋值为 null(如 clazz、company),混合使用 next() 与 nextLine() 时,注意消耗残留换行符.
- 集合排序与去重:使用 Collections.sort 结合 Comparator 实现自定义排序,通过 List.contains() 结合 equals 方法实现对象去重.
解题步骤
第一步:定义抽象类 Person
abstract class Person {
String name;
int age;
boolean gender;
public Person(String name, int age, boolean gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Person other = (Person) obj;
return age == other.age && gender == other.gender && Objects.equals(name, other.name);
}
@Override
public String toString() {
return name + "-" + age + "-" + gender;
}
}
第二步:实现 Student 类
class Student extends Person {
String stuNo;
String clazz;
public Student(String name, int age, boolean gender, String stuNo, String clazz) {
super(name, age, gender);
this.stuNo = stuNo;
this.clazz = clazz;
}
@Override
public String toString() {
return "Student:" + super.toString() + "-" + stuNo + "-" + clazz;
}
@Override
public boolean equals(Object obj) {
if (!super.equals(obj)) return false;
if (obj == null || getClass() != obj.getClass()) return false;
Student other = (Student) obj;
return Objects.equals(stuNo, other.stuNo) && Objects.equals(clazz, other.clazz);
}
}
第三步:实现 Company 类
class Company {
String name;
public Company(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Company other = (Company) obj;
return Objects.equals(name, other.name);
}
}
第四步:实现 Employee 类
class Employee extends Person {
double salary;
Company company;
DecimalFormat df = new DecimalFormat("#.#");
public Employee(String name, int age, boolean gender, double salary, Company company) {
super(name, age, gender);
this.salary = salary;
this.company = company;
}
@Override
public String toString() {
return "Employee:" + super.toString() + "-" + (company != null ? company : "null") + "-" + df.format(salary);
}
@Override
public boolean equals(Object obj) {
if (!super.equals(obj)) return false;
if (obj == null || getClass() != obj.getClass()) return false;
Employee other = (Employee) obj;
// 比较company(处理null情况)
boolean companyEqual = (company == null && other.company == null) ||
(company != null && other.company != null && company.equals(other.company));
// 比较salary(保留1位小数)
String salaryStr = df.format(salary);
String otherSalaryStr = df.format(other.salary);
return companyEqual && salaryStr.equals(otherSalaryStr);
}
}
第五步:主方法逻辑
import java.util.*;
import java.text.DecimalFormat;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
List<Person> personList = new ArrayList<>();
// 创建对象并添加到列表
while (in.hasNext()) {
String type = in.next();
if ("s".equals(type)) {
String name = in.next();
int age = in.nextInt();
boolean gender = in.nextBoolean();
String stuNo = in.next();
String clazz = in.next();
personList.add(new Student(name, age, gender, stuNo, clazz));
} else if ("e".equals(type)) {
String name = in.next();
int age = in.nextInt();
boolean gender = in.nextBoolean();
double salary = in.nextDouble();
String companyName = in.next();
Company company = "null".equals(companyName) ? null : new Company(companyName);
personList.add(new Employee(name, age, gender, salary, company));
} else {
break;
}
}
// 按姓名升序、年龄升序排序
personList.sort(Comparator.comparing(Person::getName).thenComparingInt(Person::getAge));
// 输出排序后的列表(调试用,非题目要求)
// personList.forEach(System.out::println);
// 处理继续指令
String command = in.next();
if ("exit".equals(command)) return;
// 分类并去重
List<Student> stuList = new ArrayList<>();
List<Employee> empList = new ArrayList<>();
for (Person p : personList) {
if (p instanceof Student) {
Student s = (Student) p;
if (!stuList.contains(s)) stuList.add(s);
} else if (p instanceof Employee) {
Employee e = (Employee) p;
if (!empList.contains(e)) empList.add(e);
}
}
// 输出结果
System.out.println("stuList");
stuList.forEach(System.out::println);
System.out.println("empList");
empList.forEach(System.out::println);
}
}
整体流程图:

整体代码:
import java.util.*;
import java.text.*;
class Person{
String name;
int age;
boolean gender;
public Person(String name, int age, boolean gender){
this.name = name;
this.age = age;
this.gender = gender;
}
public boolean equals(Object obj){
if(this == obj) return true;
if(obj == null || this.getClass()!=obj.getClass()) return false;
Person o = (Person) obj;
if(this.name.equals(o.name) && this.age == o.age && this.gender == o.gender) return true;
return false;
}
public String toString() {
return name + "-" + age + "-" + gender;
}
}
class Student extends Person{
String stuNo;
String clazz;
public Student(String name, int age, boolean gender, String stuNo, String clazz) {
super(name, age, gender);
this.stuNo = stuNo;
this.clazz = clazz;
}
public String toString(){
return "Student:" + super.toString() + "-" + this.stuNo + "-" + this.clazz;
}
public boolean equals(Object obj){
if(this == obj) return true;
if(obj == null) return false;
if(super.equals(obj)){
Student o = (Student) obj;
if(this.stuNo.equals(o.stuNo) && this.clazz.equals(o.clazz)) return true;
}
return false;
}
}
class Company{
String name;
public Company(String name){
this.name = name;
}
public String toString(){
return name;
}
public boolean equals(Object obj){
if(this==obj) return true;
if(obj==null||this.getClass()!=obj.getClass()) return false;
Company o = (Company) obj;
if(this.name.equals(o.name)) return true;
return false;
}
}
class Employee extends Person{
double salary;
Company company;
public Employee(String name, int age, boolean gender, double salary, Company company){
super(name,age,gender);
this.salary = salary;
this.company = company;
}
public String toString(){
return "Employee:" + super.toString() + "-" + this.company + "-" + this.salary;
}
public boolean equals(Object obj){
if(this==obj) return true;
if(obj==null||this.getClass()!=obj.getClass()) return false;
if(super.equals(obj)){
Employee o = (Employee) obj;
DecimalFormat df = new DecimalFormat("#.#");
if(this.company==null&&o.company==null) return df.format(this.salary).equals(df.format(o.salary));
if(this.company==null||o.company==null) return false;
if(this.company.equals(o.company)) return df.format(this.salary).equals(df.format(o.salary));
}
return false;
}
}
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
List<Person> personList = new ArrayList<>();
while(in.hasNext()){
String x = in.next();
if(x.equals("s")){
String name = in.next();
int age = in.nextInt();
boolean gender = in.nextBoolean();
String stuNo = in.next();
String clazz = in.next();
Person t = new Student(name, age, gender, stuNo, clazz);
personList.add(t);
}else if(x.equals("e")){
String name = in.next();
int age = in.nextInt();
boolean gender = in.nextBoolean();
double salary = in.nextDouble();
String companyname = in.next();
Company company = new Company(companyname);
Person t = new Employee(name, age, gender, salary, company);
personList.add(t);
}else {
break;
}
}
Collections.sort(personList, new Comparator<Person>() {
public int compare(Person o1, Person o2) {
int number = o1.name.compareTo(o2.name);
if(number!=0){
return number;
}else{
return o1.age-o2.age;
}
}
});
for(Person i:personList){
System.out.println(i.toString());
}
String cc = in.next();
if(cc.equals("exit")||cc.equals(("return"))) {
return;
}
List<Student> stuList = new ArrayList<>();
List<Employee> empList = new ArrayList<>();
for(Person e:personList){
if(e instanceof Student){
Student student = (Student) e;
int flag = 1;
for(Student ee:stuList){
if(ee.equals(e)){
flag = 0;
break;
}
}
if(flag==1){
stuList.add(student);
}
}else if(e instanceof Employee){
Employee employee = (Employee) e;
int flag = 1;
for(Employee ee:empList){
if(ee.equals(e)){
flag = 0;
break;
}
}
if(flag==1){
empList.add(employee);
}
}
}
System.out.println("stuList");
for(Student i:stuList){
System.out.println(i.toString());
}
System.out.println("empList");
for(Employee i:empList){
System.out.println(i.toString());
}
}
}
思考:在本次人员管理系统的设计中,关于类的结构设计与方法逻辑的思考贯穿始终,核心可从面向对象原则、代码复用性、数据处理细节三方面展开。从面向对象设计原则来看,抽象类 Person 的定义是关键基础。将 name、age、gender 等公共属性及 toString、equals 等公共行为封装在父类中,遵循 “单一职责原则”,使子类仅需关注特有属性(如 Student 的 stuNo、Employee 的 company),避免代码冗余。继承机制在此体现得淋漓尽致:Student 和 Employee 通过 extends 关键字复用父类构造方法与基础逻辑,同时通过重写 toString 和 equals 方法实现差异化功能,符合 “开闭原则”(对扩展开放,对修改关闭)。例如,Employee 的 equals 方法先调用父类逻辑判断基础属性,再补充自身属性的比较,这种 “父类定义骨架,子类填充细节” 的模式极大提升了代码的可维护性。关于sumAllArea 与 sumAllPerimeter 方法的设计决策(类比前序形状问题),本题虽未直接涉及类似工具方法,但可延伸思考:若存在统计所有人员共性数据的需求(如计算平均年龄),此类方法应放置于独立的工具类(如 Utils)或主类(Main)中,声明为 static 以避免依赖对象实例,体现 “工具方法” 的无状态性。这种设计与本题中排序逻辑(使用 Collections.sort)的思路一致 —— 将与集合操作相关的通用逻辑抽离,保持业务类的纯净性。数据处理细节方面,equals 方法的全面性是核心难点。需逐层判断:父类属性是否相等(通过 super.equals)、子类特有属性是否相等、引用类型(如 Company、String)是否为 null 及如何安全比较。例如,Employee 中对 company 的比较需分三种情况:两者均为 null、仅一方为 null、均不为 null 但 name 不同,通过 Objects.equals 简化非空判断逻辑,避免冗长的 if-else 分支。对 salary 保留 1 位小数的处理(使用 DecimalFormat)则体现了 “精度控制” 的重要性 —— 直接比较 double 可能因浮点误差导致逻辑错误,格式化后转为字符串比较更可靠,这一细节在财务、统计类场景中尤为关键。输入处理的空值兼容(如输入 “null” 时赋值为 null)与类型安全转换(如 instanceof 判断)是程序健壮性的保障。例如,创建 Company 对象时,若输入为 “null” 则直接赋值为 null,而非创建名称为 “null” 的实例,确保数据逻辑正确。分类去重时,通过 List.contains 结合 equals 方法过滤重复对象,本质上是利用多态特性 —— 父类引用在运行时动态绑定子类对象,实现 “同一接口,不同实现” 的去重逻辑。从代码扩展性角度看,若未来新增角色(如 Teacher 类),只需继承 Person 类并实现特有属性与方法,无需修改现有排序、分类逻辑,充分体现多态的优势。排序逻辑中使用 Comparator.comparing 的链式调用,使排序规则清晰易读,若需调整排序优先级(如先按年龄再按姓名),只需修改比较器顺序,符合 “最少修改原则”。综上,本次设计通过继承构建类层次结构,利用多态实现统一接口下的差异化行为,结合 equals 与 toString 方法的合理重写,以及对输入输出、集合操作的细节处理,形成了结构清晰、可扩展的人员管理系统。这些实践不仅加深了对面向对象核心概念的理解,也为复杂系统设计提供了可复用的方法论,例如 “抽象公共接口→子类实现细节→统一集合管理→多态处理业务” 的开发模式,可广泛应用于各类领域模型的构建中。

浙公网安备 33010602011771号