Java基础笔记(一)

Java面向对象核心知识点随堂笔记

前言

本次笔记完整复盘了Java面向对象入门的核心授课内容,同时补充了课堂提及的多线程经典问题的底层原理,涵盖多线程原子性基础、封装、继承、方法重写与重载等核心知识点,修正了示例代码的语法问题,适配Java入门新手的复盘与巩固需求。

一、多线程基础:经典count++原子性问题

课堂开篇先讲解了CPU的线程执行特性,以及Java多线程中最经典的count++数据安全问题,这里做完整梳理与原理补充。

1. 线程的执行本质

  • 宏观层面:CPU呈现多任务并行执行的效果,我们可以同时运行多个软件、执行多个任务,无明显卡顿感知。
  • 微观层面:CPU是以纳秒(ns)级的速度,高速交替执行不同线程的任务,同一时刻单个CPU核心只会执行一个线程的指令,只是切换速度极快,人眼无法感知。

2. 问题场景与现象

  • 初始变量:int count = 0;
  • 线程A:循环执行count++ 一百万次
  • 线程B:循环执行count++ 一百万次
  • 预期结果:count最终值为200万
  • 实际结果:最终值远小于200万,甚至会出现几万、十几万的大幅偏差

3. 核心原因:数据覆盖与非原子性操作

这里补充课堂未展开的底层执行逻辑:count++ 看似是一行代码,在CPU执行时会被拆分为3步独立的指令,不具备原子性(原子性指一个操作要么一次性全部执行完成,要么完全不执行,中间不能被打断):

  1. 读取:从主内存中读取count的当前值,加载到当前线程的工作内存
  2. 计算:在工作内存中,对读取到的值执行+1操作
  3. 回写:将计算后的新值,写回主内存

正是因为CPU会高速交替执行两个线程,就会出现临界问题:线程A读取了count=0,还没来得及回写新值,CPU就切换到了线程B,线程B也读取到了count=0。两个线程都对0做了+1操作,最终都回写了1,本该两次+1让count变成2,结果只增加了1,这就是数据覆盖问题,也是最终结果不符合预期的根源。

二、面向对象三大特性之:封装

1. 封装的核心定义

封装的核心思想,是将类中的成员变量(属性)私有化隐藏,禁止外部类直接访问和修改 ,只对外暴露统一的get/set方法,供外部安全地操作属性。

2. 封装的核心实现规则

  • 权限控制:使用private(私有)权限修饰符修饰成员变量,被private修饰的内容,仅能在当前类内部访问,外部类无法直接调用。
  • 对外接口:为每个private修饰的成员变量,提供对应的getXxx()(获取属性值)和setXxx()(设置属性值)方法,方法使用public修饰,对外公开访问。

3. 封装的完整代码示例(修正课堂代码语法问题)

java 复制代码
package com.qcby;

/**
 * 封装示例:Person实体类
 */
public class Person {
    // 私有成员变量,外部无法直接访问
    private String name = "admin";
    public int age;
    private String sex;
    private String address;
    private String phone;

    // 对外提供name属性的get方法:获取属性值
    public String getName() {
        return name;
    }

    // 对外提供name属性的set方法:设置属性值
    public void setName(String name) {
        // 封装的核心优势:可添加数据校验,避免非法数据赋值
        if (name != null && !name.isEmpty()) {
            this.name = name;
        }
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        // 年龄合法性校验,保障数据安全
        if (age >= 0 && age <= 120) {
            this.age = age;
        }
    }

    // 其余私有属性的get/set方法,可按照相同格式补充
}
java 复制代码
package com.qcby;

/**
 * 封装测试类
 */
public class Test {
    public static void main(String[] args) {
        Person p1 = new Person();
        // 通过get方法获取初始值
        System.out.println(p1.getName());
        // 通过set方法修改name属性值
        p1.setName("张三");
        // 获取修改后的值
        System.out.println(p1.getName());

        Person p2 = new Person();
        p2.setAge(20);
        System.out.println(p2.getAge());
    }
}

4. 封装的核心优势

  1. 数据安全:可在set方法中添加数据校验逻辑,避免非法数据赋值,从源头保障属性的合法性。
  2. 隐藏实现细节:外部仅需调用get/set方法,无需关注类内部的实现逻辑,降低代码耦合度。
  3. 提升可维护性:属性的修改规则仅需在类内部的get/set方法中调整,无需修改所有调用处的代码。

三、面向对象三大特性之:继承

1. 继承的核心本质

继承的核心是代码复用。通过继承,子类可以直接使用父类中非private修饰的成员变量和成员方法,无需重复编写相同的逻辑代码,大幅减少代码冗余。

2. 继承的核心语法与规则

  • 关键字:通过extends关键字实现类的继承
  • 基础格式:public class 子类名 extends 父类名 { }
  • 别称对应:父类也叫超类、基类;子类也叫派生类
  • 单继承限制:Java只支持单继承,一个子类只能有一个直接父类,但一个父类可以拥有多个子类。

3. 继承的核心调用规则

  • 子类可以直接调用父类中非private修饰的方法和属性。
  • 父类无法调用子类中独有的方法和属性。
  • 继承具有传递性:A类继承B类,B类继承C类,则A类可直接使用B类和C类中非private的内容。

4. 继承的完整代码示例(修正课堂代码命名规范)

java 复制代码
package qcby;

/**
 * 父类:动物类,提取所有动物的通用行为
 */
public class Animal {
    public void run() {
        System.out.println("running...");
    }

    public void eat() {
        System.out.println("eating...");
    }

    public void jump() {
        System.out.println("jumping...");
    }
}
java 复制代码
package qcby;

/**
 * 子类:猫类,继承自动物类
 */
public class Cat extends Animal {
    // 子类独有的方法,父类无法调用
    public void catchMouse() {
        System.out.println("小猫抓老鼠...");
    }
}
java 复制代码
package qcby;

/**
 * 继承测试类
 */
public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();
        // 调用继承自父类的通用方法
        cat.jump();
        cat.run();
        cat.eat();
        // 调用子类自身独有的方法
        cat.catchMouse();
    }
}

四、方法的重写(Override)与重载(Overload)

方法重写与重载是Java入门最容易混淆的两个知识点,这里结合课堂内容做清晰区分、规则补充与示例演示。

1. 方法的重写(Override)

核心定义

方法重写发生在父子类之间 ,子类重写父类中已有的方法,要求方法名、参数列表必须和父类完全一致。子类对象调用该方法时,会优先执行子类重写后的逻辑,而非父类的原有逻辑。

完整代码示例
java 复制代码
package com.qcby;

/**
 * 父类
 */
public class Animal {
    public void eat() {
        System.out.println("动物在吃东西...");
    }
}
java 复制代码
package com.qcby;

/**
 * 子类:猫类,重写父类的eat方法
 */
public class Cat extends Animal {
    // @Override注解:标记该方法是重写父类的方法,编译时会自动校验语法合法性
    @Override
    public void eat() {
        System.out.println("小猫吃的很多....");
    }
}
java 复制代码
package com.qcby;

public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();
        // 执行子类重写后的方法,输出:小猫吃的很多....
        cat.eat();
    }
}
重写的核心规则(补充)
  1. 方法名、参数列表必须与父类完全一致。
  2. 子类方法的访问权限,不能比父类更严格(例如父类方法是public,子类重写时就不能用private修饰)。
  3. 父类中被private、final、static修饰的方法,无法被重写。
  4. 强烈建议添加@Override注解,编译器会自动校验重写语法,避免因方法名、参数列表写错导致的隐性问题。

2. 方法的重载(Overload)

核心定义

方法重载发生在同一个类当中 ,多个方法的方法名完全相同,但参数列表不同 ,返回值、访问修饰符可以不同。

在Java中,判断两个方法是否重复的唯一标准是:方法名 + 参数列表,与返回值无关。

参数列表不同的判定标准

满足以下任意一种,即可判定为参数列表不同,构成方法重载:

  1. 参数的个数不同
  2. 参数的类型不同
  3. 参数的顺序不同
完整代码示例
java 复制代码
public class Calculator {
    // 两个int类型数值相加
    public int add(int a, int b) {
        return a + b;
    }

    // 参数个数不同,构成重载
    public int add(int a, int b, int c) {
        return a + b + c;
    }

    // 参数类型不同,构成重载
    public double add(double a, double b) {
        return a + b;
    }

    // 参数顺序不同,构成重载
    public void show(String name, int age) {
        System.out.println("姓名:" + name + ",年龄:" + age);
    }

    public void show(int age, String name) {
        System.out.println("年龄:" + age + ",姓名:" + name);
    }
}

3. 重写与重载的核心区别对照表

对比维度 方法重写(Override) 方法重载(Overload)
发生范围 父子类之间 同一个类当中
方法名 必须完全相同 必须完全相同
参数列表 必须完全相同 必须不同
返回值 必须与父类一致(或其子类) 无强制要求
访问修饰符 不能比父类更严格 无强制要求
核心作用 子类自定义父类的方法逻辑 同一个方法名适配多种入参场景

五、笔记核心总结

  1. 多线程中count++并非原子操作,会因CPU交替执行出现数据覆盖问题,这是多线程线程安全的入门核心场景。
  2. 封装的核心是私有化属性、对外提供get/set方法,核心价值是保障数据安全、隐藏实现细节。
  3. 继承的核心是代码复用,Java仅支持单继承,子类可使用父类非private的成员,父类无法访问子类独有内容。
  4. 方法重写发生在父子类之间,是子类对父类方法的重构;方法重载发生在同一个类中,是同名方法的多场景适配,二者核心判定标准均为方法名+参数列表。
相关推荐
21439651 小时前
网页如何运行html
jvm·数据库·python
程序员老邢1 小时前
【产品底稿 05】商助慧 V1.1 里程碑:RAG 文章仿写模块全链路实现
java·spring boot·程序人生·ai·milvus
Irene19912 小时前
(AI总结版)Rich 配置经验总结:PyCharm 终端颜色显示操作指南
python·pycharm
小张同学8242 小时前
[特殊字符]Python 进阶实战指南(PyCharm 专属优化):从高效编码到工程化落地,告别新手低效写法
开发语言·python·pycharm
2402_854808372 小时前
Golang数组和切片有什么区别_Golang数组切片对比教程【通俗】
jvm·数据库·python
2401_865439632 小时前
如何在 Go 中精确安装指定版本的模块
jvm·数据库·python
消失的旧时光-19432 小时前
Spring Boot 实战(三):Service 分层 + 统一返回 + 异常处理(工程级写法)
java·spring boot·接口·解耦
云烟成雨TD2 小时前
Spring AI Alibaba 1.x 系列【20】MessagesAgentHook 、MessagesModelHook 相关实现类
java·人工智能·spring
霸道流氓气质2 小时前
SpringBoot中集成LangChain4j实现集成阿里百炼平台进行AI对话记忆功能和对话隔离功能
java·人工智能·spring boot·langchain4j