Ⅰ. 基础篇——语言本身与核心 API
一、导语
JAVA体系专栏,帮您从头开始梳理知识点,方便新手串联有价值的学习,老手按需复习。让我们体验一下打怪升级般的学习吧。好了,废话不多说。做好了开始发车喽!
1、IO 与 NIO
java.io:
字节流:/
InputStream。字符流:
OutputStream/
Reader。序列化:
Writer 接口。
Serializable
java.nio:
:数据容器。
Buffer:双向数据传输。
Channel:多路复用 I/O。
Selector
NIO.2(Java 7+):、
Path、
Files。
AsynchronousFileChannel
练习:
使用 /
FileInputStream 复制大文件。基于
FileOutputStream 和
Selector 实现简单聊天室。
SocketChannel
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
public class FileCopy {
public static void main(String[] args) {
String sourcePath = "source.txt";
String targetPath = "target.txt";
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourcePath));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetPath))) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
}
System.out.println("文件复制完成。");
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class ChatServer {
private Selector selector;
private ServerSocketChannel serverChannel;
private static final int PORT = 8080;
public ChatServer() throws IOException {
selector = Selector.open();
serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(PORT));
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务器已启动,监听端口:" + PORT);
}
public void run() throws IOException {
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
accept(key);
} else if (key.isReadable()) {
read(key);
}
keyIterator.remove();
}
}
}
private void accept(SelectionKey key) throws IOException {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
System.out.println("新客户端连接:" + sc.getRemoteAddress());
}
private void read(SelectionKey key) throws IOException {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = sc.read(buffer);
if (bytesRead == -1) {
sc.close();
System.out.println("客户端断开连接:" + sc.getRemoteAddress());
return;
}
buffer.flip();
byte[] data = new byte[bytesRead];
buffer.get(data);
String message = new String(data);
System.out.println("收到消息:" + message);
broadcast(message, sc);
}
private void broadcast(String message, SocketChannel sender) throws IOException {
for (SelectionKey key : selector.keys()) {
if (key.channel() instanceof SocketChannel && key.channel() != sender) {
SocketChannel receiver = (SocketChannel) key.channel();
receiver.write(ByteBuffer.wrap(message.getBytes()));
}
}
}
public static void main(String[] args) throws IOException {
ChatServer server = new ChatServer();
server.run();
}
}
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Scanner;
public class ChatClient {
private SocketChannel socketChannel;
private static final String SERVER_ADDRESS = "localhost";
private static final int PORT = 8080;
public ChatClient() throws IOException {
socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress(SERVER_ADDRESS, PORT));
System.out.println("已连接到服务器:" + SERVER_ADDRESS + ":" + PORT);
}
public void start() throws IOException {
Thread receiveThread = new Thread(() -> {
try {
while (true) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
int bytesRead = socketChannel.read(buffer);
if (bytesRead == -1) {
break;
}
buffer.flip();
byte[] data = new byte[bytesRead];
buffer.get(data);
String message = new String(data);
System.out.println("收到消息:" + message);
}
} catch (IOException e) {
e.printStackTrace();
}
});
receiveThread.start();
Scanner scanner = new Scanner(System.in);
while (true) {
String message = scanner.nextLine();
if (message.equalsIgnoreCase("exit")) {
break;
}
socketChannel.write(ByteBuffer.wrap(message.getBytes()));
}
socketChannel.close();
}
public static void main(String[] args) throws IOException {
ChatClient client = new ChatClient();
client.start();
}
}
2、 多线程 & 并发
线程创建:继承 或实现
Thread/
Runnable。线程池:
Callable(如
ExecutorService)管理线程生命周期。同步机制:
ThreadPoolExecutor
关键字(方法、代码块)。
synchronized 接口(
Lock、
ReentrantLock)。
ReadWriteLock
线程安全:
保证可见性。
volatile 等原子类。
AtomicInteger 线程局部变量。
ThreadLocal
并发工具:
:等待多个任务完成。
CountDownLatch:多个线程相互等待。
CyclicBarrier:控制并发访问数。
Semaphore
练习:使用 实现并行网页爬虫,统计各页面关键词频率。
ExecutorService
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
public class WebCrawler {
private static final String[] URLs = {
"https://example.com",
"https://test.com",
"https://demo.com"
};
private static final String[] KEYWORDS = {"Java", "Python", "C++"};
private static final int TIMEOUT = 5; // 秒
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
try {
CompletableFuture<?>[] futures = new CompletableFuture[URLS.length];
for (int i = 0; i < URLs.length; i++) {
final int index = i;
futures[index] = CompletableFuture.supplyAsync(() -> {
try {
String content = fetchContent(URLS[index]);
return countKeywords(content);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}, executor);
}
CompletableFuture.allOf(futures).join();
System.out.println("所有任务完成。");
printResults(futures);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
executor.shutdown();
try {
if (!executor.awaitTermination(TIMEOUT, TimeUnit.SECONDS)) {
System.out.println("线程池未在指定时间内关闭。");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private static String fetchContent(String url) throws IOException, InterruptedException, TimeoutException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.ofSeconds(TIMEOUT))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
return response.body();
}
private static String countKeywords(String content) {
return String.join("
",
java.util.Arrays.stream(KEYWORDS)
.map(keyword -> keyword + ": " +
content.split(keyword, -1).length - 1)
.collect(Collectors.toList()));
}
private static void printResults(CompletableFuture<?>[] futures) {
for (CompletableFuture<?> future : futures) {
try {
Object result = future.get();
if (result != null) {
System.out.println(result);
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
}
3、 JVM 基础
内存结构:
堆:对象实例。栈:局部变量、方法调用。方法区:类信息、常量池。直接内存:NIO 使用的堆外内存。
垃圾回收:
算法:标记‑清除、复制、标记‑整理。收集器:Serial、Parallel、CMS、G1、ZGC。
类加载:加载 → 验证 → 准备 → 解析 → 初始化。诊断工具:(线程栈)、
jstack(内存快照)、
jmap(GC 统计)、VisualVM。
jstat
练习:设置 启动程序,通过
-Xmx256m -Xms128m 观察 GC 活动。
jstat -gc <pid>
4、 注解 & 反射
注解:
元注解:、
@Target、
@Retention、
@Documented。自定义注解:定义并编写处理器(编译时或运行时)。
@Inherited
反射:
、
Class、
Method、
Field 等反射 API。动态代理:
Constructor 创建接口代理。
Proxy.newProxyInstance
练习:定义 注解,通过反射在方法执行前后输出耗时。
@LogExecutionTime
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LogExecutionTime {
String value() default "";
}
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.util.Date;
@Aspect
@Component
public class LogExecutionTimeAspect {
@Around("@annotation(LogExecutionTime)")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object result = joinPoint.proceed();
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
String methodName = joinPoint.getSignature().getName();
String className = joinPoint.getTarget().getClass().getSimpleName();
String annotationValue = getAnnotationValue(joinPoint);
System.out.println(String.format(
"方法 %s.%s 执行时间: %d ms%s",
className,
methodName,
duration,
annotationValue.isEmpty() ? "" : " (" + annotationValue + ")"
));
return result;
}
private String getAnnotationValue(ProceedingJoinPoint joinPoint) {
LogExecutionTime annotation = joinPoint.getTarget().getClass()
.getMethod(joinPoint.getSignature().getName(), joinPoint.getArgumentTypes())
.getAnnotation(LogExecutionTime.class);
return annotation != null ? annotation.value() : "";
}
}
import org.springframework.stereotype.Service;
@Service
public class ExampleService {
@LogExecutionTime("示例方法")
public void exampleMethod() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
5、 模块化(Java 9+)
模块描述: 中声明
module-info.java(依赖)、
requires(导出包)。服务加载:
exports 和
provides ... with 声明服务。迁移:将传统 JAR 转为模块,解决依赖冲突。
uses
练习:创建 、
core、
service 三个模块,
web 依赖
web,
service 依赖
service。
core
二、结语
这是一个JAVA体系的系列专栏,下期继续更新Ⅱ. 进阶篇——企业级开发基础,有需要的可以关注一下。前期的体系只是大框架,后续会慢慢补充详细的!