跳到正文
Joeplover
学习笔记·2026-06-21·约 10 分钟阅读

Java 学习笔记(完整整合版)

从线程基础到 Spring 容器:涵盖 Day1~12 的 Java 核心技术笔记,含完整代码示例。

Java 学习笔记

Java 学习笔记(完整整合版)

来源:[[JAVA面试题]] 相关主题:[[设计模式]] | [[网络基础]]


Day1 — 线程基础

线程创建的 3 种方式

方式适用场景
继承 Thread简单,但 Java 单继承限制,不推荐
实现 Runnable无返回值,推荐
实现 Callable + FutureTask需要返回值
// 1. 继承 Thread
Thread t1 = new Thread("线程名") {
    @Override
    public void run() { /* 逻辑 */ }
};
t1.start();

// 2. Runnable(lambda)
Thread t2 = new Thread(() -> System.out.println("run"), "线程名");
t2.start();

// 3. Callable + FutureTask(有返回值)
Callable<String> task = () -> "结果";
FutureTask<String> ft = new FutureTask<>(task);
new Thread(ft).start();
String result = ft.get();  // 阻塞等待结果

线程 6 种状态

NEW → RUNNABLE → WAITING / TIMED_WAITING / BLOCKED → TERMINATED

start() vs run()

  • start():启动新线程,JVM 自动调用 run()
  • run():普通方法调用,不启动新线程,在当前线程执行

sleep() / yield() / join()

方法效果
sleep(ms)当前线程休眠,不释放锁
yield()让出 CPU,但依然可被调度
join()等待子线程执行完再继续

交替打印 1-100 的两种方案

方案1:wait/notify

synchronized (lock) {
    while (条件不满足) lock.wait();
    // 执行
    lock.notify();
}

方案2:Lock + Condition

Lock lock = new ReentrantLock();
Condition cond = lock.newCondition();
lock.lock();
try {
    while (条件不满足) cond.await();
    // 执行
    cond.signal();
} finally { lock.unlock(); }

Day2 — synchronized 底层

锁的是什么?

  • 对象锁:synchronized(obj) 或 synchronized 修饰实例方法
  • 类锁:synchronized(XX.class) 或 synchronized 修饰静态方法
  • 对象锁和类锁互不干扰

锁升级过程(JDK 1.6+)

无锁 → 偏向锁 → 轻量级锁(自旋) → 重量级锁(OS 互斥)
  • 低竞争:偏向锁/轻量级锁,性能很好
  • 高竞争:升级为重量级锁,线程阻塞,上下文切换开销大

可重入

同一线程可以重复进入同一个锁:

synchronized void a() { b(); }     // 可以
synchronized void b() { /* ... */ } // 同一线程再进来不会死锁

synchronized vs 代码块

// 方法锁:粒度粗
synchronized void method() { /* 整个方法 */ }

// 代码块锁:粒度细,只锁"真正需要保护的部分"
void method() {
    // 非临界区
    synchronized (this) { /* 只锁这里 */ }
}

标准对比:不加锁 → 加锁

// 不加锁:20个线程各加1万次,结果 < 20万
class UnsafeCounter {
    int count;
    void increment() { count++; }  // 非原子操作!
}

// 加锁:结果 = 20万
class SafeCounter {
    int count;
    synchronized void increment() { count++; }
}

Day3 — Lock + AQS + Socket

ReentrantLock

Lock lock = new ReentrantLock();       // 非公平锁(默认)
Lock lock = new ReentrantLock(true);   // 公平锁

lock.lock();
try {
    // 临界区
} finally {
    lock.unlock(); // 一定要在 finally 里释放!
}

AQS(AbstractQueuedSynchronizer)核心

AQS = state(状态) + CLH 队列(等待线程) + CAS(原子操作)

state = 0:锁空闲
state = 1:锁被占用
state > 1:可重入计数
  • ReentrantLock、Semaphore、CountDownLatch、ThreadPoolExecutor 都基于 AQS

Socket 通信(TCP)

服务端:

ServerSocket server = new ServerSocket(8888);
Socket client = server.accept();  // 阻塞等待客户端连接
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
PrintWriter out = new PrintWriter(client.getOutputStream(), true);

客户端:

Socket socket = new Socket("localhost", 8888);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

Day4 — volatile

volatile 做了什么

  • 保证可见性:一个线程修改,其他线程立即看到
  • 防止指令重排序:禁止编译器和 CPU 重排
  • 不保证原子性:count++ 仍然不安全

典型用途

// 1. 线程停止标志
volatile boolean running = true;
// 线程里 while (running) { ... }

// 2. DCL 单例
class Singleton {
    private static volatile Singleton instance;
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();  // 必须 volatile 防止指令重排
                }
            }
        }
        return instance;
    }
}

volatile vs synchronized

volatilesynchronized
可见性✅✅
原子性❌✅
禁止重排✅✅
性能轻量较重

Day5 — 卡牌游戏项目(Swing)

一个完整的 Java Swing 卡牌战斗游戏,技术覆盖:

技术点体现在哪
反射+注解自动扫描卡牌处理器 @CardHandler、事件监听器
集合框架CardDeck、Inventory、BattleLogDeque、Room 映射
多线程AI 异步决策、AsyncBattleLogger、WaveSpawnScheduler
SocketGameSocketServer 房间服务原型
JDBCSQLite + HikariCP 连接池持久化
分层架构BattleSession(状态机)→ SwingGameController(编排)→ SwingGameFrame(UI)
事件总线EventBus + EventListener + @GameEventListener

运行方式:

mvn compile
mvn exec:java -Dexec.mainClass=com.example.day5.game.bootstrap.GameApplication

项目结构:

game/
├── ai/strategy/       — AI 策略(策略模式)
├── bootstrap/         — 启动入口
├── card/              — 卡牌(handler 策略模式 + 注解注册)
├── combat/system/     — 战斗系统
├── common/enums/      — 枚举
├── concurrent/        — 异步日志、定时调度、房间管理
├── config/            — 配置加载
├── core/              — 核心引擎(session 状态机、tick 调度、指令处理)
├── entity/            — 实体(player、monster)
├── event/bus/         — 事件总线(观察者模式)
├── inventory/         — 背包
├── network/           — Socket 服务端 + 协议解析
├── persistence/       — JDBC + SQLite 持久化
└── ui/swing/          — Swing 界面

Day6 — Java 基础全系列(24个主题)

建议学习顺序

basics → arrays → methods_overloading → oop_encapsulation →
inheritance_polymorphism → abstract_class → interface_demo →
enum_demo → string_demo → common_classes → datetime_demo →
collections_list → map_set → generics_demo → lambda_stream →
exception_handling → io_stream → nio_files → multithreading_basic →
lock_synchronized → juc_threadpool → juc_collections →
annotation_demo → reflection_demo

核心代码示例

Lambda + Stream:

List<String> topics = List.of("java", "io", "thread", "juc", "lock");
long count = topics.stream()
        .filter(t -> t.length() >= 3)
        .map(String::toUpperCase)
        .peek(System.out::println)
        .count();

反射(3 步:类 → 构造器 → 方法):

Class<UserProfile> clazz = UserProfile.class;
Constructor<UserProfile> c = clazz.getConstructor(String.class);
UserProfile obj = c.newInstance("Java");
Method method = clazz.getMethod("greeting");
method.invoke(obj);

枚举:

enum Status {
    PENDING("待处理"), DONE("已完成");
    final String label;
    Status(String label) { this.label = label; }
}

泛型:

// 泛型类
class Box<T> { T value; }

// 泛型方法
<T> T get(T arg) { return arg; }

// 通配符
void print(List<? extends Number> list) { ... }

Day7 — IO 深度

字节流 vs 字符流

字节流字符流
基类InputStream / OutputStreamReader / Writer
处理所有文件(图片、视频)文本文件
编码不关心需要指定 charset

流装饰器模式

// 一层层包装,每层加点功能
BufferedReader br = new BufferedReader(
    new InputStreamReader(
        new FileInputStream("file.txt"), StandardCharsets.UTF_8
    )
);

关键流一览

类作用
FileInputStream/FileOutputStream文件字节流
FileReader/FileWriter文件字符流
BufferedInputStream/BufferedOutputStream带缓冲,提高性能
BufferedReader/BufferedWriter带缓冲字符流,支持 readLine()
DataInputStream/DataOutputStream读写 Java 基本类型
ObjectInputStream/ObjectOutputStream对象序列化
InputStreamReader/OutputStreamWriter字节↔字符转换桥

序列化

class MyObj implements Serializable {
    private static final long serialVersionUID = 1L;
    private transient String secret;  // transient 不序列化
}

Day8 — 递归

// 经典:阶乘
int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

// 一定要有终止条件,否则栈溢出

Day9 — 模拟 Spring / 手写 IOC 容器

核心思路:用反射创建对象 + Map 存单例

public class SpringDemo {
    HashMap<String, Object> beanMap = new HashMap<>();

    @SuppressWarnings("unchecked")
    public <T> T getInstance(String className, Class<T> type) throws Exception {
        if (beanMap.containsKey(className)) {
            return (T) beanMap.get(className);  // 单例:已有直接返回
        }
        Class<?> clazz = Class.forName(className);
        Object instance = clazz.getDeclaredConstructor().newInstance();
        beanMap.put(className, instance);       // 放入容器
        return (T) instance;
    }
}

// 使用
SpringDemo container = new SpringDemo();
User user = container.getInstance("com.example.User", User.class);

核心三要素:

  1. Class.forName() 加载类
  2. clazz.getDeclaredConstructor().newInstance() 反射创建
  3. Map 存对象实现单例

Day10 — 深浅拷贝

引用拷贝 vs 浅拷贝 vs 深拷贝

引用拷贝:b = a           → 同一个对象,两个引用
浅拷贝:  b = a.clone()   → 新对象,但内部引用指向同一个
深拷贝:  手动拷贝内部属性  → 从外到内全部独立

代码验证

// 浅拷贝:内部 Address 还是同一个
class Student implements Cloneable {
    Address address;
    @Override
    protected Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();  // 默认浅拷贝
    }
}

// 结果:stu1.address == stu2.address  → true
// 改 stu1 的 address,stu2 的也跟着变

深拷贝实现:

@Override
protected Student clone() throws CloneNotSupportedException {
    Student s = (Student) super.clone();
    s.address = this.address.clone();  // 手动拷贝内部引用
    return s;
}

注意

class Video implements Cloneable {
    String videoName;    // String 不可变,不用担心
    Audio audio;         // 自定义对象,浅拷贝会共享!
}

Day11 — 代理模式 + 序列化

静态代理(手写装饰)

interface Calculator { int add(); }

class RealCalc implements Calculator {
    public int add(int a, int b) { return a + b; }
}

class ProxyCalc implements Calculator {
    RealCalc target;
    // 在 target.add() 前后做增强
    public int add(int a, int b) {
        System.out.println("before");
        int result = target.add(a, b);
        System.out.println("after");
        return result;
    }
}

JDK 动态代理

// 1. 接口 + 实现类
interface SmsService { String send(String msg); }
class SmsServiceImpl implements SmsService { ... }

// 2. InvocationHandler
class DebugInvocationHandler implements InvocationHandler {
    Object target;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        System.out.println("before " + method.getName());
        return method.invoke(target, args);
    }
}

// 3. 工厂
class JdkProxyFactory {
    public static Object getProxy(Object target) {
        return Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new DebugInvocationHandler(target)
        );
    }
}

// 4. 使用
SmsService proxy = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl());
proxy.send("hello");  // before send → hello

序列化要点

class Request implements Serializable {
    private static final long serialVersionUID = 1L;  // 版本标识
    private transient String secret;  // transient 不序列化(如密码)
    private String methodName;
    private Object[] parameters;
}

Day12 — Spring Demo + JDK Proxy 整合

Spring 的 IoC 核心就是上面 Day9 的增强版:

  • ClassPathXmlApplicationContext 读取 XML 配置
  • getBean("id") 获取对象
  • 底层就是反射 + Map 管理
// Spring 6 使用
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
User user = (User) ctx.getBean("user");
user.add();

SpringFirst — Spring 6 入门

pom.xml 关键依赖:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>6.1.4</version>
</dependency>

XML 配置 bean.xml:

<bean id="user" class="com.joe.spring6.User" />

获取:

ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");
User user = ctx.getBean("user", User.class);

ZooKeeper — 服务发现

两种实现方式:

方案1:手动实现

注册:创建 /services/xxx/instance_xxx 临时节点(节点数据 = IP:port)
发现:获取 /services/xxx 下的所有子节点
心跳:临时节点断开连接自动消失

方案2:Curator 框架

// 注册
ServiceDiscovery<ServiceEndpoint> discovery = ServiceDiscoveryBuilder
    .builder(ServiceEndpoint.class)
    .client(client).basePath("/services")
    .serializer(new JacksonInstanceSerializer<>(...))
    .build();
discovery.registerService(serviceInstance);

// 发现
Collection<ServiceInstance<ServiceEndpoint>> instances =
    discovery.queryForInstances("serviceName");

核心模型:

class ServiceEndpoint {
    String host;
    int port;
    Map<String, Object> metadata;
}