相信你是最棒哒!!!!!!
文章目录
一、题目描述
设计学生类Student包含属性有姓名name和年龄age,由学生类派生出本科生类Undergraduate和研究生类 Graduate。本科生包含的属性有专业specialty,研究生包含的属性有研究方向study_direction ,每个类都有相关数据的toString()输出方法。
二、题目代码
1.解析版
// ============ 爸爸类:学生 ============
class Student {
private String name; // 私有:只能通过公开方法访问
private int age; // 私有:保护数据
// 构造器:Student s = new Student("张三", 18);时自动跑,负责给姓名、年龄赋初值
public Student(String name, int age) {
this.name = name; // 把形参 name 塞进成员变量 name
this.age = age; // 把形参 age 塞进成员变量 age
}
public String getName() {
return name; // 把名字"复制"一份给你,原件不动
}
public void setName(String name) {
this.name = name; // 你传新名字,我就覆盖旧的
}
public int getAge() {
return age; // 把年龄"复制"一份给你
}
public void setAge(int age) {
this.age = age; // 你传新年龄,我就覆盖旧的
}
// 打印对象时自动调用,决定"长什么样"
@Override
public String toString() {
return "姓名:" + name + ",年龄:" + age;
}
}
// ============ 大儿子类:本科生 ============
// 关键字 extends 表示"本科生 是 一种 学生",自动拥有爸爸所有非私有成员
class Undergraduate extends Student {
private String specialty; // 本科生比爸爸多出来的属性:专业
// 构造器:先让父类把姓名年龄搞定,再处理自己的专业
public Undergraduate(String name, int age, String specialty) {
super(name, age); // 调用父类的构造器,必须放第一行
this.specialty = specialty; // 自己的属性自己管
}
// 给外部读专业
public String getSpecialty() {
return specialty;
}
// 给外部改专业
public void setSpecialty(String specialty) {
this.specialty = specialty;
}
// 打印时先拉父类的信息过来,再拼上自己的特色
@Override
public String toString() {
return "本科生:[" + super.toString() + ",专业:" + specialty + "]";
}
}
// ============ 二儿子类:研究生 ============
class Graduate extends Student {
private String researchDirection; // 研究生比父类多出来的属性:研究方向
public Graduate(String name, int age, String researchDirection) {
super(name, age); // 先让爸爸搞定姓名年龄
this.researchDirection = researchDirection; // 自己的方向自己存
}
public String getResearchDirection() {
return researchDirection;
}
public void setResearchDirection(String researchDirection) {
this.researchDirection = researchDirection;
}
@Override
public String toString() {
return "研究生:[" + super.toString() + ",研究方向:" + researchDirection + "]";
}
}
// ============ 测试入口 ============
public class TestStudent {
// JVM 启动时唯一入口
public static void main(String[] args) {
// 用本科生模板造对象:姓名、年龄、专业 一次给齐
Undergraduate u = new Undergraduate("张三", 20, "计算机科学与技术");
// 用研究生模板造对象:姓名、年龄、研究方向 一次给齐
Graduate g = new Graduate("李四", 25, "人工智能与机器学习");
// 直接打印对象,会偷偷调用它们各自的 toString() 方法
System.out.println(u);
System.out.println(g);
// 通过 set 方法改内部数据,体现"封装"------外界不直接碰字段
u.setSpecialty("软件工程"); // 张三转专业
g.setResearchDirection("大数据分析"); // 李四换方向
// 再打一次,看改动效果
System.out.println("\n修改后:");
System.out.println(u);
System.out.println(g);
}
}
2.简洁版
代码如下(示例):
class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "姓名:" + name + ",年龄:" + age;
}
}
class Undergraduate extends Student {
private String specialty;
public Undergraduate(String name, int age, String specialty) {
super(name, age);
this.specialty = specialty;
}
public String getSpecialty() {
return specialty;
}
public void setSpecialty(String specialty) {
this.specialty = specialty;
}
@Override
public String toString() {
return "本科生:[" + super.toString() + ",专业:" + specialty + "]";
}
}
class Graduate extends Student {
private String researchDirection;
public Graduate(String name, int age, String researchDirection) {
super(name, age);
this.researchDirection = researchDirection;
}
public String getResearchDirection() {
return researchDirection;
}
public void setResearchDirection(String researchDirection) {
this.researchDirection = researchDirection;
}
@Override
public String toString() {
return "研究生:[" + super.toString() + ",研究方向:" + researchDirection + "]";
}
}
public class TestStudent {
public static void main(String[] args) {
Undergraduate u = new Undergraduate("张三", 20, "计算机科学与技术");
Graduate g = new Graduate("李四", 25, "人工智能与机器学习");
System.out.println(u);
System.out.println(g);
u.setSpecialty("软件工程");
g.setResearchDirection("大数据分析");
System.out.println("\n修改后:");
System.out.println(u);
System.out.println(g);
}
}
总结
-
构造器
不会点:它到底啥时候跑?
一句话:
new的一瞬间就跑,用来给对象"接生+建档"。口诀:new 必调构造,无构造系统送,有构造自己写。
-
this.name = name不会点:左边右边都是 name,到底谁是谁?
一句话:左边是"对象自己的小抽屉",右边是"外人递进来的纸条"。
口诀:this.成员 = 参数,把纸条塞进抽屉。
-
private的真正意义不会点:为啥不能直接
.name?一句话:
private是保险柜,钥匙只给get/set,以后想加校验不换锁。口诀:私有防黑手,通道留门口。
-
extends到底继承了啥不会点:"所有非私有成员"是哪部分?
一句话:除了
private的字段/方法,其余public/protected/包私有全白嫖。口诀:私有不继承,其余全白送。
-
super(...)必须第一行不会点:为啥不能放第二行?
一句话:先让爸爸把地基打好,儿子再装修;Java 强制顺序。
口诀:super 先老爸,再搞自己。
-
@Override是干啥不会点:不写也能跑,写它干嘛?
一句话:写错方法名时编译器立刻报错,防止"以为重写、其实新建"的乌龙。
口诀:Override 护身符,写错就红叉。
-
System.out.println(对象)为啥能输出人话不会点:我没调
toString()啊?一句话:
println会自动找对象的toString(),没重写就打印"类名@哈希码"。口诀:打印对象=自动 toString,重写就能说人话。
-
set方法的意义不会点:直接改字段更快,为啥多此一举?
一句话:以后想加"年龄不能为负""专业必须来自字典"等校验,只改
set即可,外部代码零变动。口诀:今天直接改,明天需求哭;通道留一手,维护不跳楼。
-
你在
main里写Student s = new Student("张三", 18); -
JVM 一看
new,立刻做三件事:a. 在内存堆区给新对象划一块地皮。
b. 在这片地里先建一个"空壳",字段全是默认值(
name=null,age=0)。c. 马上自动调用
public Student(String name, int age)------ 这就是构造器。构造器把
"张三"和18分别塞进name和age,壳子瞬间变成有血有肉的对象。 -
构造器跑完,对象返回给你,
s变量才拿到真正的"学生身份证"。
extends 之后,子类自动拿到爸爸下面这些东西:
-
public成员------随便用。 -
protected成员------同包或子类里直接用。 -
包私有成员(没写修饰符)------只要子类和爸爸在同一个包,也能直接用。
不会拿到的是:
-
private字段 / 方法 ------ 爸爸锁在保险柜里,儿子看不见,更摸不着。如果儿子非要玩,只能走爸爸提供的
public/protected方法(例如getName()/setName())去间接访问。
代码看过程:
class Dad {
private String secret = "爸爸私房钱"; // 儿子看不见
public String getSecret() { // 官方复印机
return secret;
}
}
class Son extends Dad {
void play() {
// System.out.println(secret); // ❌ 直接摸会报错
System.out.println(getSecret()); // ✅ 走爸爸提供的公开方法,拿到副本
}
}
所以"间接访问"就是:儿子不碰保险箱,只按爸爸提供的按钮,让爸爸代劳取/放。