Java面向对象核心:封装、构造器与JavaBean实战(含电影系统案例)

68 阅读9分钟

Java面向对象核心:封装、构造器与JavaBean实战(含电影系统案例)

作为Java初学者,面向对象(OOP)是绕不开的核心知识点,而封装构造方法this关键字标准JavaBean更是OOP编程的基石。本文将结合实战代码,从基础概念到综合案例,一步步拆解这些知识点,帮你彻底搞懂并上手实践~

一、封装:给数据加层"安全防护"

1. 什么是封装?

封装的核心思想是:将对象的数据(成员变量)和操作数据的方法(成员方法)封装在同一个类中,隐藏内部实现细节,只通过指定接口对外暴露访问方式

简单说,封装就像给数据装了个"保险箱"——外部不能直接修改数据,只能通过我们允许的方式(get/set方法)操作,既保证了数据安全,又让代码更整洁。

2. 如何实现封装?

关键步骤:
  1. private 关键字修饰成员变量(私有化),限制外部直接访问;
  2. 为每个私有成员变量提供 getXxx() 方法(获取变量值)和 setXxx() 方法(修改变量值);
  3. 可在 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关键字:解决"变量重名"的神器

在构造方法或成员方法中,经常会遇到「成员变量名」和「局部变量名」相同的情况(比如上面的nameage),这时候就需要用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的规范:

  1. 类名见名知意(如User、Student、Movie);
  2. 成员变量私有化(private修饰);
  3. 提供「无参构造方法」和「全参构造方法」;
  4. 为每个成员变量提供getXxx()和setXxx()方法;
  5. 可选:添加必要的业务方法(如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. 展示所有电影的基本信息(编号、名称、价格、演员);
  2. 支持根据电影编号查询详细信息。

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类):负责初始化数据和调用功能,体现程序入口。

六、核心知识点总结

  1. 封装:private私有化成员变量,通过get/set暴露访问,保证数据安全;
  2. 构造方法:初始化对象,无参+全参构造是标准配置,简化赋值流程;
  3. this关键字:区分成员变量与局部变量,指代当前对象;
  4. 标准JavaBean:数据存储的标准格式,实现数据与业务分离;
  5. 实战原则:实体类只存数据,业务类只处理逻辑,代码结构清晰易维护。

七、拓展练习(动手试试!)

  1. 给电影系统添加「修改电影价格」功能(在MovieOperator中新增updateMoviePrice方法);
  2. 给Student类添加toString()方法,直接打印对象时显示所有属性;
  3. 在Movie的setPrice方法中添加校验:价格不能小于0或大于100。

如果觉得本文对你有帮助,欢迎点赞、收藏~ 有任何疑问或补充,评论区见!