Loading...

文章背景图

Day 005-知识点汇总

2026-02-10
0
-
- 分钟

第一部分:封装(Encapsulation)

1. 封装的概念与作用

Q: 什么是封装?封装的核心思想是什么?

A: 封装是面向对象三大特征之一(封装、继承、多态),指将类的某些信息(属性)隐藏在类内部,不允许外部直接访问,而是通过该类提供的方法来访问。

核心思想

  • 隐藏:将敏感数据用 private修饰,外部无法直接访问
  • 暴露:提供 public的getter/setter方法,控制数据的访问和修改
  • 安全:在方法中进行数据校验,防止非法数据
// 未封装:数据暴露,不安全
public class StudentUnsafe {
    String name;
    int age;  // 外部可以直接赋值,如 age = -20 也合法
}

// 已封装:数据隐藏,安全可控
public class Student {
    private String name;  // 私有,外部无法直接访问
    private int age;      // 私有
  
    // 提供公共方法控制访问
    public void setAge(int age) {
        if (age < 0) {
            System.out.println("年龄不能为负数!");
        } else {
            this.age = age;  // 合法才赋值
        }
    }
  
    public int getAge() {
        return age;
    }
}

2. private与public的区别

Q: private和public修饰符有什么区别?分别用于什么场景?

A:

修饰符 访问范围 使用场景
public 任意位置都可访问 类、方法、需要对外暴露的成员
private 只能在本类中访问 属性、内部辅助方法
public class AccessDemo {
    // public:任意位置可访问
    public String publicName = "公开姓名";
  
    // private:只能在本类中访问
    private int privateAge = 20;
    private String privatePhone = "13800138000";
  
    // public方法:对外提供访问通道
    public void setAge(int age) {
        if (age > 0 && age < 150) {
            this.privateAge = age;
        }
    }
  
    public int getAge() {
        return privateAge;
    }
  
    public static void main(String[] args) {
        AccessDemo demo = new AccessDemo();
      
        // public成员:直接访问
        System.out.println(demo.publicName);  // 正常访问
      
        // private成员:本类内可以访问
        System.out.println(demo.privateAge);   // 20,本类内可以
      
        // 其他类中:private成员无法直接访问
        // demo.privateAge = 30;  // 在其他类中报错!
    }
}

// 其他类
class OtherClass {
    public void test() {
        AccessDemo demo = new AccessDemo();
        System.out.println(demo.publicName);  // OK
        // System.out.println(demo.privateAge);  // 编译报错!
      
        // 必须通过公共方法访问
        demo.setAge(25);
        System.out.println(demo.getAge());  // 25
    }
}

3. 封装的开发步骤

Q: 实现封装的标准开发步骤是什么?

A: 三步走

  1. 属性私有化:用 private修饰成员变量
  2. 提供setter方法:用于给属性赋值(可加入校验逻辑)
  3. 提供getter方法:用于获取属性值
public class Student {
    // 步骤1:属性私有化
    private String name;
    private int age;
    private double score;
  
    // 步骤2:提供setter方法(赋值)
    public void setName(String name) {
        this.name = name;
    }
  
    public void setAge(int age) {
        // 加入数据校验
        if (age < 0 || age > 150) {
            System.out.println("年龄不合法:" + age);
            return;
        }
        this.age = age;
    }
  
    public void setScore(double score) {
        if (score < 0 || score > 100) {
            System.out.println("成绩不合法:" + score);
            return;
        }
        this.score = score;
    }
  
    // 步骤3:提供getter方法(取值)
    public String getName() {
        return name;
    }
  
    public int getAge() {
        return age;
    }
  
    public double getScore() {
        return score;
    }
}

// 使用
public class Test {
    public static void main(String[] args) {
        Student s = new Student();
        // s.name = "张三";  // 报错!无法直接访问
      
        s.setName("张三");
        s.setAge(200);      // 输出:年龄不合法:200
        s.setAge(20);       // 正常赋值
        s.setScore(88.5);
      
        System.out.println(s.getName() + "," + s.getAge() + "岁,成绩:" + s.getScore());
        // 输出:张三,20岁,成绩:88.5
    }
}

第二部分:this关键字

4. this关键字的作用

Q: this关键字是什么?主要解决什么问题?

A: this是一个引用变量,指向当前对象(调用该方法的对象)。

主要作用

  1. 解决命名冲突:区分成员变量和局部变量
  2. 指代当前对象:在方法内部获取当前对象的引用
public class Student {
    private String name;  // 成员变量
    private int age;
  
    // 问题:参数名和成员变量名相同,如何区分?
    public void setName(String name) {  // 局部变量name
        // name = name;  // 错误!两个都是局部变量,自己赋值给自己
        this.name = name;  // 正确!this.name指成员变量,name指参数
    }
  
    public void setAge(int age) {
        if (age < 0) {
            System.out.println("年龄不合法:" + age);
        } else {
            this.age = age;  // this.age是成员变量,age是参数
        }
    }
  
    // this表示当前对象
    public void printThis() {
        System.out.println("当前对象:" + this);  // 打印对象地址
    }
}

public class Test {
    public static void main(String[] args) {
        Student s1 = new Student();
        System.out.println(s1);           // Student@6d06d69c
        s1.printThis();                   // Student@6d06d69c(同一个对象)
      
        Student s2 = new Student();
        System.out.println(s2);           // Student@7852e922
        s2.printThis();                   // Student@7852e922
      
        // 结论:哪个对象调用方法,this就指向哪个对象
    }
}

第三部分:构造器(Constructor)

5. 构造器的概念与特点

Q: 什么是构造器?有什么特点?

A: 构造器(构造方法)是一种特殊方法,用于创建对象时初始化对象

特点

特性 说明
名称 必须与类名完全相同
返回值 没有返回值,连 void都不能写
调用时机 new对象时自动调用
默认构造器 不写构造器时,JVM自动生成无参构造器
重载 可以定义多个构造器(参数列表不同)
public class Student {
    private String name;
    private int age;
  
    // 无参构造器:创建对象,不初始化属性
    public Student() {
        System.out.println("无参构造器被调用");
    }
  
    // 有参构造器:创建对象,同时初始化属性
    public Student(String name, int age) {
        System.out.println("有参构造器被调用");
        this.name = name;
        this.age = age;
    }
  
    // 构造器重载:部分参数
    public Student(String name) {
        this.name = name;
    }
}

public class Test {
    public static void main(String[] args) {
        Student s1 = new Student();              // 调用无参构造器
        Student s2 = new Student("张三", 20);     // 调用有参构造器
        Student s3 = new Student("李四");         // 调用单参构造器
    }
}

6. 构造器的注意事项

Q: 使用构造器有哪些重要注意事项?

A:

注意点 说明
一旦定义有参构造器,默认无参构造器消失 建议手动添加无参构造器
构造器可以调用其他构造器 使用 this(...),必须放在第一行
构造器不能递归调用 不能自己调用自己
public class Student {
    private String name;
    private int age;
  
    // 注意:如果不写任何构造器,JVM会自动提供无参构造器
    // 但如果写了有参构造器,JVM不再提供无参构造器!
  
    // 建议:显式定义无参构造器
    public Student() {
        // this("未知", 0);  // 可以调用其他构造器,必须放第一行
        System.out.println("无参构造器");
    }
  
    // 有参构造器
    public Student(String name, int age) {
        // this();  // 调用无参构造器,必须放第一行
        this.name = name;
        this.age = age;
    }
  
    // 单参构造器:复用双参构造器
    public Student(String name) {
        this(name, 0);  // 调用双参构造器,避免代码重复
    }
}

public class Test {
    public static void main(String[] args) {
        // 常见错误:只定义有参构造器,却用无参方式创建对象
        // Student s = new Student();  // 如果只有有参构造器,这行报错!
      
        // 正确做法:始终保留无参构造器
        Student s1 = new Student();           // OK
        Student s2 = new Student("张三", 20);  // OK
        Student s3 = new Student("李四");      // OK,age默认为0
    }
}

第四部分:JavaBean规范

7. JavaBean的标准规范

Q: 什么是JavaBean?需要满足哪些规范?

A: JavaBean(实体类)是一种符合特定规范的Java类,主要用于封装数据

规范要求

规范 说明
属性私有 所有成员变量用 private修饰
无参构造器 必须提供 public的无参构造器
全参构造器 建议提供(可选但推荐)
getter/setter 为每个属性提供公共的访问方法
toString() 重写方法,方便打印对象信息
// 标准JavaBean示例
public class Student {
    // 1. 属性私有
    private String name;
    private int age;
    private double chinese;
    private double math;
  
    // 2. 无参构造器(必须)
    public Student() {
    }
  
    // 3. 全参构造器(推荐)
    public Student(String name, int age, double chinese, double math) {
        this.name = name;
        this.age = age;
        this.chinese = chinese;
        this.math = math;
    }
  
    // 4. getter和setter方法
    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;
    }
  
    public double getChinese() {
        return chinese;
    }
  
    public void setChinese(double chinese) {
        this.chinese = chinese;
    }
  
    public double getMath() {
        return math;
    }
  
    public void setMath(double math) {
        this.math = math;
    }
  
    // 5. 重写toString()
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", chinese=" + chinese +
                ", math=" + math +
                '}';
    }
}

// 使用
public class Test {
    public static void main(String[] args) {
        // 使用全参构造器快速创建对象
        Student s = new Student("黑马", 20, 100, 90);
      
        // 直接打印对象,显示属性值(因为重写了toString)
        System.out.println(s);  
        // 输出:Student{name='黑马', age=20, chinese=100.0, math=90.0}
    }
}

8. IDEA快速生成JavaBean

Q: IDEA中如何快速生成JavaBean的代码?

A: 快捷键Alt + Insert(或右键 → Generate)

生成内容 操作步骤
构造器 Alt + InsertConstructor → 选择参数
getter/setter Alt + InsertGetter and Setter → 全选属性
toString() Alt + InserttoString() → 全选属性
public class Movie {
    private String name;
    private double score;
    private String director;
  
    // 1. 生成无参构造器:Alt+Insert → Constructor → Select None
    public Movie() {
    }
  
    // 2. 生成全参构造器:Alt+Insert → Constructor → Ctrl+A全选
    public Movie(String name, double score, String director) {
        this.name = name;
        this.score = score;
        this.director = director;
    }
  
    // 3. 生成getter/setter:Alt+Insert → Getter and Setter → Ctrl+A全选
    public String getName() {
        return name;
    }
  
    public void setName(String name) {
        this.name = name;
    }
  
    // ... 其他getter/setter
  
    // 4. 生成toString():Alt+Insert → toString() → Ctrl+A全选
    @Override
    public String toString() {
        return "Movie{" +
                "name='" + name + '\'' +
                ", score=" + score +
                ", director='" + director + '\'' +
                '}';
    }
}

第五部分:static关键字

9. static修饰成员变量

Q: static修饰的成员变量有什么特点?与实例变量有什么区别?

A: static变量(静态变量/类变量)属于,在内存中只有一份,被所有对象共享。

特性 静态变量(static) 实例变量(非static)
归属 属于类 属于对象
内存份数 只有1份 每个对象1份
访问方式 类名.变量名(推荐)或 对象.变量名 对象.变量名
别名 类变量 实例变量
public class Student {
    // 静态变量:属于类,只有一份,所有对象共享
    public static String schoolName = "黑马程序员";
    public static int count = 0;  // 统计创建了多少个学生
  
    // 实例变量:属于对象,每个对象独立
    private String name;
    private int age;
  
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        count++;  // 每创建一个学生,计数+1
    }
}

public class Test {
    public static void main(String[] args) {
        // 访问静态变量:类名.变量名(推荐)
        System.out.println(Student.schoolName);  // 黑马程序员
      
        Student s1 = new Student("张三", 20);
        Student s2 = new Student("李四", 21);
      
        // 静态变量共享
        System.out.println(Student.count);  // 2(两个对象共享)
        System.out.println(s1.count);       // 2(也可以用对象访问,但不推荐)
        System.out.println(s2.count);       // 2
      
        // 修改静态变量:影响所有对象
        Student.schoolName = "传智教育";
        System.out.println(s1.schoolName);  // 传智教育
        System.out.println(s2.schoolName);  // 传智教育
    }
}

10. static修饰成员方法

Q: 静态方法和实例方法有什么区别?如何选择?

A:

特性 静态方法(static) 实例方法(非static)
归属 属于类 属于对象
调用方式 类名.方法名()(推荐) 对象.方法名()
访问成员 只能访问静态成员 可以访问静态+实例成员
this关键字 不能使用 可以使用
应用场景 工具方法、不依赖对象数据的方法 需要操作对象属性的方法
public class Student {
    private String name;           // 实例变量
    private static int count = 0;  // 静态变量
  
    // 实例方法:需要操作对象属性
    public void study() {
        // 可以访问实例变量
        System.out.println(name + "在学习");
      
        // 也可以访问静态变量
        System.out.println("当前学生数:" + count);
      
        // 可以使用this
        this.name = "学习中";
    }
  
    // 静态方法:不依赖对象,属于类
    public static void printHello() {
        System.out.println("Hello World");
      
        // 不能访问实例变量!
        // System.out.println(name);  // 编译报错!
      
        // 不能访问实例方法!
        // study();  // 编译报错!
      
        // 可以访问静态成员
        System.out.println("学生总数:" + count);
      
        // 不能使用this!
        // this.name = "xxx";  // 编译报错!
      
        // 如果必须访问实例成员,需要先创建对象
        Student s = new Student();
        s.name = "临时学生";
    }
}

// 工具类:全部用静态方法
public class StringUtil {
    // 构造器私有,防止创建对象
    private StringUtil() {}
  
    // 静态工具方法
    public static int getLength(String str) {
        return str.length();
    }
  
    public static boolean isEmpty(String str) {
        return str == null || str.length() == 0;
    }
}

// 使用
public class Test {
    public static void main(String[] args) {
        // 调用静态方法:类名.方法名
        Student.printHello();
      
        // 调用实例方法:必须先创建对象
        Student s = new Student();
        s.study();
      
        // 工具类使用:无需创建对象
        int len = StringUtil.getLength("hello");  // 5
        boolean empty = StringUtil.isEmpty("");   // true
    }
}

11. 静态代码块与实例代码块

Q: 什么是静态代码块和实例代码块?执行时机是什么?

A:

代码块类型 语法 执行时机 执行次数
静态代码块 static { } 类加载时执行 只执行1次
实例代码块 { } 创建对象时执行(构造器之前) 每次创建对象都执行
public class Demo {
    // 静态代码块:类加载时执行,只执行一次
    static {
        System.out.println("静态代码块执行");
        // 常用于初始化静态变量
        count = 100;
    }
  
    // 实例代码块:每次创建对象时执行,在构造器之前
    {
        System.out.println("实例代码块执行");
    }
  
    public static int count;
  
    public Demo() {
        System.out.println("构造器执行");
    }
  
    public static void main(String[] args) {
        System.out.println("main开始");
      
        Demo d1 = new Demo();
        // 输出顺序:
        // 静态代码块执行(类加载时)
        // main开始
        // 实例代码块执行
        // 构造器执行
      
        Demo d2 = new Demo();
        // 输出:
        // 实例代码块执行
        // 构造器执行
        // (静态代码块不再执行!)
    }
}

第六部分:综合案例

12. 电影信息展示系统

Q: 如何设计一个电影信息展示系统?涉及哪些知识点?

A: 涉及知识点

  • JavaBean封装电影数据
  • static静态变量存储共享数据
  • static静态方法提供功能
  • 数组存储多个对象
  • 用户交互菜单
// 1. 电影实体类(JavaBean)
public class Movie {
    private String name;      // 电影名称
    private double score;     // 评分
    private String director;  // 导演
  
    // 构造器、getter/setter、toString...
    public Movie() {}
  
    public Movie(String name, double score, String director) {
        this.name = name;
        this.score = score;
        this.director = director;
    }
  
    // getter和setter...
    public String getName() { return name; }
    public double getScore() { return score; }
    public String getDirector() { return director; }
}

// 2. 电影系统类(功能实现)
public class MovieSystem {
    // 静态变量:存储所有电影(全局一份)
    private static Movie[] movies;
  
    // 静态代码块:初始化电影数据
    static {
        movies = new Movie[6];
        movies[0] = new Movie("肖申克的救赎", 9.7, "弗兰克·德拉邦特");
        movies[1] = new Movie("霸王别姬", 9.6, "陈凯歌");
        movies[2] = new Movie("阿甘正传", 9.5, "罗伯特·泽米吉斯");
        movies[3] = new Movie("泰坦尼克号", 9.5, "詹姆斯·卡梅隆");
        movies[4] = new Movie("千与千寻", 9.4, "宫崎骏");
        movies[5] = new Movie("黑马程序员", 9.9, "黑马");
    }
  
    // 静态方法:显示所有电影
    public static void showAllMovies() {
        System.out.println("=== 全部电影 ===");
        for (int i = 0; i < movies.length; i++) {
            System.out.println((i+1) + ". " + movies[i].getName());
        }
    }
  
    // 静态方法:根据名称搜索电影
    public static void showDetailByName(String name) {
        int found = 0;
        for (Movie movie : movies) {
            // contains:模糊匹配
            if (movie.getName().contains(name)) {
                found++;
                System.out.println("找到第" + found + "部:");
                System.out.println("  名称:" + movie.getName());
                System.out.println("  评分:" + movie.getScore());
                System.out.println("  导演:" + movie.getDirector());
            }
        }
        if (found == 0) {
            System.out.println("未找到相关电影");
        }
    }
}

// 3. 主程序(用户交互)
public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
    
        while (true) {
            System.out.println("=== 黑马影院 ===");
            System.out.println("1. 显示全部电影");
            System.out.println("2. 搜索电影");
            System.out.println("3. 退出");
            System.out.print("请选择:");
        
            int choice = sc.nextInt();
        
            switch (choice) {
                case 1 -> MovieSystem.showAllMovies();  // 调用静态方法
                case 2 -> {
                    System.out.print("请输入电影名称:");
                    String name = sc.next();
                    MovieSystem.showDetailByName(name);
                }
                case 3 -> {
                    System.out.println("欢迎下次光临!");
                    return;
                }
                default -> System.out.println("无效选择");
            }
        }
    }
}
评论交流

文章目录