Java面向对象编程核心概念
一、对象与类的核心认知
1.1 对象的本质
对象是一种特殊的数据结构,用于承载一个事物的完整数据,从而在程序中对该事物进行具象化表达。
相较于变量、数组等基础数据存储结构,对象具备更强的结构化能力:可将一个事物的多维度属性与行为进行整合,实现数据与处理逻辑的一体化管理。例如对于影视演员这一事物,可通过对象承载其姓名、年龄、身高、体重等多维度属性;对于学生这一事物,可通过对象承载姓名、各科成绩等数据,同时内置成绩计算的相关行为。
1.2 类的核心定位
类也被称为对象的设计图或模板,是创建对象的基础。在Java中,必须先定义类,才能通过类创建对应的对象;每一次通过new关键字实例化类,都会得到一个全新的、独立的对象。
类的核心组成分为两部分:
- 成员变量(属性):用来说明对象可存储的数据,描述事物的静态特征;
- 成员方法(行为):描述对象具备的功能,即对数据可执行的处理操作。
二、类的基础语法与对象实例化
2.1 类的基础语法结构
/**
* 学生类:作为创建学生对象的模板
*/
public class Student {
// 成员变量:学生的属性
String name; // 姓名
double chinese; // 语文成绩
double math; // 数学成绩
// 成员方法:计算并打印总成绩
public void printTotalScore() {
System.out.println(name + "同学的各科总分是:" + (chinese + math));
}
// 成员方法:计算并打印平均成绩
public void printAverageScore() {
System.out.println(name + "同学的各科平均分是:" + (chinese + math) / 2.0);
}
}2.2 对象的实例化与使用
通过new关键字完成类的实例化,得到对象后,可通过对象名.属性名访问成员变量,通过对象名.方法名()调用成员方法。
/**
* 测试类:完成学生对象的创建与功能验证
*/
public class StudentTest {
public static void main(String[] args) {
// 实例化第一个学生对象并赋值
Student s1 = new Student();
s1.name = "播妞";
s1.chinese = 100;
s1.math = 100;
// 调用对象的方法
s1.printTotalScore();
s1.printAverageScore();
// 实例化第二个学生对象并赋值
Student s2 = new Student();
s2.name = "播仔";
s2.chinese = 59;
s2.math = 100;
// 调用对象的方法
s2.printTotalScore();
s2.printAverageScore();
}
}程序执行结果:
播妞同学的各科总分是:200.0
播妞同学的各科平均分是:100.0
播仔同学的各科总分是:159.0
播仔同学的各科平均分是:79.52.3 对象的内存模型
Java程序运行时,对象的相关数据会分布在三个核心内存区域:
- 栈内存:存储对象的引用(地址),方法的局部变量,方法执行完毕后会自动释放;
- 堆内存:存储实例化对象的实际数据(成员变量),每一个
new出来的对象都会在堆内存中分配独立的空间; - 方法区:存储类的字节码信息,包括类的成员变量、成员方法定义,类加载时仅会加载一次。
三、构造器的定义与应用
3.1 构造器的核心作用
构造器是类的特殊成员方法,在对象通过new关键字创建时,会被自动调用,核心应用场景为完成对象成员变量的初始化赋值。
3.2 构造器的语法规范
构造器的名称必须与类名完全一致,且无返回值类型声明(无需写void),基础语法如下:
public class Student {
String name;
int age;
// 无参构造器
public Student() {
}
// 有参构造器
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}3.3 构造器的使用规则
- 类在定义时,会默认自带一个无参构造器,无需手动声明;
- 若为类显式定义了有参构造器,默认的无参构造器会自动失效,若需使用无参构造器,必须手动显式定义;
- 一个类可定义多个重载的构造器,根据参数列表的不同完成不同的初始化逻辑。
3.4 构造器的实战使用
public class ConstructorTest {
public static void main(String[] args) {
// 调用无参构造器创建对象,后续通过set方法赋值
Student s1 = new Student();
s1.name = "张三";
s1.age = 20;
// 调用有参构造器创建对象,同时完成初始化赋值
Student s2 = new Student("李四", 22);
}
}四、this关键字的核心作用
4.1 this的本质
this是一个引用类型变量,存在于类的成员方法与构造器中,指向当前调用该方法的对象,即“哪个对象调用方法,this就指向哪个对象”。
4.2 核心应用场景
this的核心作用是解决成员变量与方法内局部变量的命名冲突问题。当方法内的局部变量与类的成员变量名称相同时,通过this.变量名的方式,显式指定访问的是类的成员变量。
public class Student {
// 成员变量
String name;
double score;
// 带参方法,局部变量与成员变量重名
public void checkPass(double score) {
// this.score 代表当前对象的成员变量score
// score 代表方法传入的局部变量score
if(this.score >= score) {
System.out.println("成绩达标");
} else {
System.out.println("成绩未达标");
}
}
}除此之外,this也可用于在构造器中调用本类的其他重载构造器,简化初始化代码。
五、封装特性的设计与实现
5.1 封装的核心定义
封装是面向对象编程的三大核心特征(封装、继承、多态)之一,其核心设计思想是:将事物的数据与处理数据的方法设计在同一个类的对象中,遵循合理隐藏、合理暴露的设计规范。
5.2 封装的代码实现
通过Java的访问权限修饰符,控制类成员的可见性,实现封装的设计规范:
- 隐藏成员:使用
private(私有)修饰符修饰成员变量,仅当前类内部可访问,外部类无法直接操作; - 暴露成员:使用
public(公开)修饰符修饰成员方法,对外提供统一的访问与操作入口。
5.3 封装的设计优势
- 提升数据安全性,避免外部类直接修改成员变量,可在暴露的方法中增加数据校验逻辑;
- 规范数据的访问方式,降低代码耦合度;
- 隐藏代码的实现细节,仅对外暴露必要的功能入口。
封装后的标准类示例:
public class Student {
// 私有成员变量:对外隐藏
private String name;
private double chinese;
private double math;
// 公开的get/set方法:对外暴露,提供访问入口
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getChinese() {
return chinese;
}
public void setChinese(double chinese) {
// 增加数据校验,确保成绩合法
if(chinese >= 0 && chinese <= 100) {
this.chinese = chinese;
} else {
System.out.println("语文成绩输入不合法,需在0-100之间");
}
}
public double getMath() {
return math;
}
public void setMath(double math) {
if(math >= 0 && math <= 100) {
this.math = math;
} else {
System.out.println("数学成绩输入不合法,需在0-100之间");
}
}
// 公开的业务方法:对外暴露功能
public void printTotalScore() {
System.out.println(name + "同学的各科总分是:" + (chinese + math));
}
}六、JavaBean(实体类)规范与应用
6.1 JavaBean的核心规范
JavaBean是Java开发中约定俗成的实体类规范,是一种仅负责数据存取的特殊类,核心作用是实现数据与业务处理逻辑的分离,是MVC、分层开发架构的基础。
标准JavaBean需满足以下3个核心要求:
- 类中的所有成员变量必须使用
private修饰实现私有化; - 为每一个私有化的成员变量,提供
public修饰的getter(取值)与setter(赋值)方法; - 必须提供一个
public修饰的无参构造器,有参构造器为可选定义。
6.2 标准JavaBean示例
/**
* 教师实体类:标准JavaBean规范实现
*/
public class Teacher {
// 私有成员变量
private String name;
private String workId;
// 无参构造器(必须)
public Teacher() {
}
// 有参构造器(可选)
public Teacher(String name, String workId) {
this.name = name;
this.workId = workId;
}
// getter与setter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getWorkId() {
return workId;
}
public void setWorkId(String workId) {
this.workId = workId;
}
// 成员方法
public void teach() {
System.out.println("工号为" + workId + "的" + name + "老师正在讲课");
}
}6.3 JavaBean的使用方式
public class TeacherTest {
public static void main(String[] args) {
// 方式1:无参构造器创建对象 + setter方法赋值
Teacher t1 = new Teacher();
t1.setName("杨老师");
t1.setWorkId("t001");
t1.teach();
// 方式2:有参构造器创建对象,直接完成赋值
Teacher t2 = new Teacher("李老师", "t002");
t2.teach();
}
}6.4 应用场景
JavaBean实体类的对象仅负责数据的承载与存取,数据的业务处理逻辑由专门的业务类实现,从而实现数据与业务的解耦,提升代码的可维护性与可扩展性。
七、static关键字与静态成员
static意为静态,可用于修饰类的成员变量与成员方法,被修饰的成员属于类本身,而非类的实例对象,与类一起加载,无需创建对象即可访问。
7.1 静态成员变量(类变量)
7.1.1 核心定义与特性
成员变量根据是否被static修饰,分为两类:
| 类型 | 定义 | 核心特性 | 访问方式 |
|---|---|---|---|
| 静态变量(类变量) | 被static修饰的成员变量 | 与类一起加载,内存中仅存在一份,被该类的所有实例对象共享 | 推荐:类名.静态变量名不推荐: 对象.静态变量名 |
| 实例变量(对象变量) | 未被static修饰的成员变量 | 属于每个独立的对象,每个对象都有一份独立副本,互不影响 | 仅支持:对象.实例变量名 |
7.1.2 应用场景与代码示例
当某个数据仅需一份,且需要被所有对象共享访问、修改时,可定义为静态变量。典型场景:统计类的实例化对象总数。
public class User {
// 静态变量:统计对象创建数量,被所有对象共享
public static int userCount = 0;
// 无参构造器:每创建一个对象,计数+1
public User() {
User.userCount++;
}
}public class StaticFieldTest {
public static void main(String[] args) {
// 类名直接访问静态变量
System.out.println(User.userCount); // 输出:0
// 创建3个对象
new User();
new User();
new User();
// 静态变量已被所有对象共享修改
System.out.println(User.userCount); // 输出:3
}
}7.2 静态成员方法(类方法)
7.2.1 核心定义与特性
成员方法根据是否被static修饰,分为两类:
| 类型 | 定义 | 核心特性 | 访问方式 |
|---|---|---|---|
| 静态方法(类方法) | 被static修饰的成员方法 | 属于类本身,无需创建对象即可调用 | 推荐:类名.静态方法名不推荐: 对象.静态方法名 |
| 实例方法(对象方法) | 未被static修饰的成员方法 | 属于对象,必须创建实例对象后才能调用 | 仅支持:对象.实例方法名 |
7.2.2 核心应用场景:工具类设计
静态方法的核心应用场景是开发工具类。工具类是一种通用功能类,其中的方法均为静态方法,每个方法完成一个通用功能,可直接被开发者调用,无需创建工具类的对象。
工具类设计的核心优势:
- 提高代码复用性,通用功能可全局调用;
- 调用便捷,无需实例化对象,直接通过类名调用;
- 节省内存,避免创建大量仅用于调用方法的对象。
7.2.3 工具类设计规范与示例
工具类无需创建对象,建议将构造器私有化,避免被外部类实例化。
/**
* 字符串工具类:静态方法实现通用功能
*/
public class StringUtil {
// 私有化构造器:禁止外部实例化
private StringUtil() {
}
// 静态方法:判断字符串是否为空
public static boolean isEmpty(String str) {
return str == null || str.trim().length() == 0;
}
// 静态方法:判断邮箱格式是否合法
public static boolean isEmail(String email) {
if(isEmpty(email)) {
return false;
}
return email.matches("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$");
}
}工具类的使用:
public class UtilTest {
public static void main(String[] args) {
// 直接通过类名调用静态方法,无需创建对象
System.out.println(StringUtil.isEmpty("")); // 输出:true
System.out.println(StringUtil.isEmail("test@163.com")); // 输出:true
}
}7.3 静态成员的访问注意事项
- 静态方法中可以直接访问静态成员,无法直接访问实例成员;
- 实例方法中既可以直接访问静态成员,也可以直接访问实例成员;
- 实例方法中可以使用
this关键字,静态方法中不允许使用this关键字。
八、实战案例:简易电影信息展示系统
8.1 需求说明
- 展示系统中的全部电影信息(每部电影展示名称、价格);
- 支持根据电影编号(id)查询对应电影的详细信息。
8.2 代码实现
步骤1:定义电影实体类(JavaBean)
public class Movie {
// 私有成员变量
private int id; // 电影编号
private String name; // 电影名称
private double price; // 电影票价
private String director;// 导演
private String cast; // 主演
private double score; // 电影评分
// 无参构造器
public Movie() {
}
// 有参构造器
public Movie(int id, String name, double price, String director, String cast, double score) {
this.id = id;
this.name = name;
this.price = price;
this.director = director;
this.cast = cast;
this.score = score;
}
// getter与setter方法
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 getDirector() {
return director;
}
public void setDirector(String director) {
this.director = director;
}
public String getCast() {
return cast;
}
public void setCast(String cast) {
this.cast = cast;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
}步骤2:定义电影业务处理类
public class MovieOperator {
private Movie[] movies;
// 构造器:传入电影数据数组
public MovieOperator(Movie[] movies) {
this.movies = movies;
}
// 功能1:展示全部电影的名称与价格
public void showAllMovies() {
System.out.println("===== 系统全部电影信息 =====");
for (Movie movie : movies) {
System.out.println("电影名称:" + movie.getName() + ",票价:" + movie.getPrice() + "元");
}
}
// 功能2:根据电影编号查询电影详情
public void queryMovieById(int id) {
for (Movie movie : movies) {
if(movie.getId() == id) {
System.out.println("===== 电影详情信息 =====");
System.out.println("电影编号:" + movie.getId());
System.out.println("电影名称:" + movie.getName());
System.out.println("电影评分:" + movie.getScore());
System.out.println("电影票价:" + movie.getPrice() + "元");
System.out.println("导演:" + movie.getDirector());
System.out.println("主演:" + movie.getCast());
return;
}
}
System.out.println("未查询到编号为" + id + "的电影信息");
}
}步骤3:测试主类,实现功能调用
public class MovieSystem {
public static void main(String[] args) {
// 1. 初始化电影数据
Movie[] movies = new Movie[3];
movies[0] = new Movie(1, "长津湖之水门桥", 45.0, "徐克", "吴京、易烊千玺", 9.6);
movies[1] = new Movie(2, "一点就到家", 38.0, "许宏宇", "刘昊然、彭昱畅", 8.7);
movies[2] = new Movie(3, "月球陨落", 52.0, "罗兰·艾默里奇", "哈莉·贝瑞", 7.9);
// 2. 创建业务处理对象
MovieOperator operator = new MovieOperator(movies);
// 3. 调用功能1:展示全部电影信息
operator.showAllMovies();
// 4. 调用功能2:根据编号查询电影详情
operator.queryMovieById(2);
operator.queryMovieById(5);
}
}8.3 程序执行结果
===== 系统全部电影信息 =====
电影名称:长津湖之水门桥,票价:45.0元
电影名称:一点就到家,票价:38.0元
电影名称:月球陨落,票价:52.0元
===== 电影详情信息 =====
电影编号:2
电影名称:一点就到家
电影评分:8.7
电影票价:38.0元
导演:许宏宇
主演:刘昊然、彭昱畅
未查询到编号为5的电影信息