Java 学习笔记(完整整合版)
从线程基础到 Spring 容器:涵盖 Day1~12 的 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
| volatile | synchronized | |
|---|---|---|
| 可见性 | ✅ | ✅ |
| 原子性 | ❌ | ✅ |
| 禁止重排 | ✅ | ✅ |
| 性能 | 轻量 | 较重 |
Day5 — 卡牌游戏项目(Swing)
一个完整的 Java Swing 卡牌战斗游戏,技术覆盖:
| 技术点 | 体现在哪 |
|---|---|
| 反射+注解 | 自动扫描卡牌处理器 @CardHandler、事件监听器 |
| 集合框架 | CardDeck、Inventory、BattleLogDeque、Room 映射 |
| 多线程 | AI 异步决策、AsyncBattleLogger、WaveSpawnScheduler |
| Socket | GameSocketServer 房间服务原型 |
| JDBC | SQLite + 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 / OutputStream | Reader / 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);
核心三要素:
Class.forName()加载类clazz.getDeclaredConstructor().newInstance()反射创建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;
}