【Java基础|学习路线 && 快速回顾】

📚 Java + AI 完整学习笔记(整理版)

💡 核心提示:本笔记整合了Java基础到进阶的全部核心知识点,按学习路径组织,去除重复内容,便于快速回顾和复习。


Day 1 - Java入门与环境搭建

快速回顾

  • Java三大平台:SE(标准版)、EE(企业版)、ME(小型版)

  • JDK ⊃ JRE ⊃ JVM,JDK用于开发,JRE用于运行,JVM实现跨平台

  • 开发流程:编写.java → javac编译 → 生成.class → JVM解释执行

内容

1. Java核心特性

跨平台原理:一次编写,多处运行。JVM将字节码翻译成对应操作系统的机器指令。

2. JDK/JRE/JVM关系

组件 作用 包含内容
JVM 跨平台核心 字节码解析执行
JRE 运行环境 JVM + 核心类库
JDK 开发工具包 JRE + 编译工具(javac/java等)

3. 环境配置

复制代码
# 验证安装
java -version
javac -version

环境变量配置:

  • JAVA_HOME: JDK安装路径

  • Path: %JAVA_HOME%\bin

4. HelloWorld程序

复制代码
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

编译运行:

复制代码
javac HelloWorld.java    # 编译
java HelloWorld          # 运行

5. 编码规范

  • 类名:大驼峰(HelloWorld)

  • 方法/变量:小驼峰(helloWorld)

  • 常量:全大写(MAX_VALUE)

问答

Q1: 为什么说Java是跨平台的? A: Java程序编译后生成字节码(.class),不同操作系统安装对应的JVM,JVM将字节码翻译成该系统的机器指令执行。

Q2: JDK和JRE的区别? A: JDK是开发工具包,包含JRE和编译工具;JRE是运行环境,只包含运行所需组件。开发需要JDK,运行只需要JRE。

Q3: 环境变量的作用是什么? A: 让系统在任何目录下都能识别javac、java等命令,而不必进入JDK的bin目录。


Day 2 - 方法、类型转换、运算符

快速回顾

  • 方法:封装功能的代码块,支持重载(同名不同参)

  • 类型转换:小→大自动转,大→小强制转(可能丢失精度)

  • 运算符:算术、赋值、比较、逻辑、位运算、三元

内容

1. 方法详解

完整语法:

复制代码
修饰符 返回值类型 方法名(参数列表) {
    方法体
    return 返回值;
}

方法重载规则:

  • 同一类中,方法名相同

  • 参数列表不同(个数/类型/顺序)

  • 与返回值无关

复制代码
public static void print(int num) { }
public static void print(String str) { }
public static void print(double num, String desc) { }

2. 类型转换

类型范围 :byte < short < char < int < long < float < double

转换类型 方向 语法 安全性
自动转换 小→大 int a = byteVal; 安全
强制转换 大→小 int a = (int)doubleVal; 可能丢失

表达式自动提升:

复制代码
byte a = 10;
byte b = 20;
int c = a + b;  // 运算时自动提升为int

3. 运算符

算术运算符 :+ - * / % ++ --

赋值运算符 := += -= *= /= %=

比较运算符 :== != > < >= <=

逻辑运算符 :&& || ! & |

  • &&短路与:左边false右边不执行

  • ||短路或:左边true右边不执行

三元运算符 :条件 ? 值1 : 值2

问答

Q1: 方法重载和方法重写有什么区别? A: 重载是同一类中同名不同参;重写是子类对父类方法的重新实现,方法签名相同。

Q2: 强制转换可能产生什么问题? A: 大范围转小范围可能导致数据溢出或精度丢失,如int转byte可能截断高位。

Q3: && 和 & 的区别? A: &&是短路与,左边false右边不执行;&是非短路,两边都执行。||和|同理。


Day 3 - 流程控制

快速回顾

  • 顺序结构:默认自上而下执行

  • 分支结构:if/switch条件判断

  • 循环结构:for/while/do-while重复执行

  • 跳转语句:break/continue控制流程

内容

1. 分支结构

if分支:

复制代码
// 单条件
if (条件) { 语句体; }
​
// 二选一
if (条件) { 语句体1; } else { 语句体2; }
​
// 多条件
if (条件1) { } else if (条件2) { } else { }

switch分支:

复制代码
switch(表达式) {
    case 值1: 语句体1; break;
    case 值2: 语句体2; break;
    default: 默认语句;
}
  • 表达式支持:byte/short/int/char/枚举/String(JDK7+)

  • case值必须是字面量,不能重复

  • 无break会"穿透"执行

2. 循环结构

for循环(已知次数):

复制代码
for (初始化; 条件; 迭代) {
    循环体;
}

while循环(未知次数):

复制代码
while (条件) {
    循环体;
}

do-while循环(至少执行一次):

复制代码
do {
    循环体;
} while (条件);

3. 跳转语句

语句 作用
break 跳出当前循环/switch
continue 跳过本次循环,继续下一次
return 结束方法执行

问答

Q1: if和switch的使用场景区别? A: if支持区间和多条件组合,更灵活;switch适合等值判断,代码更简洁。

Q2: for、while、do-while如何选择? A: 已知循环次数用for;未知次数用while;至少执行一次用do-while。

Q3: break和continue的区别? A: break是跳出整个循环;continue是跳过本次,继续下一次循环。


Day 4 - 数组

快速回顾

  • 数组:同类型数据的连续内存集合,长度固定

  • 索引从0开始,通过索引快速访问

  • Arrays工具类提供排序、搜索、复制等操作

内容

1. 数组初始化

复制代码
// 静态初始化
int[] arr1 = {1, 2, 3};
int[] arr2 = new int[]{1, 2, 3};
​
// 动态初始化
int[] arr3 = new int[5];  // 默认值0
String[] arr4 = new String[5];  // 默认值null

默认值规则:整数0,浮点0.0,布尔false,引用类型null

2. 数组遍历

复制代码
// 普通for
for (int i = 0; i < arr.length; i++) {
    System.out.println(arr[i]);
}
​
// 增强for
for (int num : arr) {
    System.out.println(num);
}
​
// 快速打印
System.out.println(Arrays.toString(arr));

3. 二维数组

复制代码
// 初始化
int[][] arr = {{1,2}, {3,4,5}, {6}};
​
// 遍历
for (int i = 0; i < arr.length; i++) {
    for (int j = 0; j < arr[i].length; j++) {
        System.out.println(arr[i][j]);
    }
}

4. Arrays工具类

方法 功能
sort(arr) 排序(快排/TimSort)
binarySearch(arr, key) 二分查找(需先排序)
copyOf(arr, length) 复制数组
fill(arr, val) 填充数组
equals(arr1, arr2) 比较数组
toString(arr) 转字符串

问答

Q1: 数组和ArrayList的区别? A: 数组长度固定,可存基本类型;ArrayList长度可变,只能存对象。

Q2: 为什么数组索引从0开始? A: 索引表示偏移量,arr0表示从首地址偏移0个单位。

Q3: 二分查找的前提条件? A: 数组必须是有序的,否则结果不可预期。


Day 5 - 面向对象基础

快速回顾

  • 类是模板,对象是实例

  • 封装:private属性 + public方法

  • 构造器:初始化对象,可重载

  • this:区分成员变量和局部变量

内容

1. 类与对象

复制代码
public class Student {
    // 成员变量
    private String name;
    private int age;
    
    // 构造器
    public Student() {}
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 成员方法
    public void study() {
        System.out.println(name + "在学习");
    }
    
    // getter/setter
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

2. 封装

作用:保护数据安全,隐藏实现细节

实现:

  • 属性私有化(private)

  • 提供公共访问方法(getter/setter)

3. 构造器

特点:

  • 方法名与类名相同

  • 无返回值(void也没有)

  • 默认提供无参构造,定义有参后需手动添加无参

this调用构造器:

复制代码
public Student() {
    this("未知", 0);  // 必须放第一行
}

4. this关键字

用途 示例
区分成员变量 this.name = name;
调用其他构造器 this(参数);
返回当前对象 return this;

问答

Q1: 成员变量和局部变量的区别? A: 成员变量在类中定义,有默认值,作用域整个类;局部变量在方法中定义,无默认值,作用域方法内。

Q2: 为什么要封装? A: 保护数据不被随意修改,可以在setter中添加校验逻辑,提高安全性。

Q3: 构造器和普通方法的区别? A: 构造器无返回值,方法名与类名相同,用于初始化对象;普通方法有返回值,用于实现功能。


Day 6 - 继承、多态、final、单例模式

快速回顾

  • 继承:子类extends父类,复用代码

  • 多态:父类引用指向子类对象,方法重写实现

  • final:修饰类(不可继承)、方法(不可重写)、变量(不可变)

  • 单例:全局唯一实例

内容

1. 继承

复制代码
class Animal {
    protected String name;
    public void eat() { }
}
​
class Dog extends Animal {
    public void bark() { }
}

方法重写规则:

  • 方法名、参数列表相同

  • 返回值类型相同或子类(协变)

  • 访问权限≥父类

  • 异常≤父类

super关键字:

复制代码
public Dog(String name) {
    super(name);  // 调用父类构造器
}

2. 多态

前提条件:

  1. 继承关系

  2. 方法重写

  3. 父类引用指向子类对象

复制代码
Animal animal = new Dog();  // 向上转型
animal.eat();  // 调用Dog的eat()
​
// 向下转型
if (animal instanceof Dog) {
    Dog dog = (Dog) animal;
    dog.bark();
}

3. final关键字

修饰 作用
类 不可被继承
方法 不可被重写
变量 不可重新赋值(常量)

4. 单例模式

饿汉式:

复制代码
public class Singleton {
    private static final Singleton INSTANCE = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

懒汉式:

复制代码
public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

问答

Q1: 重载和重写的区别? A: 重载是同一类中同名不同参;重写是子类对父类方法的重新实现,方法签名相同。

Q2: 多态的好处? A: 提高代码扩展性,便于维护。如定义Animal\[\]数组,可存Dog、Cat等各种子类对象。

Q3: 单例模式的应用场景? A: 配置类、连接池、线程池等需要全局唯一实例的场景。


Day 7 - 抽象类、接口、代码块、内部类

快速回顾

  • 抽象类:半成品,可含抽象方法和普通方法

  • 接口:行为规范,JDK8+支持默认/静态方法

  • 代码块:静态代码块(类加载执行)、构造代码块(创建对象执行)

  • 内部类:成员/局部/匿名/静态内部类

内容

1. 抽象类

复制代码
abstract class Animal {
    String name;
    
    abstract void cry();  // 抽象方法
    
    void eat() {  // 普通方法
        System.out.println("eating");
    }
}

特点:

  • 不能实例化

  • 子类必须实现所有抽象方法

  • 单继承

2. 接口

复制代码
interface Swim {
    void swim();  // 默认public abstract
    
    default void warmUp() {  // 默认方法
        System.out.println("热身");
    }
    
    static void showRule() {  // 静态方法
        System.out.println("规则");
    }
}

接口vs抽象类:

特性 接口 抽象类
方法 JDK8前只能抽象 可有抽象和普通方法
继承 多实现 单继承
变量 默认public static final 普通成员变量
构造器 无 有

3. 代码块

复制代码
public class Demo {
    static {  // 静态代码块
        // 类加载时执行,只执行一次
    }
    
    {  // 构造代码块
        // 每次创建对象时执行
    }
    
    public Demo() {
        // 构造器
    }
}

4. 内部类

复制代码
public class Outer {
    // 成员内部类
    class Inner {
        void show() {
            System.out.println(Outer.this.name);  // 访问外部类成员
        }
    }
    
    // 静态内部类
    static class StaticInner { }
    
    public void method() {
        // 局部内部类
        class LocalInner { }
        
        // 匿名内部类
        Runnable r = new Runnable() {
            public void run() { }
        };
    }
}

问答

Q1: 抽象类和接口的区别? A: 抽象类是半成品模板,单继承;接口是行为规范,多实现。JDK8后接口可有默认方法。

Q2: 什么时候用抽象类,什么时候用接口? A: is-a关系用抽象类(如Dog is a Animal);has-a能力用接口(如Dog has Swim ability)。

Q3: 内部类的作用? A: 封装隐藏、访问外部类私有成员、实现回调机制(如匿名内部类)。


Day 8 - 函数式编程、常用API

快速回顾

  • Lambda:简化匿名内部类,(参数) -> {方法体}

  • 方法引用:::简化Lambda

  • String:不可变,常量池机制

  • ArrayList:动态数组,自动扩容

内容

1. Lambda表达式

复制代码
// 匿名内部类
Comparator<Integer> c1 = new Comparator<Integer>() {
    public int compare(Integer a, Integer b) {
        return a - b;
    }
};
​
// Lambda完整
Comparator<Integer> c2 = (Integer a, Integer b) -> {
    return a - b;
};
​
// Lambda最简
Comparator<Integer> c3 = (a, b) -> a - b;

函数式接口:只有一个抽象方法的接口

  • Runnable: () -> void

  • Comparator<T>: (T, T) -> int

  • Function<T, R>: T -> R

  • Predicate<T>: T -> boolean

  • Consumer<T>: T -> void

  • Supplier<T>: () -> T

2. 方法引用

类型 语法 示例
静态方法 类名::静态方法 Integer::parseInt
实例方法 对象::实例方法 str::toUpperCase
特定类型 类名::实例方法 String::length
构造器 类名::new ArrayList::new

3. String类

核心特性:

  • 不可变:修改创建新对象

  • 常量池:字面量方式创建入池

复制代码
String s1 = "abc";              // 常量池
String s2 = new String("abc");  // 堆内存
String s3 = s2.intern();        // 入池
System.out.println(s1 == s3);   // true

常用方法:

  • length(), charAt(), substring(), split(), replace(), contains(), equals(), trim(), startsWith()

4. ArrayList

复制代码
List<String> list = new ArrayList<>();
list.add("A");
list.get(0);
list.set(0, "B");
list.remove(0);
list.size();

遍历方式:

复制代码
// 普通for
for (int i = 0; i < list.size(); i++) { }

// 增强for
for (String s : list) { }

// 迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) { }

// forEach + Lambda
list.forEach(s -> System.out.println(s));

问答

Q1: Lambda的使用前提? A: 必须是函数式接口(只有一个抽象方法)。

Q2: String为什么不可变? A: 底层用final char\[\]存储,保证安全(如作为HashMap的key)、节省内存(常量池复用)。

Q3: ArrayList的扩容机制? A: 默认初始容量10,扩容时增长为原来的1.5倍,使用Arrays.copyOf复制元素。


Day 9 - 项目实战:银行管理系统

快速回顾

  • 分层架构:model/dao/util/ui

  • JDBC:Java连接数据库的标准API

  • Swing:Java GUI开发工具包

内容

1. 项目结构

复制代码
src/main/java/com/bank/
├── model/      # 实体类(Account, Transaction)
├── dao/        # 数据访问层(数据库CRUD)
├── util/       # 工具类(DBUtil)
└── ui/         # 界面层(Swing组件)

2. JDBC核心步骤

复制代码
// 1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");

// 2. 获取连接
Connection conn = DriverManager.getConnection(url, user, password);

// 3. 创建Statement
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, param);

// 4. 执行SQL
ResultSet rs = ps.executeQuery();  // 查询
int rows = ps.executeUpdate();     // 增删改

// 5. 处理结果
while (rs.next()) {
    String name = rs.getString("name");
}

// 6. 关闭资源
rs.close(); ps.close(); conn.close();

3. 事务处理

复制代码
try {
    conn.setAutoCommit(false);  // 开启事务
    // 执行多个SQL操作
    conn.commit();  // 提交
} catch (Exception e) {
    conn.rollback();  // 回滚
} finally {
    conn.setAutoCommit(true);
}

问答

Q1: 为什么要分层架构? A: 高内聚低耦合,便于维护和扩展。各层职责清晰,如dao层只负责数据库操作。

Q2: Statement和PreparedStatement的区别? A: PreparedStatement预编译SQL,防止SQL注入,性能更好,支持参数化查询。

Q3: 事务的ACID特性? A: 原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。


Day 10 - 异常、泛型、集合

快速回顾

  • 异常:Error(系统级)和Exception(可处理)

  • 泛型:编译期类型检查,类型擦除

  • 集合:List(有序可重复)、Set(无序不重复)

内容

1. 异常体系

复制代码
Throwable
├─ Error(不可恢复)
│  ├─ OutOfMemoryError
│  └─ StackOverflowError
└─ Exception
   ├─ 编译时异常(Checked):必须处理
   └─ 运行时异常(Unchecked):RuntimeException

处理方式:

复制代码
// try-catch-finally
try {
    // 可能抛异常的代码
} catch (SpecificException e) {
    // 处理特定异常
} finally {
    // 必须执行的代码
}

// throws声明
public void read() throws IOException { }

// 主动抛出
throw new IllegalArgumentException("参数错误");

// try-with-resources(自动关闭)
try (FileInputStream fis = new FileInputStream("file.txt")) { }

2. 泛型

复制代码
// 泛型类
class Box<T> {
    private T data;
    public T getData() { return data; }
}

// 泛型方法
public <T> T getElement(T[] array, int index) {
    return array[index];
}

// 泛型接口
interface DataOperate<T> {
    void add(T data);
}

通配符:

  • ?:任意类型

  • ? extends T:T或T的子类(上界,只读)

  • ? super T:T或T的父类(下界,只写)

3. List集合

实现类 底层结构 特点
ArrayList 数组 查询快O(1),增删慢O(n)
LinkedList 双向链表 查询慢O(n),增删快O(1)
Vector 数组 线程安全,已过时

问答

Q1: 编译时异常和运行时异常的区别? A: 编译时异常必须处理(try-catch或throws),运行时异常可不处理,如NullPointerException。

Q2: 泛型的类型擦除是什么? A: 编译期泛型存在,运行期被擦除为Object或上界类型,保证向后兼容。

Q3: ArrayList和LinkedList如何选择? A: 查询多用ArrayList,频繁增删用LinkedList。大部分场景ArrayList更优。


Day 11 - Set、Map、Stream

快速回顾

  • Set:无序不重复,HashSet/LinkedHashSet/TreeSet

  • Map:键值对,HashMap/LinkedHashMap/TreeMap

  • Stream:函数式操作集合,链式调用

内容

1. Set集合

实现类 有序性 底层 特点
HashSet 无序 哈希表 去重、O(1)查询
LinkedHashSet 保留添加顺序 哈希表+链表 去重+有序
TreeSet 排序 红黑树 去重+排序

HashSet去重原理:

  • 先比较hashCode()

  • hashCode相同再比较equals()

  • 两者都相同则认为是重复元素

复制代码
// 必须同时重写hashCode和equals
@Override
public boolean equals(Object o) { }

@Override
public int hashCode() { }

2. Map集合

方法 功能
put(K, V) 添加/覆盖键值对
get(K) 根据键获取值
remove(K) 删除键值对
containsKey(K) 判断是否包含键
keySet() 获取所有键
entrySet() 获取键值对集合

遍历方式:

复制代码
// 1. 键找值
for (String key : map.keySet()) {
    Integer value = map.get(key);
}

// 2. 键值对(推荐)
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    String key = entry.getKey();
    Integer value = entry.getValue();
}

// 3. forEach + Lambda
map.forEach((k, v) -> System.out.println(k + "=" + v));

3. Stream流

复制代码
List<Integer> result = list.stream()
    .filter(x -> x > 10)        // 过滤
    .map(x -> x * 2)            // 映射
    .sorted()                   // 排序
    .limit(5)                   // 限制数量
    .collect(Collectors.toList());  // 收集

常用操作:

  • 中间操作:filter, map, sorted, distinct, limit, skip

  • 终结操作:collect, forEach, count, reduce, anyMatch, allMatch

问答

Q1: HashSet如何保证元素不重复? A: 通过hashCode和equals方法,先比hashCode,相同再比equals。

Q2: HashMap的底层原理? A: JDK8前是数组+链表,JDK8后是数组+链表+红黑树。链表长度>8且数组长度≥64时转红黑树。

Q3: Stream的优势? A: 代码简洁、支持并行处理(parallelStream)、函数式编程风格。


Day 12 - File、递归、IO流

快速回顾

  • File:文件/目录操作,非流操作

  • 递归:方法调用自身,需有终止条件

  • IO流:字节流(InputStream/OutputStream)、字符流(Reader/Writer)

内容

1. File类

复制代码
File file = new File("path");

// 判断
file.exists();
file.isFile();
file.isDirectory();

// 获取信息
file.getName();
file.length();
file.getAbsolutePath();

// 创建删除
file.createNewFile();
file.mkdir();      // 单级目录
file.mkdirs();     // 多级目录
file.delete();     // 删除文件或空目录

// 遍历
File[] files = dir.listFiles();

2. 递归

三要素:

  1. 递归公式

  2. 递归方向(向终止条件靠近)

  3. 终止条件

复制代码
// 阶乘
public int factorial(int n) {
    if (n == 1) return 1;
    return n * factorial(n - 1);
}

// 文件搜索
public void search(File dir, String target) {
    File[] files = dir.listFiles();
    for (File f : files) {
        if (f.isFile() && f.getName().equals(target)) {
            System.out.println("找到:" + f);
        } else if (f.isDirectory()) {
            search(f, target);  // 递归
        }
    }
}

3. IO流

字节流(适合所有文件):

复制代码
// 文件复制
FileInputStream fis = new FileInputStream("src.jpg");
FileOutputStream fos = new FileOutputStream("dest.jpg");
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) != -1) {
    fos.write(buffer, 0, len);
}
fis.close();
fos.close();

字符流(适合文本):

复制代码
BufferedReader br = new BufferedReader(new FileReader("file.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("out.txt"));
String line;
while ((line = br.readLine()) != null) {
    bw.write(line);
    bw.newLine();
}
br.close();
bw.close();

问答

Q1: 字节流和字符流的区别? A: 字节流按字节读写,适合所有文件;字符流按字符读写,带编码转换,适合文本文件。

Q2: 递归的注意事项? A: 必须有终止条件,否则栈溢出;递归深度不宜过大。

Q3: 为什么使用Buffered流? A: 带缓冲区,减少系统IO次数,提高读写效率。


Day 13 - 多线程

快速回顾

  • 线程创建:继承Thread、实现Runnable/Callable

  • 线程状态:新建→就绪→运行→阻塞→死亡

  • 线程安全:synchronized、Lock、原子类

  • 线程池:复用线程,减少创建销毁开销

内容

1. 线程创建

复制代码
// 方式1:继承Thread
class MyThread extends Thread {
    @Override
    public void run() { }
}
new MyThread().start();

// 方式2:实现Runnable(推荐)
class MyRunnable implements Runnable {
    public void run() { }
}
new Thread(new MyRunnable()).start();

// 方式3:实现Callable(有返回值)
FutureTask<Integer> task = new FutureTask<>(new MyCallable());
new Thread(task).start();
Integer result = task.get();  // 阻塞获取结果

2. 线程同步

synchronized:

复制代码
// 同步方法
public synchronized void method() { }

// 同步代码块
synchronized (this) { }
synchronized (obj) { }

Lock接口:

复制代码
Lock lock = new ReentrantLock();
lock.lock();
try {
    // 临界区代码
} finally {
    lock.unlock();
}

3. 线程池

复制代码
ExecutorService pool = Executors.newFixedThreadPool(10);
// 或自定义
ThreadPoolExecutor pool = new ThreadPoolExecutor(
    5,                      // 核心线程数
    10,                     // 最大线程数
    60L,                    // 空闲线程存活时间
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(100)  // 任务队列
);

pool.execute(() -> { });
Future<Integer> future = pool.submit(() -> 100);
pool.shutdown();

4. 常用方法

方法 作用
start() 启动线程
sleep(ms) 休眠,不释放锁
yield() 礼让CPU
join() 等待该线程执行完毕
interrupt() 中断线程

问答

Q1: start()和run()的区别? A: start()启动新线程执行run();直接调用run()只是普通方法调用,不会创建新线程。

Q2: synchronized和Lock的区别? A: synchronized是关键字,自动释放锁;Lock是接口,需手动释放,更灵活(可中断、超时、公平锁)。

Q3: 为什么要用线程池? A: 减少线程创建销毁开销,便于管理,提高响应速度,控制并发数。


Day 14 - 网络编程

快速回顾

  • Socket:网络通信端点,IP+端口

  • TCP:面向连接,可靠传输

  • UDP:无连接,不可靠但效率高

  • C/S架构:客户端/服务端模式

内容

1. TCP通信

服务端:

复制代码
ServerSocket serverSocket = new ServerSocket(8888);
Socket socket = serverSocket.accept();  // 阻塞等待连接
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
// 读写数据
socket.close();
serverSocket.close();

客户端:

复制代码
Socket socket = new Socket("127.0.0.1", 8888);
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
// 读写数据
socket.close();

2. UDP通信

复制代码
// 发送端
DatagramSocket socket = new DatagramSocket();
byte[] data = "Hello".getBytes();
DatagramPacket packet = new DatagramPacket(
    data, data.length, 
    InetAddress.getByName("127.0.0.1"), 8888
);
socket.send(packet);
socket.close();

// 接收端
DatagramSocket socket = new DatagramSocket(8888);
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet);  // 阻塞接收
String msg = new String(packet.getData(), 0, packet.getLength());
socket.close();

3. TCP vs UDP

特性 TCP UDP
连接 面向连接 无连接
可靠性 可靠 不可靠
效率 较低 高
应用场景 文件传输、HTTP 视频直播、DNS

问答

Q1: TCP的三次握手和四次挥手? A: 三次握手建立连接(SYN→SYN+ACK→ACK);四次挥手断开连接(FIN→ACK→FIN→ACK)。

Q2: 为什么需要端口号? A: IP定位主机,端口定位主机上的具体应用程序。

Q3: Socket通信的基本流程? A: 服务端创建ServerSocket监听端口,accept等待连接;客户端创建Socket连接服务端;双方通过输入输出流通信。


Day 15 - 单元测试、反射、注解、动态代理

快速回顾

  • JUnit:单元测试框架,自动化验证代码正确性

  • 反射:运行时获取类信息、操作成员

  • 注解:代码元数据,替代XML配置

  • 动态代理:运行时创建代理对象,实现AOP

内容

1. JUnit单元测试

复制代码
@Test
public void testAdd() {
    Calculator calc = new Calculator();
    int result = calc.add(1, 2);
    assertEquals(3, result);
}

常用注解:

  • @Test:标记测试方法

  • @BeforeEach/@AfterEach:每个测试前后执行

  • @BeforeAll/@AfterAll:类级别执行(静态方法)

常用断言:

  • assertEquals(expected, actual)

  • assertTrue(condition)

  • assertNull(object)

  • assertThrows(Exception.class, () -> { })

2. 反射

复制代码
// 获取Class对象
Class<?> clazz = Class.forName("com.example.User");

// 创建对象
Object obj = clazz.getDeclaredConstructor().newInstance();

// 操作字段
Field field = clazz.getDeclaredField("name");
field.setAccessible(true);  // 暴力访问私有
field.set(obj, "张三");

// 调用方法
Method method = clazz.getDeclaredMethod("sayHello");
method.invoke(obj);

3. 注解

元注解:

复制代码
@Retention(RetentionPolicy.RUNTIME)  // 生命周期
@Target(ElementType.METHOD)          // 作用目标
public @interface MyAnnotation {
    String value() default "";
}

解析注解:

复制代码
if (method.isAnnotationPresent(MyAnnotation.class)) {
    MyAnnotation anno = method.getAnnotation(MyAnnotation.class);
    String value = anno.value();
}

4. 动态代理

JDK动态代理:

复制代码
public class ProxyFactory {
    public static Object createProxy(Object target) {
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            (proxy, method, args) -> {
                System.out.println("前置增强");
                Object result = method.invoke(target, args);
                System.out.println("后置增强");
                return result;
            }
        );
    }
}

问答

Q1: 反射的应用场景? A: 框架开发(Spring IoC、MyBatis)、通用工具(JSON序列化)、IDE代码提示。

Q2: 注解的RetentionPolicy三种类型? A: SOURCE(仅源码)、CLASS(编译到class文件)、RUNTIME(运行时可通过反射获取)。

Q3: 动态代理和静态代理的区别? A: 静态代理需手动编写代理类;动态代理运行时生成代理类,更灵活,Spring AOP基于此实现。


附录:核心知识点速查表

访问修饰符

修饰符 同类 同包 子类 其他包
private ✓ ✗ ✗ ✗
default ✓ ✓ ✗ ✗
protected ✓ ✓ ✓ ✗
public ✓ ✓ ✓ ✓

集合对比

集合 有序 可重复 底层 线程安全
ArrayList ✓ ✓ 数组 ✗
LinkedList ✓ ✓ 链表 ✗
HashSet ✗ ✗ 哈希表 ✗
TreeSet 排序 ✗ 红黑树 ✗
HashMap ✗ key不重复 哈希表 ✗
Hashtable ✗ key不重复 哈希表 ✓
ConcurrentHashMap ✗ key不重复 哈希表 ✓(分段锁)

线程状态转换

复制代码
新建(new) → start() → 就绪(runnable) → 获取CPU → 运行(running)
                           ↑__________________________|
                           |                          |
                         调度                        阻塞(blocked)
                           |                          |
                           |←←←←←←←←←←←←←←←←←←←←←←←←←
                                              wait/sleep/IO

异常处理选择

场景 处理方式
方法内可处理 try-catch
方法内无法处理 throws
必须执行清理 finally / try-with-resources
参数校验失败 throw

笔记整理完成,建议按Day顺序学习,每天配合代码练习加深理解。

相关推荐
靠沿1 分钟前
MySQL数据库基础——事务
java·数据库·mysql
秋秋小事1 分钟前
python 数据契约层FastAPI+Pydantic(一)
python
AIFQuant1 分钟前
Python港股实时行情API接入:恒生股票数据获取与AH股溢价监控实战
开发语言·数据库·python·金融·实时数据api
朝阳资本论8 分钟前
小马智行杀入伦敦牵手Uber,中国Robotaxi出海怎么打?
python
外收内放12 分钟前
Python基础语法练习题(70)
开发语言·python
老唐77712 分钟前
Agent 开发入门教程:从零搭建一个 Python AI Agent
人工智能·python·深度学习·langchain·大模型·agent·智能体
学linux的QQ蛋28 分钟前
sys文件系统与misc文件系统学习小总结
linux·学习·驱动
宿州派大星3 小时前
Python实战:PyQt5 + OpenCV + Dlib 打造AI桌面应用
人工智能·python·qt
承渊政道4 小时前
【从零开始大模型开发与微调:基于PyTorch与ChatGLM】(开源大模型ChatGLM高级定制化应用实战)
人工智能·pytorch·python·llm·模型微调·glm
Joy T6 小时前
Agent 确定性上下文设计:从 Prompt 参数注入到能力分层
java·开发语言·微服务·架构·prompt·agent context