Java核心知识点深度解析:从面向对象到函数式编程

一、面向对象编程

1. 类与对象

概念解释
类是对象的模板,定义了对象的属性和行为。对象是类的实例,具有具体的状态和行为。

// 类定义
public class Person {
    // 属性(成员变量)
    private String name;
    private int age;
    
    // 方法
    public void introduce() {
        System.out.println("Hello, I'm " + name);
    }
}

// 对象创建
Person person = new Person();
person.introduce();

实践建议

  • 遵循单一职责原则,一个类只负责一个功能
  • 使用private保护成员变量,通过getter/setter访问

2. 构造方法与初始化块

public class Order {
    // 静态初始化块(类加载时执行)
    static {
        System.out.println("Static initialization block");
    }
    
    // 实例初始化块(每次new时执行)
    {
        System.out.println("Instance initialization block");
    }
    
    // 构造方法
    public Order() {
        System.out.println("Constructor");
    }
}

执行顺序:静态块 → 实例块 → 构造方法

3. 接口与抽象类

classDiagram
    class AbstractAnimal {
        <<abstract>>
        +String name
        +abstract void makeSound()
        +void sleep()
    }
    
    interface Flyable {
        <<interface>>
        +void fly()
    }
    
    class Bird {
        +void makeSound()
        +void fly()
    }
    
    AbstractAnimal <|-- Bird
    Flyable <|.. Bird

关键区别

  • 抽象类可以有实现方法,接口在Java 8前只能有抽象方法
  • 类只能单继承抽象类,但可实现多个接口
  • 接口更适合定义行为契约,抽象类适合代码复用

4. 内部类

public class Outer {
    private int x = 10;
    
    // 成员内部类
    class Inner {
        void accessOuter() {
            System.out.println(x); // 可直接访问外部类成员
        }
    }
    
    // 静态内部类
    static class StaticInner {
        void show() {
            System.out.println("Static inner");
        }
    }
    
    void method() {
        // 局部内部类
        class LocalInner {
            void display() {
                System.out.println("Local inner");
            }
        }
        
        // 匿名内部类
        Runnable r = new Runnable() {
            public void run() {
                System.out.println("Anonymous inner");
            }
        };
    }
}

使用场景

  • 匿名类:事件监听器、线程实现等一次性使用场景
  • 静态内部类:不需要访问外部类实例时,更节省内存

二、异常处理

1. 异常体系

图2

关键类型

  • Error:系统级错误(如OutOfMemoryError),不应捕获
  • RuntimeException:未检查异常(如NullPointerException)
  • 其他Exception:检查异常,必须处理

2. try-catch-finally

try {
    FileInputStream fis = new FileInputStream("file.txt");
    // 处理文件
} catch (FileNotFoundException e) {
    System.err.println("文件未找到: " + e.getMessage());
} catch (IOException e) {
    System.err.println("IO错误: " + e);
} finally {
    // 无论是否异常都会执行
    if (fis != null) {
        try {
            fis.close();
        } catch (IOException e) {
            // 关闭资源时的异常处理
        }
    }
}

最佳实践

  • 使用try-with-resources简化资源管理
  • 不要捕获Exception基类,应捕获具体异常
  • finally块中避免return语句

3. 自定义异常

public class InsufficientFundsException extends Exception {
    private double amount;
    
    public InsufficientFundsException(double amount) {
        super("资金不足,缺少: " + amount);
        this.amount = amount;
    }
    
    public double getAmount() {
        return amount;
    }
}

// 使用
void withdraw(double amount) throws InsufficientFundsException {
    if (balance < amount) {
        throw new InsufficientFundsException(amount - balance);
    }
    // 其他逻辑
}

三、集合框架

1. 核心接口与实现类

图3

选择指南

  • ArrayList:随机访问多,插入删除少
  • LinkedList:频繁插入删除,随机访问少
  • HashSet:无序唯一集合,快速查找
  • TreeSet:有序唯一集合
  • HashMap:键值对存储,快速查找
  • LinkedHashMap:保持插入顺序的HashMap

2. 迭代与泛型

List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");

// 传统迭代器
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    System.out.println(it.next());
}

// 增强for循环
for (String lang : list) {
    System.out.println(lang);
}

// Java 8 forEach
list.forEach(System.out::println);

类型擦除问题

List<String> strList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();

// 运行时都是List.class
System.out.println(strList.getClass() == intList.getClass()); // true

四、多线程与并发

1. 线程创建方式

// 继承Thread
class MyThread extends Thread {
    public void run() {
        System.out.println("Thread running");
    }
}

// 实现Runnable
class MyRunnable implements Runnable {
    public void run() {
        System.out.println("Runnable running");
    }
}

// 实现Callable
class MyCallable implements Callable<String> {
    public String call() throws Exception {
        return "Callable result";
    }
}

// 使用
new MyThread().start();
new Thread(new MyRunnable()).start();

ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(new MyCallable());
System.out.println(future.get());
executor.shutdown();

2. 线程同步机制

// synchronized方法
public synchronized void syncMethod() {
    // 临界区
}

// synchronized块
public void syncBlock() {
    synchronized(this) {
        // 临界区
    }
}

// ReentrantLock
private final Lock lock = new ReentrantLock();
public void lockMethod() {
    lock.lock();
    try {
        // 临界区
    } finally {
        lock.unlock();
    }
}

// volatile变量
private volatile boolean flag = false;

选择建议

  • synchronized:简单同步场景
  • Lock:需要尝试获取锁、超时、公平锁等高级特性
  • volatile:保证可见性但不保证原子性

3. 线程池最佳实践

// 创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
    5, // 核心线程数
    10, // 最大线程数
    60, // 空闲线程存活时间
    TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(100), // 工作队列
    new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略
);

// 提交任务
executor.execute(() -> System.out.println("Task running"));
Future<String> future = executor.submit(() -> "Result");

// 优雅关闭
executor.shutdown();
try {
    if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
        executor.shutdownNow();
    }
} catch (InterruptedException e) {
    executor.shutdownNow();
    Thread.currentThread().interrupt();
}

五、I/O与NIO

1. 传统I/O示例

// 字节流复制文件
try (InputStream in = new FileInputStream("source.txt");
     OutputStream out = new FileOutputStream("target.txt")) {
    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = in.read(buffer)) != -1) {
        out.write(buffer, 0, bytesRead);
    }
}

// 字符流读取文件
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
}

2. NIO核心组件

// 文件复制示例
try (FileChannel inChannel = FileChannel.open(Paths.get("source.txt"));
     FileChannel outChannel = FileChannel.open(Paths.get("target.txt"), 
                StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
    
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    while (inChannel.read(buffer) != -1) {
        buffer.flip(); // 切换为读模式
        outChannel.write(buffer);
        buffer.clear(); // 清空缓冲区
    }
}

// Selector多路复用
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);

while (true) {
    selector.select();
    Set<SelectionKey> keys = selector.selectedKeys();
    Iterator<SelectionKey> iter = keys.iterator();
    
    while (iter.hasNext()) {
        SelectionKey key = iter.next();
        if (key.isAcceptable()) {
            // 处理新连接
        } else if (key.isReadable()) {
            // 处理读事件
        }
        iter.remove();
    }
}

六、反射与注解

1. 反射API使用

Class<?> clazz = Class.forName("com.example.User");

// 创建实例
Object user = clazz.getDeclaredConstructor().newInstance();

// 访问字段
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true); // 突破private限制
nameField.set(user, "John");

// 调用方法
Method method = clazz.getMethod("setName", String.class);
method.invoke(user, "Alice");

// 获取注解
Annotation[] annotations = clazz.getAnnotations();

2. 自定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {
    String value() default "";
}

// 使用注解
public class Service {
    @LogExecutionTime("processData")
    public void processData() {
        // 业务逻辑
    }
}

// 处理注解
Method method = Service.class.getMethod("processData");
if (method.isAnnotationPresent(LogExecutionTime.class)) {
    LogExecutionTime annotation = method.getAnnotation(LogExecutionTime.class);
    System.out.println("Method " + annotation.value() + " will be logged");
}

七、函数式编程

1. Lambda表达式

// 替代匿名类
Runnable r = () -> System.out.println("Lambda run");

// 集合排序
List<String> names = Arrays.asList("Bob", "Alice", "Charlie");
names.sort((a, b) -> a.compareTo(b));

// 函数式接口
@FunctionalInterface
interface Calculator {
    int calculate(int x, int y);
}

Calculator add = (a, b) -> a + b;
System.out.println(add.calculate(3, 5)); // 8

2. Stream API

List<String> transactions = Arrays.asList("T1001", "T2002", "T1003", "T3004");

// 流操作链
long count = transactions.stream()
    .filter(t -> t.startsWith("T1"))
    .map(String::toUpperCase)
    .sorted()
    .peek(System.out::println)
    .count();

// 并行流
List<Integer> numbers = IntStream.range(1, 100)
    .parallel()
    .filter(n -> n % 2 == 0)
    .boxed()
    .collect(Collectors.toList());

实践建议

  • 避免在lambda中修改外部状态
  • 简单操作用stream,复杂业务仍用传统方式
  • 大数据量考虑parallelStream,但要注意线程安全

通过本文的系统梳理,我们深入探讨了Java的核心知识点。建议读者结合实际项目需求,选择适合的技术方案,并在实践中不断深化理解。记住,掌握这些基础概念是成为Java专家的必经之路。

添加新评论