《Java 高级编程:从进阶到大师的飞升秘籍》

一、注解与反射

1. 注解

注解是 Java 提供的一种元数据机制,它为程序元素(类、方法、变量等)添加额外信息,这些信息可在编译、运行时被读取和处理,以实现代码检查、配置管理、框架扩展等功能。

自定义注解

自定义注解需使用 @interface 关键字,同时借助元注解指定注解的保留策略、作用目标等。常见元注解有 @Retention@Target@Documented 和 @Inherited

java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// @Retention 用于指定注解的保留策略,这里设置为 RUNTIME 表示在运行时可以通过反射获取注解信息
@Retention(RetentionPolicy.RUNTIME)
// @Target 用于指定注解可以应用的程序元素类型,这里表示注解可以应用于方法上
@Target(ElementType.METHOD)
@interface MyAnnotation {
    // 定义注解的属性,类似于方法声明,可以有默认值
    String value() default "default value";
    int count() default 1;
}
使用注解

在类中使用自定义注解,并在方法上添加注解属性值。

java

class MyClass {
    @MyAnnotation(value = "Hello Annotation", count = 3)
    public void myMethod() {
        System.out.println("This is a method with annotation.");
    }
}
注解处理器

注解处理器可以在编译时处理注解,执行代码生成、验证等操作。例如,使用 javax.annotation.processing 包中的类创建一个简单的注解处理器。

java

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import java.util.Set;

@SupportedAnnotationTypes("MyAnnotation")
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MyAnnotationProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (TypeElement annotation : annotations) {
            Set<? extends Element> annotatedElements = roundEnv.getElementsAnnotatedWith(annotation);
            for (Element element : annotatedElements) {
                MyAnnotation myAnnotation = element.getAnnotation(MyAnnotation.class);
                System.out.println("Annotation value: " + myAnnotation.value());
                System.out.println("Annotation count: " + myAnnotation.count());
            }
        }
        return true;
    }
}

2. 反射

反射允许程序在运行时获取类的信息并操作类的属性、方法和构造函数。通过反射,可在运行时动态地创建对象、调用方法、访问和修改属性等。

获取类的信息

通过 Class 对象可以获取类的各种信息,如类名、父类、接口、方法、属性等。

java

import java.lang.reflect.Method;

public class ReflectionExample {
    public static void main(String[] args) throws Exception {
        MyClass obj = new MyClass();
        // 获取对象的 Class 对象
        Class<?> cls = obj.getClass();
        // 获取类的名称
        System.out.println("Class name: " + cls.getName());

        // 获取类的所有方法
        Method[] methods = cls.getMethods();
        for (Method method : methods) {
            System.out.println("Method name: " + method.getName());
            // 检查方法上是否有 MyAnnotation 注解
            if (method.isAnnotationPresent(MyAnnotation.class)) {
                MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
                System.out.println("Annotation value: " + annotation.value());
                System.out.println("Annotation count: " + annotation.count());
            }
        }
    }
}
动态创建对象和调用方法

通过反射可以在运行时动态地创建对象并调用方法。

java

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class ReflectionObjectCreation {
    public static void main(String[] args) throws Exception {
        // 获取类的 Class 对象
        Class<?> cls = MyClass.class;
        // 获取类的无参构造函数
        Constructor<?> constructor = cls.getConstructor();
        // 通过构造函数创建对象
        Object obj = constructor.newInstance();

        // 获取指定名称和参数类型的方法
        Method method = cls.getMethod("myMethod");
        // 调用方法
        method.invoke(obj);
    }
}
反射与泛型

反射可以处理泛型信息,但由于 Java 的泛型擦除机制,在运行时需要特殊处理。

java

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

class GenericClass<T> {
    private List<T> list;

    public GenericClass() {
        list = new ArrayList<>();
    }

    public List<T> getList() {
        return list;
    }
}

public class ReflectionWithGeneric {
    public static void main(String[] args) throws NoSuchFieldException {
        GenericClass<String> genericClass = new GenericClass<>();
        Class<?> cls = genericClass.getClass();
        java.lang.reflect.Field field = cls.getDeclaredField("list");
        Type genericType = field.getGenericType();
        if (genericType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for (Type type : actualTypeArguments) {
                System.out.println("Generic type: " + type.getTypeName());
            }
        }
    }
}

二、多线程高级应用

1. 线程池

线程池可以管理和复用线程,避免频繁创建和销毁线程带来的性能开销,提高程序的性能和稳定性。Java 提供了 ExecutorService 接口和 Executors 工具类来创建和管理线程池。

创建线程池

常见的线程池类型有固定大小线程池、缓存线程池、单线程线程池和定时任务线程池。

java

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Running task in thread: " + Thread.currentThread().getName());
        try {
            // 模拟任务执行时间
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建固定大小为 3 的线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 5; i++) {
            // 向线程池提交任务
            executor.submit(new MyRunnable());
        }
        // 关闭线程池,不再接受新任务,但会等待已提交的任务执行完毕
        executor.shutdown();
    }
}
线程池的生命周期管理

线程池有四种状态:运行、关闭、停止和终止。可以通过 shutdown() 方法关闭线程池,不再接受新任务,但会等待已提交的任务执行完毕;通过 shutdownNow() 方法立即停止线程池,尝试中断正在执行的任务,并返回未执行的任务列表。

java

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ThreadPoolLifecycle {
    public static void main(String[] args) throws InterruptedException {
        ExecutorService executor = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 5; i++) {
            executor.submit(new MyRunnable());
        }

        // 关闭线程池
        executor.shutdown();
        // 等待线程池中的任务执行完毕,最多等待 5 秒
        if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {
            // 如果 5 秒后任务还未执行完毕,强制停止线程池
            List<Runnable> remainingTasks = executor.shutdownNow();
            System.out.println("Remaining tasks: " + remainingTasks.size());
        }
    }
}
自定义线程池

除了使用 Executors 工具类创建线程池,还可以通过 ThreadPoolExecutor 类自定义线程池。

java

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CustomThreadPoolExample {
    public static void main(String[] args) {
        int corePoolSize = 2;
        int maximumPoolSize = 5;
        long keepAliveTime = 60;
        TimeUnit unit = TimeUnit.SECONDS;
        ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10);

        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                corePoolSize,
                maximumPoolSize,
                keepAliveTime,
                unit,
                workQueue
        );

        for (int i = 0; i < 5; i++) {
            executor.submit(new MyRunnable());
        }

        executor.shutdown();
    }
}

2. 并发集合

Java 提供了并发集合,如 ConcurrentHashMapConcurrentLinkedQueue 等,这些集合在多线程环境下可以安全地进行读写操作,避免了使用传统集合时可能出现的线程安全问题。

ConcurrentHashMap

ConcurrentHashMap 是线程安全的哈希表,采用分段锁或 CAS(Compare-And-Swap)机制来实现并发操作。

java

import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentMapExample {
    public static void main(String[] args) {
        ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
        // 向 ConcurrentHashMap 中添加元素
        map.put("key1", 1);
        map.put("key2", 2);

        // 获取元素
        Integer value = map.get("key1");
        System.out.println("Value of key1: " + value);

        // 替换元素
        map.replace("key2", 3);
        System.out.println("Value of key2 after replacement: " + map.get("key2"));
    }
}
ConcurrentLinkedQueue

ConcurrentLinkedQueue 是线程安全的无界队列,基于链表实现,适用于多线程环境下的生产者 - 消费者模型。

java

import java.util.concurrent.ConcurrentLinkedQueue;

public class ConcurrentQueueExample {
    public static void main(String[] args) {
        ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
        // 向队列中添加元素
        queue.add("element1");
        queue.add("element2");

        // 从队列中取出元素
        String element = queue.poll();
        System.out.println("Polled element: " + element);
    }
}
CopyOnWriteArrayList

CopyOnWriteArrayList 是线程安全的列表,它在进行写操作时会创建一个新的数组副本,适用于读多写少的场景。

java

import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        list.add("item1");
        list.add("item2");

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        list.add("item3");
        iterator = list.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
    }
}

3. 锁机制

Java 提供了多种锁机制,如 synchronized 关键字、ReentrantLockReadWriteLock 等,用于实现线程同步和并发控制。

synchronized 关键字

synchronized 关键字可以修饰方法或代码块,确保同一时间只有一个线程可以访问被修饰的方法或代码块。

java

class SynchronizedExample {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    }
}
ReentrantLock

ReentrantLock 是一个可重入锁,它提供了比 synchronized 更灵活的锁机制,如可中断锁、定时锁等。

java

import java.util.concurrent.locks.ReentrantLock;

class ReentrantLockExample {
    private int count = 0;
    private ReentrantLock lock = new ReentrantLock();

    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }
}
ReadWriteLock

ReadWriteLock 是一个读写锁,它允许多个线程同时进行读操作,但在写操作时会独占锁,适用于读多写少的场景。

java

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class ReadWriteLockExample {
    private int data = 0;
    private ReadWriteLock lock = new ReentrantReadWriteLock();

    public int readData() {
        lock.readLock().lock();
        try {
            return data;
        } finally {
            lock.readLock().unlock();
        }
    }

    public void writeData(int newData) {
        lock.writeLock().lock();
        try {
            data = newData;
        } finally {
            lock.writeLock().unlock();
        }
    }
}

三、网络编程

1. Socket 编程

Socket 编程用于实现网络通信,Java 提供了 Socket 和 ServerSocket 类来实现客户端 - 服务器模型的网络通信。

服务器端代码

服务器端使用 ServerSocket 监听指定端口,等待客户端连接。当有客户端连接时,会返回一个 Socket 对象,用于与客户端进行通信。

java

import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class Server {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8888)) {
            System.out.println("Server is listening on port 8888");
            while (true) {
                // 等待客户端连接
                Socket socket = serverSocket.accept();
                System.out.println("Client connected: " + socket.getInetAddress());

                try (Scanner in = new Scanner(socket.getInputStream());
                     PrintWriter out = new PrintWriter(socket.getOutputStream(), true)) {
                    String inputLine;
                    while ((inputLine = in.nextLine()) != null) {
                        System.out.println("Received from client: " + inputLine);
                        // 向客户端发送响应
                        out.println("Server received: " + inputLine);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
客户端代码

客户端使用 Socket 连接到服务器指定的地址和端口,然后可以通过输入输出流与服务器进行通信。

java

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) {
        try (Socket socket = new Socket("localhost", 8888);
             PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
             Scanner in = new Scanner(socket.getInputStream());
             Scanner scanner = new Scanner(System.in)) {
            System.out.println("Connected to server. Enter message:");
            while (true) {
                String message = scanner.nextLine();
                // 向服务器发送消息
                out.println(message);
                if ("quit".equalsIgnoreCase(message)) {
                    break;
                }
                // 接收服务器的响应
                String response = in.nextLine();
                System.out.println("Server response: " + response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
基于 UDP 的 Socket 编程

UDP(User Datagram Protocol)是一种无连接的传输协议,它不保证数据的可靠传输,但具有传输速度快的特点。Java 提供了 DatagramSocket 和 DatagramPacket 类来实现 UDP 通信。

java

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

// UDP 服务器
class UDPServer {
    public static void main(String[] args) {
        try (DatagramSocket socket = new DatagramSocket(8888)) {
            byte[] receiveBuffer = new byte[1024];
            DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
            socket.receive(receivePacket);

            String message = new String(receivePacket.getData(), 0, receivePacket.getLength());
            System.out.println("Received from client: " + message);

            InetAddress clientAddress = receivePacket.getAddress();
            int clientPort = receivePacket.getPort();
            String responseMessage = "Server received: " + message;
            byte[] sendBuffer = responseMessage.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length, clientAddress, clientPort);
            socket.send(sendPacket);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

// UDP 客户端
class UDPClient {
    public static void main(String[] args) {
        try (DatagramSocket socket = new DatagramSocket()) {
            InetAddress serverAddress = InetAddress.getByName("localhost");
            String message = "Hello, server!";
            byte[] sendBuffer = message.getBytes();
            DatagramPacket sendPacket = new DatagramPacket(sendBuffer, sendBuffer.length, serverAddress, 8888);
            socket.send(sendPacket);

            byte[] receiveBuffer = new byte[1024];
            DatagramPacket receivePacket = new DatagramPacket(receiveBuffer, receiveBuffer.length);
            socket.receive(receivePacket);

            String responseMessage = new String(receivePacket.getData(), 0, receivePacket.getLength());
            System.out.println("Received from server: " + responseMessage);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

2. NIO 编程

Java NIO(New I/O)是 Java 1.4 引入的新的 I/O 库,提供了非阻塞 I/O 操作,适用于高并发场景。NIO 主要基于通道(Channel)和缓冲区(Buffer)进行数据传输,通过选择器(Selector)实现多路复用。

java

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 NioServer {
    public static void main(String[] args) throws IOException {
        // 创建选择器
        Selector selector = Selector.open();
        // 创建服务器套接字通道
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(8888));
        // 设置为非阻塞模式
        serverSocketChannel.configureBlocking(false);
        // 注册选择器,监听连接事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        System.out.println("NIO Server is listening on port 8888");

        while (true) {
            // 等待事件发生
            selector.select();
            // 获取所有已就绪的选择键
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

            while (keyIterator.hasNext()) {
                SelectionKey key = keyIterator.next();

                if (key.isAcceptable()) {
                    // 处理连接事件
                    ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                    SocketChannel socketChannel = ssc.accept();
                    socketChannel.configureBlocking(false);
                    // 注册选择器,监听读事件
                    socketChannel.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    // 处理读事件
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int bytesRead = socketChannel.read(buffer);
                    if (bytesRead > 0) {
                        buffer.flip();
                        byte[] data = new byte[buffer.remaining()];
                        buffer.get(data);
                        String message = new String(data);
                        System.out.println("Received from client: " + message);

                        // 向客户端发送响应
                        ByteBuffer responseBuffer = ByteBuffer.wrap(("Server received: " + message).getBytes());
                        socketChannel.write(responseBuffer);
                    }
                }
                // 移除已处理的选择键
                keyIterator.remove();
            }
        }
    }
}
NIO.2 编程

Java 7 引入了 NIO.2,它在 NIO 的基础上进行了扩展,提供了更强大的文件和网络编程功能。例如,使用 AsynchronousFileChannel 进行异步文件操作。

java

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.Future;

public class Nio2Example {
    public static void main(String[] args) {
        Path path = Paths.get("test.txt");
        try (AsynchronousFileChannel fileChannel = AsynchronousFileChannel.open(path, StandardOpenOption.READ)) {
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            Future<Integer> result = fileChannel.read(buffer, 0);
            while (!result.isDone()) {
                System.out.println("Reading file...");
            }
            Integer bytesRead = result.get();
            System.out.println("Bytes read: " + bytesRead);
            buffer.flip();
            byte[] data = new byte[buffer.remaining()];
            buffer.get(data);
            String content = new String(data);
            System.out.println("File content: " + content);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

四、数据库操作

1. JDBC 连接数据库

使用 JDBC(Java Database Connectivity)可以连接数据库并执行 SQL 语句。JDBC 提供了一套标准的 API,使得 Java 程序可以与各种数据库进行交互。

连接 MySQL 数据库

首先需要下载并添加 MySQL JDBC 驱动到项目中,然后使用 DriverManager 类来获取数据库连接。

java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class JdbcExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String user = "root";
        String password = "password";
        try (Connection conn = DriverManager.getConnection(url, user, password);
             Statement stmt = conn.createStatement()) {
            // 执行查询语句
            String sql = "SELECT * FROM users";
            ResultSet rs = stmt.executeQuery(sql);
            while (rs.next()) {
                // 获取查询结果
                int id = rs.getInt("id");
                String username = rs.getString("username");
                String email = rs.getString("email");
                System.out.println("ID: " + id + ", Username: " + username + ", Email: " + email);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
预处理语句

使用预处理语句(PreparedStatement)可以提高 SQL 语句的执行效率,同时避免 SQL 注入攻击。

java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class PreparedStatementExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String user = "root";
        String password = "password";
        try (Connection conn = DriverManager.getConnection(url, user, password)) {
            // 定义预处理语句
            String sql = "SELECT * FROM users WHERE username = ?";
            PreparedStatement pstmt = conn.prepareStatement(sql);
            // 设置参数
            pstmt.setString(1, "john");
            // 执行查询
            ResultSet rs = pstmt.executeQuery();
            while (rs.next()) {
                int id = rs.getInt("id");
                String username = rs.getString("username");
                String email = rs.getString("email");
                System.out.println("ID: " + id + ", Username: " + username + ", Email: " + email);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
批量操作

使用 Statement 或 PreparedStatement 可以进行批量操作,提高数据库操作的效率。

java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;

public class BatchOperationExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String user = "root";
        String password = "password";
        try (Connection conn = DriverManager.getConnection(url, user, password)) {
            String sql = "INSERT INTO users (username, email) VALUES (?, ?)";
            PreparedStatement pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, "user1");
            pstmt.setString(2, "user1@example.com");
            pstmt.addBatch();
            pstmt.setString(1, "user2");
            pstmt.setString(2, "user2@example.com");
            pstmt.addBatch();

            int[] results = pstmt.executeBatch();
            for (int result : results) {
                System.out.println("Insert result: " + result);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2. 事务管理

在数据库操作中,事务是一组不可分割的操作序列,要么全部执行成功,要么全部失败回滚。JDBC 提供了事务管理的功能,可以通过设置自动提交模式和手动提交或回滚来实现事务控制。

java

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;

public class TransactionExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/mydb";
        String user = "root";
        String password = "password";
        try (Connection conn = DriverManager.getConnection(url, user, password)) {
            // 关闭自动提交模式
            conn.setAutoCommit(false);
            try (Statement stmt = conn.createStatement()) {
                // 执行插入操作
                String sql1 = "INSERT INTO users (username, email) VALUES ('jane', 'jane@example.com')";
                stmt.executeUpdate(sql1);

                // 模拟异常
                int result = 1 / 0;

                // 执行更新操作
                String sql2 = "UPDATE users SET email = 'newemail@example.com' WHERE username = 'john'";
                stmt.executeUpdate(sql2);

                // 提交事务
                conn.commit();
                System.out.println("Transaction committed successfully");
            } catch (Exception e) {
                // 回滚事务
                conn.rollback();
                System.out.println("Transaction rolled back due to exception: " + e.getMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
分布式事务

在分布式系统中,可能涉及多个数据库或服务的事务操作,需要使用分布式事务管理。常见的分布式事务解决方案有两阶段提交(2PC)、三阶段提交(3PC)和事务补偿机制等。以 JTA(Java Transaction API)为例,它提供了一种标准的方式来管理分布式事务。

java

import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class DistributedTransactionExample {
    public static void main(String[] args) {
        try {
            InitialContext ctx = new InitialContext();
            UserTransaction ut = (UserTransaction) ctx.lookup("java:comp/UserTransaction");
            ut.begin();

            Connection conn1 = DriverManager.getConnection("jdbc:mysql://localhost:3306/db1", "user1", "password1");
            Connection conn2 = DriverManager.getConnection("jdbc:mysql://localhost:3306/db2", "user2", "password2");

            Statement stmt1 = conn1.createStatement();
            stmt1.executeUpdate("INSERT INTO table1 (column1) VALUES ('value1')");

            Statement stmt2 = conn2.createStatement();
            stmt2.executeUpdate("INSERT INTO table2 (column2) VALUES ('value2')");

            ut.commit();
            System.out.println("Distributed transaction committed successfully");
        } catch (NamingException | NotSupportedException | SystemException | RollbackException | HeuristicMixedException | HeuristicRollbackException | SQLException e) {
            e.printStackTrace();
        }
    }
}

五、设计模式应用

1. 单例模式

单例模式确保一个类只有一个实例,并提供一个全局访问点。常见的单例模式实现方式有饿汉式、懒汉式、双重检查锁定和静态内部类。

饿汉式单例

饿汉式单例在类加载时就创建实例,线程安全,但可能会造成资源浪费。

java

class SingletonEager {
    // 在类加载时就创建实例
    private static final SingletonEager instance = new SingletonEager();

    private SingletonEager() {}

    public static SingletonEager getInstance() {
        return instance;
    }
}
懒汉式单例

懒汉式单例在第一次使用时才创建实例,但在多线程环境下可能会出现线程安全问题。

java

class SingletonLazy {
    private static SingletonLazy instance;

    private SingletonLazy() {}

    public static synchronized SingletonLazy getInstance() {
        if (instance == null) {
            instance = new SingletonLazy();
        }
        return instance;
    }
}
双重检查锁定单例

双重检查锁定单例结合了懒汉式和线程安全的特点,在多线程环境下高效地创建单例实例。

java

class SingletonDoubleCheck {
    private static volatile SingletonDoubleCheck instance;

    private SingletonDoubleCheck() {}

    public static SingletonDoubleCheck getInstance() {
        if (instance == null) {
            synchronized (SingletonDoubleCheck.class) {
                if (instance == null) {
                    instance = new SingletonDoubleCheck();
                }
            }
        }
        return instance;
    }
}
静态内部类单例

静态内部类单例利用 Java 静态内部类的特性,实现了延迟加载和线程安全。

java

class SingletonStaticInnerClass {
    private SingletonStaticInnerClass() {}

    private static class SingletonHolder {
        private static final SingletonStaticInnerClass instance = new SingletonStaticInnerClass();
    }

    public static SingletonStaticInnerClass getInstance() {
        return SingletonHolder.instance;
    }
}
枚举单例

枚举单例是一种简洁、线程安全且可以防止反序列化重新创建新对象的单例实现方式。

java

enum SingletonEnum {
    INSTANCE;

    public void doSomething() {
        System.out.println("Doing something...");
    }
}

2. 工厂模式

工厂模式是一种创建对象的设计模式,将对象的创建和使用分离,提高了代码的可维护性和可扩展性。常见的工厂模式有简单工厂模式、工厂方法模式和抽象工厂模式。

简单工厂模式

简单工厂模式定义一个工厂类,根据传入的参数创建不同类型的对象。

java

// 产品接口
interface Product {
    void operation();
}

// 具体产品类
class ConcreteProductA implements Product {
    @Override
    public void operation() {
        System.out.println("ConcreteProductA operation");
    }
}

class ConcreteProductB implements Product {
    @Override
    public void operation() {
        System.out.println("ConcreteProductB operation");
    }
}

// 简单工厂类
class SimpleFactory {
    public static Product createProduct(String type) {
        if ("A".equals(type)) {
            return new ConcreteProductA();
        } else if ("B".equals(type)) {
            return new ConcreteProductB();
        }
        return null;
    }
}

public class SimpleFactoryExample {
    public static void main(String[] args) {
        Product productA = SimpleFactory.createProduct("A");
        productA.operation();

        Product productB = SimpleFactory.createProduct("B");
        productB.operation();
    }
}

工厂方法模式

工厂方法模式将对象的创建延迟到子类中实现,每个具体工厂类负责创建一种具体产品。

java

// 产品接口
interface Product {
    void operation();
}

// 具体产品类
class ConcreteProductA implements Product {
    @Override
    public void operation() {
        System.out.println("ConcreteProductA operation");
    }
}

class ConcreteProductB implements Product {
    @Override
    public void operation() {
        System.out.println("ConcreteProductB operation");
    }
}

// 抽象工厂类
abstract class Factory {
    public abstract Product createProduct();
}

// 具体工厂类
class ConcreteFactoryA extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

class ConcreteFactoryB extends Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

public class FactoryMethodExample {
    public static void main(String[] args) {
        Factory factoryA = new ConcreteFactoryA();
        Product productA = factoryA.createProduct();
        productA.operation();

        Factory factoryB = new ConcreteFactoryB();
        Product productB = factoryB.createProduct();
        productB.operation();
    }
}

工厂方法模式的优势在于符合开闭原则,当需要新增产品时,只需创建新的具体产品类和对应的具体工厂类,而无需修改原有的代码。不过,它也有一定的缺点,随着产品种类的增多,具体工厂类的数量会不断增加,导致类的数量膨胀。

抽象工厂模式

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。它与工厂方法模式的区别在于,工厂方法模式针对单一产品等级结构,而抽象工厂模式针对多个产品等级结构。

java

// 抽象产品A
interface AbstractProductA {
    void use();
}

// 具体产品A1
class ConcreteProductA1 implements AbstractProductA {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA1");
    }
}

// 具体产品A2
class ConcreteProductA2 implements AbstractProductA {
    @Override
    public void use() {
        System.out.println("Using ConcreteProductA2");
    }
}

// 抽象产品B
interface AbstractProductB {
    void work();
}

// 具体产品B1
class ConcreteProductB1 implements AbstractProductB {
    @Override
    public void work() {
        System.out.println("ConcreteProductB1 is working");
    }
}

// 具体产品B2
class ConcreteProductB2 implements AbstractProductB {
    @Override
    public void work() {
        System.out.println("ConcreteProductB2 is working");
    }
}

// 抽象工厂
interface AbstractFactory {
    AbstractProductA createProductA();
    AbstractProductB createProductB();
}

// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {
    @Override
    public AbstractProductA createProductA() {
        return new ConcreteProductA1();
    }

    @Override
    public AbstractProductB createProductB() {
        return new ConcreteProductB1();
    }
}

// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {
    @Override
    public AbstractProductA createProductA() {
        return new ConcreteProductA2();
    }

    @Override
    public AbstractProductB createProductB() {
        return new ConcreteProductB2();
    }
}

public class AbstractFactoryExample {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        AbstractProductA productA1 = factory1.createProductA();
        AbstractProductB productB1 = factory1.createProductB();
        productA1.use();
        productB1.work();

        AbstractFactory factory2 = new ConcreteFactory2();
        AbstractProductA productA2 = factory2.createProductA();
        AbstractProductB productB2 = factory2.createProductB();
        productA2.use();
        productB2.work();
    }
}

抽象工厂模式的优点是将一系列产品的创建封装在一个工厂中,便于维护和管理。缺点是当产品等级结构发生变化时,需要修改抽象工厂接口及其所有具体工厂类,违反了开闭原则。

3. 观察者模式

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己的状态。

java

import java.util.ArrayList;
import java.util.List;

// 主题接口
interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

// 观察者接口
interface Observer {
    void update(String message);
}

// 具体主题
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();
    private String message;

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }

    public void setMessage(String message) {
        this.message = message;
        notifyObservers();
    }
}

// 具体观察者
class ConcreteObserver implements Observer {
    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " received message: " + message);
    }
}

public class ObserverPatternExample {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();

        ConcreteObserver observer1 = new ConcreteObserver("Observer1");
        ConcreteObserver observer2 = new ConcreteObserver("Observer2");

        subject.registerObserver(observer1);
        subject.registerObserver(observer2);

        subject.setMessage("New message from the subject!");

        subject.removeObserver(observer2);
        subject.setMessage("Another message after removing an observer.");
    }
}

观察者模式在很多场景中都有应用,如 GUI 编程中的事件处理、消息通知系统等。它的优点是实现了对象之间的解耦,提高了系统的可维护性和可扩展性。但如果观察者过多,通知所有观察者可能会带来性能问题。

4. 装饰器模式

装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。它通过创建一个包装对象,也就是装饰器,来包裹真实的对象。

java

// 组件接口
interface Component {
    void operation();
}

// 具体组件
class ConcreteComponent implements Component {
    @Override
    public void operation() {
        System.out.println("ConcreteComponent operation");
    }
}

// 抽象装饰器
abstract class Decorator implements Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        component.operation();
    }
}

// 具体装饰器A
class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addedBehaviorA();
    }

    private void addedBehaviorA() {
        System.out.println("Added behavior A");
    }
}

// 具体装饰器B
class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addedBehaviorB();
    }

    private void addedBehaviorB() {
        System.out.println("Added behavior B");
    }
}

public class DecoratorPatternExample {
    public static void main(String[] args) {
        Component component = new ConcreteComponent();
        Component decoratedComponentA = new ConcreteDecoratorA(component);
        Component decoratedComponentAB = new ConcreteDecoratorB(decoratedComponentA);

        decoratedComponentAB.operation();
    }
}

装饰器模式的优点是可以动态地为对象添加功能,避免了使用继承带来的类爆炸问题。但它也会导致代码中对象嵌套较多,增加了代码的复杂度。

5. 代理模式

代理模式为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用。

静态代理

java

// 主题接口
interface Subject {
    void request();
}

// 真实主题
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject handling request");
    }
}

// 代理主题
class ProxySubject implements Subject {
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        preRequest();
        realSubject.request();
        postRequest();
    }

    private void preRequest() {
        System.out.println("ProxySubject: Preparing to handle request");
    }

    private void postRequest() {
        System.out.println("ProxySubject: Finished handling request");
    }
}

public class StaticProxyExample {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxySubject proxySubject = new ProxySubject(realSubject);
        proxySubject.request();
    }
}

静态代理的缺点是代理类和委托类的接口方法必须一致,并且每一个委托类都需要创建一个对应的代理类,当接口方法发生变化时,需要同时修改委托类和代理类。

动态代理

java

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

// 主题接口
interface Subject {
    void request();
}

// 真实主题
class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("RealSubject handling request");
    }
}

// 调用处理器
class ProxyHandler implements InvocationHandler {
    private Object target;

    public ProxyHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        preRequest();
        Object result = method.invoke(target, args);
        postRequest();
        return result;
    }

    private void preRequest() {
        System.out.println("Proxy: Preparing to handle request");
    }

    private void postRequest() {
        System.out.println("Proxy: Finished handling request");
    }
}

public class DynamicProxyExample {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        ProxyHandler handler = new ProxyHandler(realSubject);
        Subject proxySubject = (Subject) Proxy.newProxyInstance(
                Subject.class.getClassLoader(),
                new Class<?>[]{Subject.class},
                handler
        );
        proxySubject.request();
    }
}

动态代理通过反射机制在运行时创建代理对象,避免了静态代理的缺点。它在 AOP(面向切面编程)中有着广泛的应用。

六、序列化与反序列化

1. 基本概念

序列化是将对象的状态信息转换为可以存储或传输的形式(如字节序列)的过程,反序列化则是将字节序列恢复为对象的过程。在 Java 中,对象要实现序列化,需要实现 java.io.Serializable 接口。

java

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;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

public class SerializationExample {
    public static void main(String[] args) {
        Person person = new Person("John", 30);

        // 序列化
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser"))) {
            oos.writeObject(person);
            System.out.println("Object serialized");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 反序列化
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser"))) {
            Person deserializedPerson = (Person) ois.readObject();
            System.out.println("Deserialized person: " + deserializedPerson.getName() + ", " + deserializedPerson.getAge());
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

2. 注意事项

  • serialVersionUID:它是一个序列化版本号,用于在反序列化时验证序列化对象和当前类是否兼容。如果没有显式定义,Java 会根据类的结构自动生成一个,当类的结构发生变化时,可能会导致反序列化失败。因此,建议显式定义 serialVersionUID
  • transient 关键字:如果某些字段不需要序列化,可以使用 transient 关键字修饰。例如:

java

import java.io.*;

class Employee implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private transient int salary;

    public Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public int getSalary() {
        return salary;
    }
}

public class TransientExample {
    public static void main(String[] args) {
        Employee employee = new Employee("Alice", 5000);

        // 序列化
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("employee.ser"))) {
            oos.writeObject(employee);
            System.out.println("Employee object serialized");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 反序列化
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("employee.ser"))) {
            Employee deserializedEmployee = (Employee) ois.readObject();
            System.out.println("Deserialized employee: " + deserializedEmployee.getName() + ", Salary: " + deserializedEmployee.getSalary());
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

在上述例子中,salary 字段被 transient 修饰,反序列化后该字段的值为默认值(对于 int 类型是 0)。

七、性能优化与调优

1. 代码层面优化

减少对象创建

频繁创建对象会增加垃圾回收的压力,尽量复用对象。例如,使用 StringBuilder 代替 String 进行字符串拼接。

java

public class StringConcatenationExample {
    public static void main(String[] args) {
        // 使用 StringBuilder 进行字符串拼接
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 1000; i++) {
            sb.append(i);
        }
        String result = sb.toString();
    }
}
避免使用全局变量

全局变量会增加对象的生命周期,不利于垃圾回收。尽量使用局部变量。

合理使用数据结构

根据不同的业务场景选择合适的数据结构。例如,需要频繁查找元素时,使用 HashMap;需要保持插入顺序时,使用 LinkedHashMap

2. 内存优化

垃圾回收机制

了解 Java 的垃圾回收机制,合理设置堆内存大小。可以通过 -Xmx 和 -Xms 参数来设置最大堆内存和初始堆内存。例如:

plaintext

java -Xmx512m -Xms256m YourMainClass
弱引用和软引用

使用 WeakReference 和 SoftReference 可以在内存不足时让对象更容易被垃圾回收。例如:

java

import java.lang.ref.SoftReference;

public class SoftReferenceExample {
    public static void main(String[] args) {
        byte[] largeObject = new byte[1024 * 1024];
        SoftReference<byte[]> softReference = new SoftReference<>(largeObject);
        largeObject = null; // 释放强引用

        byte[] retrievedObject = softReference.get();
        if (retrievedObject != null) {
            System.out.println("Object is still in memory");
        } else {
            System.out.println("Object has been garbage collected");
        }
    }
}

3. 性能监测工具

VisualVM

VisualVM 是一个可视化的性能监测工具,可以实时监控 Java 应用程序的内存使用、线程状态、CPU 使用率等。通过它可以分析应用程序的性能瓶颈。

YourKit

YourKit 是一款功能强大的 Java 性能分析工具,它可以深入分析应用程序的内存泄漏、方法调用时间等问题。

通过深入学习这些 Java 高级知识,你能更全面、更深入地理解 Java 语言的特性和机制,编写出更高效、更复杂、更具可维护性和可扩展性的 Java 程序。同时,不断实践和应用这些知识,将有助于你在实际项目中更好地解决问题,提升自己的编程能力和技术水平。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值