外观
Java 笔记
约 5024 字大约 17 分钟
2025-08-16
一、Java 基础知识
1.1 变量、常量和数据类型
变量
- 变量用于存储信息,可以在程序中使用
- 命名规则:
- 由大小写字母、数字、下划线(
_)和美元符号($)组成 - 不能以数字开头
- 不能包含空格、
@、#、+、-、/等符号 - 大小写敏感,如
A和a是不同变量 - 应使用有意义的名称,达到见名知意
- 由大小写字母、数字、下划线(
public class Main {
public static void main(String[] args) {
int a = 10; // 定义变量并赋初始值
System.out.println(a); // 输出10
}
}常量
- 使用
final关键字修饰 - 值只能在定义时赋值,之后不能修改
public static void main(String[] args) {
final int a = 666; // 定义常量
// a = 777; // 错误:常量的值不允许修改
}基本数据类型
| 类型 | 描述 | 范围 | 示例 |
|---|---|---|---|
| byte | 字节型 (1字节) | -128 ~ 127 | byte b = 10; |
| short | 短整型 (2字节) | -32768 ~ 32767 | short s = 1000; |
| int | 整型 (4字节) | -2147483648 ~ 2147483647 | int i = 100000; |
| long | 长整型 (8字节) | -9223372036854775808 ~ 9223372036854775807 | long l = 100000L; |
| float | 单精度浮点型 (4字节) | 约±3.4E38 (6-7位有效数字) | float f = 3.14F; |
| double | 双精度浮点型 (8字节) | 约±1.7E308 (15位有效数字) | double d = 3.14; |
| char | 字符型 (2字节) | 0 ~ 65535 | char c = 'A'; |
| boolean | 布尔型 | true 或 false | boolean flag = true; |
类型转换:
- 隐式转换(自动):小范围类型 → 大范围类型
byte → short → int → long → float → double
- 显式转换(强制):大范围类型 → 小范围类型,可能丢失精度
int a = 10;
double b = a; // 隐式转换:int → double
double d = 10.5;
int i = (int)d; // 显式转换:double → int,结果为101.2 运算符
赋值运算符
| 运算符 | 描述 | 示例 |
|---|---|---|
| = | 简单赋值 | a = 10 |
| += | 加后赋值 | a += 1等价于a = a + 1 |
| -= | 减后赋值 | a -= 1等价于a = a - 1 |
| *= | 乘后赋值 | a *= 1等价于a = a * 1 |
| /= | 除后赋值 | a /= 1等价于a = a / 1 |
| %= | 取模后赋值 | a %= 1等价于a = a % 1 |
| ++ | 自增 | a++等价于a = a + 1 |
| -- | 自减 | a--等价于a = a - 1 |
算术运算符
| 运算符 | 描述 |
|---|---|
| + | 加法 |
| - | 减法 |
| * | 乘法 |
| / | 除法 |
| % | 取余 |
关系运算符
| 运算符 | 描述 |
|---|---|
| == | 等于 |
| != | 不等于 |
| > | 大于 |
| < | 小于 |
| >= | 大于等于 |
| <= | 小于等于 |
逻辑运算符
| 运算符 | 描述 |
|---|---|
| && | 与:两边都为true,结果才为true |
| || | 或:两边至少有一个为true,结果就为true |
| ! | 非:取反操作 |
三元运算符
条件表达式 ? 表达式1 : 表达式2如果条件为true,返回表达式1的值;否则返回表达式2的值
int a = 10;
char b = a > 5 ? 'A' : 'B'; // b的值为'A'1.3 控制流程语句
选择结构
if语句:
int score = 85;
if (score >= 90) {
System.out.println("优秀");
} else if (score >= 70) {
System.out.println("良好");
} else if (score >= 60) {
System.out.println("及格");
} else {
System.out.println("不及格");
}switch语句:
char grade = 'B';
switch (grade) {
case 'A':
System.out.println("90分以上");
break;
case 'B':
System.out.println("80-89分");
break;
case 'C':
System.out.println("70-79分");
break;
default:
System.out.println("其他分数");
}循环结构
for循环:
// 打印0-9
for (int i = 0; i < 10; i++) {
System.out.println(i);
}while循环:
int i = 0;
while (i < 10) {
System.out.println(i);
i++;
}do-while循环:
int i = 0;
do {
System.out.println(i);
i++;
} while (i < 10);控制关键字:
break:立即跳出整个循环continue:跳过当前循环,进入下一次循环
1.4 方法
方法定义:
// 返回两个整数的和
int sum(int a, int b) {
return a + b;
}方法调用:
public static void main(String[] args) {
int result = sum(5, 3); // 调用方法
System.out.println(result); // 输出8
}方法重载:
- 同一个类中可以有多个同名方法,但参数列表必须不同
int sum(int a, int b) {
return a + b;
}
double sum(double a, double b) {
return a + b;
}二、Java 面向对象编程
2.1 类和对象
类的定义
public class Person {
// 属性(成员变量)
String name;
int age;
String sex;
// 方法
void hello() {
System.out.println("我叫 " + name + " 今年 " + age + " 岁了!");
}
// 构造方法
public Person(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
}对象创建与使用
public static void main(String[] args) {
// 创建Person对象
Person p = new Person("小明", 18, "男");
// 访问对象属性
p.name = "小明";
p.age = 18;
// 调用对象方法
p.hello();
}this关键字
- 指向当前对象的引用
- 用于区分成员变量和局部变量
void setName(String name) {
this.name = name; // this.name表示成员变量,name表示参数
}2.2 封装、继承和多态
封装
- 将数据和行为包装在一起,隐藏实现细节
- 通常将成员变量设为
private,提供公共的getter/setter方法
public class Person {
private String name;
private int age;
// getter和setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}继承
- 使用
extends关键字 - 子类继承父类的非私有成员
// 父类
public class Person {
protected String name;
protected int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void hello() {
System.out.println("我叫 " + name + ",今年 " + age + "岁");
}
}
// 子类
public class Student extends Person {
private String studentId;
public Student(String name, int age, String studentId) {
super(name, age); // 调用父类构造方法
this.studentId = studentId;
}
public void study() {
System.out.println("我正在学习,学号是 " + studentId);
}
}多态
- 同一操作作用于不同对象,可以有不同的解释,产生不同的执行结果
- 通过方法重写实现
// 父类
public class Animal {
public void sound() {
System.out.println("动物发出声音");
}
}
// 子类
public class Dog extends Animal {
@Override
public void sound() {
System.out.println("汪汪汪");
}
}
public class Cat extends Animal {
@Override
public void sound() {
System.out.println("喵喵喵");
}
}
// 测试
public static void main(String[] args) {
Animal myDog = new Dog();
Animal myCat = new Cat();
myDog.sound(); // 输出:汪汪汪
myCat.sound(); // 输出:喵喵喵
}2.3 抽象类和接口
抽象类
- 使用
abstract关键字定义 - 可以包含抽象方法(只有声明,没有实现)
- 不能直接实例化,必须由子类继承并实现抽象方法
public abstract class Shape {
protected String color;
public Shape(String color) {
this.color = color;
}
// 抽象方法
public abstract double area();
// 普通方法
public void displayColor() {
System.out.println("颜色: " + color);
}
}
public class Circle extends Shape {
private double radius;
public Circle(String color, double radius) {
super(color);
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}接口
- 使用
interface关键字定义 - 只能包含抽象方法(Java 8+可以有default方法)
- 类可以实现多个接口
// 接口
public interface Drawable {
void draw();
// Java 8+的default方法
default void display() {
System.out.println("显示图形");
}
}
public interface Resizable {
void resize(double factor);
}
// 实现多个接口
public class Rectangle implements Drawable, Resizable {
private double width;
private double height;
public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}
@Override
public void draw() {
System.out.println("绘制矩形");
}
@Override
public void resize(double factor) {
width *= factor;
height *= factor;
}
}三、Java 常用进阶知识
3.1 字符串
String str1 = "Hello";
String str2 = new String("World");
// 常用方法
String str3 = str1 + " " + str2; // 字符串连接
int length = str3.length(); // 获取长度
char c = str3.charAt(0); // 获取指定位置字符
String lower = str3.toLowerCase(); // 转小写
String upper = str3.toUpperCase(); // 转大写
boolean equals = str1.equals(str2); // 比较内容是否相等
int index = str3.indexOf("World"); // 查找子字符串
String sub = str3.substring(6); // 截取子字符串
String[] parts = str3.split(" "); // 分割字符串3.2 数组
// 一维数组
int[] numbers = new int[5]; // 创建长度为5的整型数组
numbers[0] = 10; // 赋值
int first = numbers[0]; // 取值
// 初始化数组
int[] nums = {1, 2, 3, 4, 5};
// 遍历数组
for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]);
}
// 增强for循环
for (int num : nums) {
System.out.println(num);
}
// 二维数组
int[][] matrix = new int[3][3];
matrix[0][0] = 1;3.3 异常处理
try {
// 可能抛出异常的代码
int result = 10 / 0;
} catch (ArithmeticException e) {
// 处理特定异常
System.out.println("发生算术异常: " + e.getMessage());
} catch (Exception e) {
// 处理其他异常
System.out.println("发生异常: " + e.getMessage());
} finally {
// 无论是否发生异常都会执行
System.out.println("执行finally块");
}
// 抛出异常
public void checkAge(int age) throws IllegalArgumentException {
if (age < 0) {
throw new IllegalArgumentException("年龄不能为负数");
}
}3.4 Java 集合框架
List(有序可重复)
import java.util.ArrayList;
import java.util.List;
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
// 访问元素
String first = list.get(0);
// 遍历
for (String item : list) {
System.out.println(item);
}
// 移除元素
list.remove("Banana");Set(无序不可重复)
import java.util.HashSet;
import java.util.Set;
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Apple"); // 重复元素不会被添加
// 检查元素是否存在
boolean contains = set.contains("Apple");Map(键值对)
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 1);
map.put("Banana", 2);
map.put("Orange", 3);
// 获取值
int appleCount = map.get("Apple");
// 遍历
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}3.5 泛型
// 泛型类
public class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
// 使用泛型
Box<String> stringBox = new Box<>();
stringBox.setContent("Hello");
String content = stringBox.getContent();
// 泛型方法
public <T> void printArray(T[] array) {
for (T item : array) {
System.out.println(item);
}
}3.6 Lambda表达式(Java 8+)
// 传统匿名内部类
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello World");
}
};
// Lambda表达式
Runnable r2 = () -> System.out.println("Hello World");
// 带参数的Lambda
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println(name));
// 多行Lambda
names.forEach(name -> {
String greeting = "Hello, " + name;
System.out.println(greeting);
});3.7 Stream API(Java 8+)
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 过滤和转换
List<String> filtered = names.stream()
.filter(name -> name.startsWith("A")) // 过滤以A开头的名字
.map(String::toUpperCase) // 转换为大写
.collect(Collectors.toList()); // 收集结果
// 求和
int sum = numbers.stream()
.mapToInt(Integer::intValue)
.sum();
// 分组
Map<Integer, List<String>> grouped = names.stream()
.collect(Collectors.groupingBy(String::length));四、Java I/O 基础
4.1 文件读写
import java.io.*;
import java.nio.file.*;
// 写入文件
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get("output.txt"))) {
writer.write("Hello World");
}
// 读取文件
try (BufferedReader reader = Files.newBufferedReader(Paths.get("input.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
// 读取整个文件
String content = new String(Files.readAllBytes(Paths.get("input.txt")));4.2 序列化
import java.io.*;
// 可序列化的类
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
// 构造方法、getter和setter
}
// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.dat"))) {
Person person = new Person("Alice", 30);
oos.writeObject(person);
}
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.dat"))) {
Person person = (Person) ois.readObject();
System.out.println(person.getName() + ", " + person.getAge());
}五、多线程基础
5.1 创建线程
// 方法一:继承Thread类
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程运行中...");
}
}
// 方法二:实现Runnable接口
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程运行中...");
}
}
// 使用
public static void main(String[] args) {
// 方法一
MyThread thread1 = new MyThread();
thread1.start();
// 方法二
Thread thread2 = new Thread(new MyRunnable());
thread2.start();
// Lambda表达式
new Thread(() -> System.out.println("Lambda线程")).start();
}5.2 线程同步
class Counter {
private int count = 0;
// 同步方法
public synchronized void increment() {
count++;
}
// 同步代码块
public void decrement() {
synchronized (this) {
count--;
}
}
public int getCount() {
return count;
}
}5.3 线程池
import java.util.concurrent.*;
public static void main(String[] args) {
// 创建固定大小的线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
// 提交任务
for (int i = 0; i < 10; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("任务 " + taskId + " 正在执行,线程: " + Thread.currentThread().getName());
});
}
// 关闭线程池
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}三、Java 常用进阶知识
3.1 字符串
String str1 = "Hello";
String str2 = new String("World");
// 常用方法
String str3 = str1 + " " + str2; // 字符串连接
int length = str3.length(); // 获取长度
char c = str3.charAt(0); // 获取指定位置字符
String lower = str3.toLowerCase(); // 转小写
String upper = str3.toUpperCase(); // 转大写
boolean equals = str1.equals(str2); // 比较内容是否相等
int index = str3.indexOf("World"); // 查找子字符串
String sub = str3.substring(6); // 截取子字符串
String[] parts = str3.split(" "); // 分割字符串字符串常量池:
- 直接使用双引号创建的字符串会存放在字符串常量池中
new String()创建的字符串对象在堆内存中,但内容可能指向常量池
String s1 = "Java"; // 常量池
String s2 = "Java"; // 与s1指向同一个常量
String s3 = new String("Java"); // 堆内存中的新对象
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s1.equals(s3)); // trueStringBuilder/StringBuffer:
- 当需要频繁修改字符串时,使用StringBuilder(单线程)或StringBuffer(多线程)
- 比直接使用String连接效率高得多
// 字符串拼接效率比较
String result = "";
for (int i = 0; i < 10000; i++) {
result += i; // 效率极低,每次都会创建新对象
}
// 高效方式
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++) {
sb.append(i);
}
String efficientResult = sb.toString();3.2 数组
// 一维数组
int[] numbers = new int[5]; // 创建长度为5的整型数组
numbers[0] = 10; // 赋值
int first = numbers[0]; // 取值
// 初始化数组
int[] nums = {1, 2, 3, 4, 5};
// 遍历数组
for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]);
}
// 增强for循环
for (int num : nums) {
System.out.println(num);
}
// 二维数组
int[][] matrix = new int[3][3];
matrix[0][0] = 1;数组工具类Arrays:
import java.util.Arrays;
int[] arr = {5, 2, 8, 1, 3};
// 排序
Arrays.sort(arr); // [1, 2, 3, 5, 8]
// 填充
Arrays.fill(arr, 0); // 所有元素设为0
// 比较
int[] arr2 = {1, 2, 3};
boolean isEqual = Arrays.equals(arr, arr2); // false
// 转换为字符串
String str = Arrays.toString(arr); // "[1, 2, 3, 5, 8]"3.3 异常处理
try {
// 可能抛出异常的代码
int result = 10 / 0;
} catch (ArithmeticException e) {
// 处理特定异常
System.out.println("发生算术异常: " + e.getMessage());
} catch (Exception e) {
// 处理其他异常
System.out.println("发生异常: " + e.getMessage());
} finally {
// 无论是否发生异常都会执行
System.out.println("执行finally块");
}
// 抛出异常
public void checkAge(int age) throws IllegalArgumentException {
if (age < 0) {
throw new IllegalArgumentException("年龄不能为负数");
}
}常见异常类型:
NullPointerException:空指针异常(最常见)ArrayIndexOutOfBoundsException:数组越界ClassCastException:类型转换异常NumberFormatException:数字格式异常IOException:IO操作异常
自定义异常:
// 创建自定义异常类
class MyException extends Exception {
public MyException(String message) {
super(message);
}
}
// 使用自定义异常
public void validate(int value) throws MyException {
if (value < 0) {
throw new MyException("值不能为负数");
}
}3.4 Java 集合框架
List(有序可重复)
import java.util.ArrayList;
import java.util.List;
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Banana");
list.add("Orange");
// 访问元素
String first = list.get(0);
// 遍历
for (String item : list) {
System.out.println(item);
}
// 移除元素
list.remove("Banana");Set(无序不可重复)
import java.util.HashSet;
import java.util.Set;
Set<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
set.add("Apple"); // 重复元素不会被添加
// 检查元素是否存在
boolean contains = set.contains("Apple");Map(键值对)
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> map = new HashMap<>();
map.put("Apple", 1);
map.put("Banana", 2);
map.put("Orange", 3);
// 获取值
int appleCount = map.get("Apple");
// 遍历
for (Map.Entry<String, Integer> entry : map.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}集合选择指南:
- 需要有序列表 → ArrayList
- 需要快速插入/删除 → LinkedList
- 需要唯一元素 → HashSet
- 需要排序的唯一元素 → TreeSet
- 需要键值对 → HashMap
- 需要排序的键值对 → TreeMap
3.5 泛型
// 泛型类
public class Box<T> {
private T content;
public void setContent(T content) {
this.content = content;
}
public T getContent() {
return content;
}
}
// 使用泛型
Box<String> stringBox = new Box<>();
stringBox.setContent("Hello");
String content = stringBox.getContent();
// 泛型方法
public <T> void printArray(T[] array) {
for (T item : array) {
System.out.println(item);
}
}泛型的好处:
- 类型安全:在编译期检查类型
- 消除强制类型转换
- 代码重用
泛型边界:
// 上界:T必须是Number或其子类
public <T extends Number> double sum(T[] numbers) {
double total = 0.0;
for (T num : numbers) {
total += num.doubleValue();
}
return total;
}
// 通配符
void processList(List<? extends Number> list) {
// 可以读取Number类型
for (Number n : list) {
System.out.println(n);
}
// 不能添加元素(除了null)
}3.6 Lambda表达式(Java 8+)
// 传统匿名内部类
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello World");
}
};
// Lambda表达式
Runnable r2 = () -> System.out.println("Hello World");
// 带参数的Lambda
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println(name));
// 多行Lambda
names.forEach(name -> {
String greeting = "Hello, " + name;
System.out.println(greeting);
});函数式接口:
- 只包含一个抽象方法的接口
- 常用函数式接口:
Predicate<T>:断言,测试条件Function<T, R>:函数,转换操作Consumer<T>:消费者,执行操作Supplier<T>:供应者,提供值
// Predicate示例
List<String> filtered = names.stream()
.filter(name -> name.length() > 4)
.collect(Collectors.toList());
// Function示例
List<Integer> lengths = names.stream()
.map(String::length)
.collect(Collectors.toList());
// Consumer示例
names.forEach(name -> System.out.println("Name: " + name));
// Supplier示例
Supplier<Double> randomSupplier = () -> Math.random();
System.out.println(randomSupplier.get());3.7 Stream API(Java 8+)
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// 过滤和转换
List<String> filtered = names.stream()
.filter(name -> name.startsWith("A")) // 过滤以A开头的名字
.map(String::toUpperCase) // 转换为大写
.collect(Collectors.toList()); // 收集结果
// 求和
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.mapToInt(Integer::intValue)
.sum();
// 分组
Map<Integer, List<String>> grouped = names.stream()
.collect(Collectors.groupingBy(String::length));Stream常用操作:
filter():过滤元素map():转换元素sorted():排序distinct():去重limit():限制数量skip():跳过元素forEach():遍历collect():收集结果count():计数anyMatch()/allMatch()/noneMatch():匹配检查
3.8 常用注解
// 重写父类方法
@Override
public String toString() {
return "Custom object";
}
// 标记已过时
@Deprecated
public void oldMethod() {
// ...
}
// 抑制编译器警告
@SuppressWarnings("unchecked")
public void uncheckedMethod() {
// ...
}自定义注解:
// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
int priority() default 1;
String description() default "";
}
// 使用注解
@Test(priority = 2, description = "测试方法")
public void testMethod() {
// ...
}四、Java I/O 基础
4.1 文件读写
import java.io.*;
import java.nio.file.*;
// 写入文件
try (BufferedWriter writer = Files.newBufferedWriter(Paths.get("output.txt"))) {
writer.write("Hello World");
}
// 读取文件
try (BufferedReader reader = Files.newBufferedReader(Paths.get("input.txt"))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
// 读取整个文件
String content = new String(Files.readAllBytes(Paths.get("input.txt")));常用I/O类:
File:文件和目录路径名的抽象表示FileInputStream/FileOutputStream:字节流BufferedReader/BufferedWriter:字符流,带缓冲PrintWriter:格式化打印
4.2 序列化
import java.io.*;
// 可序列化的类
class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// getter和setter
}
// 序列化
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.dat"))) {
Person person = new Person("Alice", 30);
oos.writeObject(person);
}
// 反序列化
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.dat"))) {
Person person = (Person) ois.readObject();
System.out.println(person.getName() + ", " + person.getAge());
}序列化注意事项:
- 必须实现
Serializable接口 - 静态变量和
transient修饰的变量不会被序列化 - 建议显式定义
serialVersionUID - 序列化可能带来安全风险,不应用于敏感数据
五、多线程基础
5.1 创建线程
// 方法一:继承Thread类
class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程运行中...");
}
}
// 方法二:实现Runnable接口
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程运行中...");
}
}
// 使用
public static void main(String[] args) {
// 方法一
MyThread thread1 = new MyThread();
thread1.start();
// 方法二
Thread thread2 = new Thread(new MyRunnable());
thread2.start();
// Lambda表达式
new Thread(() -> System.out.println("Lambda线程")).start();
}5.2 线程同步
class Counter {
private int count = 0;
// 同步方法
public synchronized void increment() {
count++;
}
// 同步代码块
public void decrement() {
synchronized (this) {
count--;
}
}
public int getCount() {
return count;
}
}常见同步问题:
- 死锁:两个或多个线程互相等待对方释放资源
- 活锁:线程不断重试但始终无法前进
- 饥饿:某些线程长期得不到执行机会
5.3 线程池
import java.util.concurrent.*;
public static void main(String[] args) {
// 创建固定大小的线程池
ExecutorService executor = Executors.newFixedThreadPool(5);
// 提交任务
for (int i = 0; i < 10; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("任务 " + taskId + " 正在执行,线程: " + Thread.currentThread().getName());
});
}
// 关闭线程池
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
}
}常用线程池类型:
newFixedThreadPool(n):固定大小线程池newCachedThreadPool():可缓存线程池,适合大量短期任务newSingleThreadExecutor():单线程执行器newScheduledThreadPool(n):定时任务线程池
线程安全集合:
// 线程安全的List
List<String> safeList = Collections.synchronizedList(new ArrayList<>());
// ConcurrentHashMap比Hashtable性能更好
Map<String, Integer> safeMap = new ConcurrentHashMap<>();六、常用设计模式
6.1 单例模式
// 饿汉式(线程安全,可能造成资源浪费)
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
// 懒汉式(双重检查锁定,线程安全且延迟初始化)
public class Singleton {
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}6.2 工厂模式
// 简单工厂
public class ShapeFactory {
public static Shape getShape(String type) {
if ("CIRCLE".equals(type)) {
return new Circle();
} else if ("RECTANGLE".equals(type)) {
return new Rectangle();
}
return null;
}
}
// 使用
Shape shape = ShapeFactory.getShape("CIRCLE");
shape.draw();6.3 观察者模式
import java.util.ArrayList;
import java.util.List;
// 被观察者
class Subject {
private List<Observer> observers = new ArrayList<>();
private int state;
public void attach(Observer observer) {
observers.add(observer);
}
public void setState(int state) {
this.state = state;
notifyAllObservers();
}
private void notifyAllObservers() {
for (Observer observer : observers) {
observer.update();
}
}
}
// 观察者
interface Observer {
void update();
}
// 具体观察者
class ConcreteObserver implements Observer {
private Subject subject;
public ConcreteObserver(Subject subject) {
this.subject = subject;
subject.attach(this);
}
@Override
public void update() {
System.out.println("状态更新: " + subject.getState());
}
}七、Java 11+ 新特性(精选)
7.1 局部变量类型推断
// 以前
List<String> list = new ArrayList<String>();
// Java 10+
var list = new ArrayList<String>(); // 编译器自动推断类型
// 适用于局部变量
var count = 10;
var name = "Java";7.2 新的字符串方法
// Java 11+
String str = " Java ";
System.out.println(str.isBlank()); // true
System.out.println(str.strip()); // "Java" (比trim()更全面)
System.out.println(str.stripLeading()); // "Java "
System.out.println(str.stripTrailing());// " Java"
// 重复字符串
String repeated = "Java".repeat(3); // "JavaJavaJava"
// 文本块(Java 15+)
String json = """
{
"name": "Java",
"version": "17"
}
""";7.3 HTTP Client(Java 11+)
import java.net.http.*;
// 同步请求
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/data"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
// 异步请求
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);