Java面向对象核心:封装、构造器与JavaBean实战(含电影系统案例)
作为Java初学者,面向对象(OOP)是绕不开的核心知识点,而封装、构造方法、this关键字和标准JavaBean更是OOP编程的基石。本文将结合实战代码,从基础概念到综合案例,一步步拆解这些知识点,帮你彻底搞懂并上手实践~
一、封装:给数据加层"安全防护"
1. 什么是封装?
封装的核心思想是:将对象的数据(成员变量)和操作数据的方法(成员方法)封装在同一个类中,隐藏内部实现细节,只通过指定接口对外暴露访问方式。
简单说,封装就像给数据装了个"保险箱"——外部不能直接修改数据,只能通过我们允许的方式(get/set方法)操作,既保证了数据安全,又让代码更整洁。
2. 如何实现封装?
关键步骤:
- 用
private关键字修饰成员变量(私有化),限制外部直接访问; - 为每个私有成员变量提供
getXxx()方法(获取变量值)和setXxx()方法(修改变量值); - 可在
setXxx()中添加数据校验逻辑,避免非法数据录入。
实战示例(GirlFriend类):
public class GirlFriend2 {
// 私有成员变量(外部无法直接访问)
private String name;
private int age;
private String gender;
// setName:给name赋值(对外暴露的赋值接口)
public void setName(String n) {
name = n; // 无歧义,无需this(形参名n与成员变量name不同)
}
// getName:对外提供name的值
public String getName() {
return name;
}
// setAge:赋值时添加数据校验(核心价值!)
public void setAge(int a) {
if (a >= 18 && a <= 50) { // 只允许18-50岁的合法数据
age = a;
} else {
System.out.println("非法参数:年龄必须在18-50之间");
}
}
public int getAge() {
return age;
}
// gender的get/set方法
public void setGender(String g) {
gender = g;
}
public String getGender() {
return gender;
}
// 封装的行为方法
public void sleep() {
System.out.println(name + "在睡觉");
}
}
测试类调用:
public class GirlFriendTest2 {
public static void main(String[] args) {
GirlFriend2 gf = new GirlFriend2();
gf.setName("小诗诗");
gf.setAge(18); // 合法数据,赋值成功
gf.setGender("女");
// 只能通过get方法获取数据
System.out.println(gf.getName()); // 小诗诗
System.out.println(gf.getAge()); // 18
gf.sleep(); // 小诗诗在睡觉
// 测试非法数据
gf.setAge(17); // 输出:非法参数:年龄必须在18-50之间
}
}
3. 封装的核心价值:
- 数据安全:避免外部随意修改敏感数据(比如年龄不能是负数);
- 代码解耦:内部实现逻辑修改时,不影响外部调用(比如后续修改年龄校验规则,只需改setAge方法);
- 代码整洁:明确数据的访问入口,便于维护。
二、构造方法:对象初始化的"快捷方式"
创建对象时,我们经常需要给成员变量赋初始值。如果每次都用set方法逐个赋值,代码会很繁琐——这时候「构造方法」就派上用场了。
1. 构造方法的核心规则:
- 方法名必须与类名完全一致(大小写也相同);
- 没有返回值类型,连
void都不能写; - 创建对象时由虚拟机自动调用,不能手动调用;
- 支持重载(多个构造方法参数列表不同)。
2. 构造方法的作用:
- 无参构造:初始化对象时,成员变量采用默认值(字符串null、int 0等);
- 有参构造:初始化对象时直接给成员变量赋值,一步到位。
3. 实战示例(Student类):
public class Student {
private String name;
private int age;
// 1. 无参构造(推荐手动书写,避免默认构造被覆盖)
public Student() {
System.out.println("无参构造调用:对象创建成功");
}
// 2. 有参构造(初始化时直接赋值)
public Student(String name, int age) {
this.name = name; // this区分成员变量和局部变量
this.age = age;
}
// get/set方法省略...
}
4. 调用构造方法创建对象:
public class StudentTest {
public static void main(String[] args) {
// 无参构造:创建对象后用set赋值
Student s1 = new Student();
s1.setName("张三");
s1.setAge(20);
// 有参构造:创建对象时直接赋值(更简洁)
Student s2 = new Student("李四", 22);
System.out.println(s2.getName()); // 李四
}
}
5. 注意事项:
- 如果没手动写构造方法,系统会默认提供一个无参构造;
- 一旦手动写了构造方法(无论有参无参),系统不再提供默认无参构造;
- 推荐用法:无论是否需要,都手动书写无参构造和全参构造(IDE快捷键:Alt+Insert → Constructor)。
三、this关键字:解决"变量重名"的神器
在构造方法或成员方法中,经常会遇到「成员变量名」和「局部变量名」相同的情况(比如上面的name和age),这时候就需要用this关键字区分。
1. this的核心作用:
- 指代「当前对象」(哪个对象调用方法,this就指向哪个对象);
- 区分成员变量和局部变量(
this.成员变量)。
2. 实战示例:
public class Student {
private String name;
// 形参名name与成员变量名相同,必须用this区分
public void setName(String name) {
this.name = name; // this.name:成员变量;name:局部变量
}
// 打印爱好:this.name指代当前对象的name
public void printHobby(String hobby) {
System.out.println(this.name + "喜欢" + hobby);
}
}
// 测试类
public class Test {
public static void main(String[] args) {
Student s = new Student();
s.setName("周杰伦");
s.printHobby("音乐"); // 输出:周杰伦喜欢音乐
}
}
3. 总结:
只要方法中出现「局部变量与成员变量同名」,就必须用this.成员变量表示成员变量;如果没有重名,可省略this(但推荐保留,增强代码可读性)。
四、标准JavaBean:OOP编程的"规范模板"
标准JavaBean是「封装」「构造方法」「this关键字」的综合应用,是Java开发中存储数据的标准格式,也叫「实体类」。
1. 标准JavaBean的规范:
- 类名见名知意(如User、Student、Movie);
- 成员变量私有化(private修饰);
- 提供「无参构造方法」和「全参构造方法」;
- 为每个成员变量提供getXxx()和setXxx()方法;
- 可选:添加必要的业务方法(如toString())。
2. 实战示例(User类):
public class User {
// 1. 私有成员变量
private String username;
private String password;
private int age;
// 2. 无参构造
public User() {}
// 3. 全参构造
public User(String username, String password, int age) {
this.username = username;
this.password = password;
this.age = age;
}
// 4. get/set方法
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getPassword() { return password; }
public void setPassword(String password) { this.password = password; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
3. JavaBean的应用场景:
实体类只负责「存储数据」,而数据的业务处理(如计算、查询、打印)交给专门的业务类(如StudentOperator、MovieOperator),实现「数据与业务分离」,让代码结构更清晰。
示例:Student实体类 + StudentOperator业务类
// 实体类:只存数据
public class Student {
private String name;
private double chinese;
private double math;
// 无参+全参构造、get/set方法省略...
}
// 业务类:只处理业务逻辑
public class StudentOperator {
private Student student;
// 构造方法接收Student对象
public StudentOperator(Student student) {
this.student = student;
}
// 业务方法:计算总成绩
public void printTotalScore() {
double total = student.getChinese() + student.getMath();
System.out.println(student.getName() + "的总成绩:" + total);
}
}
五、综合实战:电影信息展示系统
掌握了以上知识点,我们来实现一个完整的面向对象案例——电影信息展示系统,需求如下:
- 展示所有电影的基本信息(编号、名称、价格、演员);
- 支持根据电影编号查询详细信息。
1. 步骤拆解:
第一步:设计Movie实体类(符合JavaBean规范)
package com.wmh.demo;
public class Movie {
// 私有成员变量
private int id; // 电影编号
private String name; // 电影名称
private double price; // 电影价格
private String actor; // 主演
// 无参构造
public Movie() {}
// 全参构造
public Movie(String name, double price, int id, String actor) {
this.name = name;
this.price = price;
this.id = id;
this.actor = actor;
}
// get/set方法
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
public String getActor() { return actor; }
public void setActor(String actor) { this.actor = actor; }
}
第二步:设计MovieOperator业务类(封装核心功能)
package com.wmh.demo;
import java.util.Scanner;
public class MovieOperator {
private Movie[] movies; // 存储所有电影对象
// 构造方法:接收电影数组
public MovieOperator(Movie[] movies) {
this.movies = movies;
}
// 功能1:打印所有电影信息
public void printAllMovies() {
System.out.println("============全部电影信息============");
for (Movie movie : movies) {
System.out.printf("%d\t%s\t%.1f\t%s%n",
movie.getId(), movie.getName(), movie.getPrice(), movie.getActor());
}
}
// 功能2:根据编号查询电影
public void searchMovieById() {
System.out.print("请输入要查询的电影编号:");
Scanner sc = new Scanner(System.in);
int targetId = sc.nextInt();
// 遍历数组查询
for (Movie movie : movies) {
if (movie.getId() == targetId) {
System.out.println("============查询结果============");
System.out.printf("%d\t%s\t%.1f\t%s%n",
movie.getId(), movie.getName(), movie.getPrice(), movie.getActor());
return;
}
}
// 未找到
System.out.println("未找到编号为" + targetId + "的电影!");
}
}
第三步:设计Test测试类(初始化数据+调用功能)
package com.wmh.demo;
public class Test {
public static void main(String[] args) {
// 1. 初始化电影数据(创建6个电影对象)
Movie[] movies = new Movie[6];
movies[0] = new Movie("唐人街探案", 9.5, 1, "王宝强");
movies[1] = new Movie("星际穿越", 9.6, 2, "安妮海瑟薇");
movies[2] = new Movie("速度与激情8", 9.2, 3, "瑞秋费尔南多");
movies[3] = new Movie("夏洛特烦恼", 9.2, 4, "沈腾");
movies[4] = new Movie("不能说的秘密", 9.5, 5, "周杰伦");
movies[5] = new Movie("让子弹飞", 9.6, 6, "姜文");
// 2. 创建业务对象,传入电影数组
MovieOperator operator = new MovieOperator(movies);
// 3. 调用功能
operator.printAllMovies();
operator.searchMovieById();
}
}
2. 运行结果:
============全部电影信息============
1 唐人街探案 9.5 王宝强
2 星际穿越 9.6 安妮海瑟薇
3 速度与激情8 9.2 瑞秋费尔南多
4 夏洛特烦恼 9.2 沈腾
5 不能说的秘密 9.5 周杰伦
6 让子弹飞 9.6 姜文
请输入要查询的电影编号:3
============查询结果============
3 速度与激情8 9.2 瑞秋费尔南多
3. 案例设计思路:
- 数据层(Movie类):封装电影数据,符合JavaBean规范,确保数据安全;
- 业务层(MovieOperator类):封装核心功能,与数据层分离,便于维护;
- 测试层(Test类):负责初始化数据和调用功能,体现程序入口。
六、核心知识点总结
- 封装:private私有化成员变量,通过get/set暴露访问,保证数据安全;
- 构造方法:初始化对象,无参+全参构造是标准配置,简化赋值流程;
- this关键字:区分成员变量与局部变量,指代当前对象;
- 标准JavaBean:数据存储的标准格式,实现数据与业务分离;
- 实战原则:实体类只存数据,业务类只处理逻辑,代码结构清晰易维护。
七、拓展练习(动手试试!)
- 给电影系统添加「修改电影价格」功能(在MovieOperator中新增updateMoviePrice方法);
- 给Student类添加toString()方法,直接打印对象时显示所有属性;
- 在Movie的setPrice方法中添加校验:价格不能小于0或大于100。
如果觉得本文对你有帮助,欢迎点赞、收藏~ 有任何疑问或补充,评论区见!