【NIO番外篇】之组件 Channel

在这里插入图片描述

目录

    • 一、什么是NIO Channel?
    • 二、常见的Channel组件及其用法
      • 1. FileChannel
      • 2. SocketChannel
      • 3. ServerSocketChannel
      • 4. DatagramChannel

🌟我的其他文章也讲解的比较有趣😁,如果喜欢博主的讲解方式,可以多多支持一下,感谢🤗!

🌟了解 Redis主从复制 请看 : Redis主从复制:告别单身Redis!

其他优质专栏: 【🎇SpringBoot】【🎉多线程】【🎨Redis】【✨设计模式专栏(已完结)】…等

如果喜欢作者的讲解方式,可以点赞收藏加关注,你的支持就是我的动力
✨更多文章请看个人主页: 码熔burning

这篇文章让我来详细讲解一下Java NIO中的Channel(通道)组件。

一、什么是NIO Channel?

看本篇文章之前可以先看看NIO是啥:NIO,看完你就懂了!

在Java NIO(New I/O)模型中,Channel扮演着核心角色。可以将其理解为一个连接到能够执行I/O操作的实体(如文件、网络套接字)的开放连接或通道。它类似于传统Java I/O中的Stream(流),但有几个关键区别:

  1. 双向性:传统的InputStream只能读,OutputStream只能写。而Channel通常是双向的,可以同时进行读和写操作(具体取决于通道类型,例如FileChannel)。
  2. 与Buffer交互Channel本身不直接存储数据。所有数据读写都必须通过Buffer对象进行。数据总是先从Channel读入Buffer,或者从Buffer写入Channel
  3. 异步/非阻塞支持Channel可以工作在阻塞(Blocking)模式或非阻塞(Non-Blocking)模式下。非阻塞模式是NIO实现高并发、高性能网络应用的关键,通常与Selector(选择器)一起使用。
  4. 底层连接Channel代表了与操作系统底层I/O服务的直接连接。

可以把Channel想象成数据传输的管道,而Buffer是运载数据的卡车。卡车(Buffer)在管道(Channel)中来回运输数据。

二、常见的Channel组件及其用法

Java NIO提供了多种Channel实现,用于处理不同类型的I/O。以下是一些最常见的:

  1. FileChannel: 用于文件I/O。
  2. SocketChannel: 用于TCP网络通信的客户端。
  3. ServerSocketChannel: 用于TCP网络通信的服务器端,监听并接受连接。
  4. DatagramChannel: 用于UDP网络通信。

下面我们逐一详细讲解:


1. FileChannel

FileChannel是用于读、写、映射和操作文件的通道。它是唯一保证始终阻塞,不能配置为非阻塞模式的常用通道。

特点:

  • 可以从文件的任何位置读写数据(随机访问)。
  • 可以将文件区域直接映射到内存(MappedByteBuffer),实现更快的I/O(内存映射文件)。
  • 可以实现通道之间的数据直接传输(零拷贝,Zero-Copy),效率很高。
  • 线程安全。

如何获取FileChannel

  • 通过FileInputStreamgetChannel()方法。
  • 通过FileOutputStreamgetChannel()方法。
  • 通过RandomAccessFilegetChannel()方法。
  • (推荐) 使用FileChannel.open(Path path, OpenOption... options)静态工厂方法。

常用方法:

  • read(ByteBuffer dst): 从通道读取数据到Buffer。返回读取的字节数,或-1表示到达文件末尾。
  • write(ByteBuffer src): 将Buffer中的数据写入通道。返回写入的字节数。
  • position(): 返回此通道的文件位置。
  • position(long newPosition): 设置此通道的文件位置。
  • size(): 返回此通道关联文件的当前大小。
  • truncate(long size): 将此通道的文件截断为给定大小。
  • force(boolean metaData): 强制将通道的所有更新写入存储设备。
  • map(FileChannel.MapMode mode, long position, long size): 将此通道的文件区域直接映射到内存中。
  • transferTo(long position, long count, WritableByteChannel target): 将字节从此通道的文件传输到给定的可写字节通道(高效的文件复制)。
  • transferFrom(ReadableByteChannel src, long position, long count): 将字节从给定的可读字节通道传输到此通道的文件(高效的文件复制)。

示例:使用FileChannel读取文件

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;public class FileChannelReadExample {public static void main(String[] args) {Path filePath = Paths.get("example.txt"); // 假设存在一个 example.txt 文件// 使用 try-with-resources 确保通道被关闭try (FileChannel fileChannel = FileChannel.open(filePath, StandardOpenOption.READ)) {ByteBuffer buffer = ByteBuffer.allocate(1024); // 分配一个1KB的缓冲区System.out.println("Reading from file: " + filePath);int bytesRead;while ((bytesRead = fileChannel.read(buffer)) != -1) { // 从通道读数据到缓冲区System.out.println("Read " + bytesRead + " bytes.");// 切换Buffer到读模式buffer.flip();// 处理缓冲区中的数据 (这里简单地打印出来)// 使用 Charset 将字节解码为字符System.out.print(StandardCharsets.UTF_8.decode(buffer));// 清空/重置Buffer,为下一次读做准备buffer.clear(); // 或者 buffer.compact(); 如果想保留未读数据}System.out.println("\nEnd of file reached.");} catch (IOException e) {System.err.println("Error reading file: " + e.getMessage());e.printStackTrace();}}
}
// 需要先创建一个 example.txt 文件,并写入一些内容,例如:
// Hello, Java NIO FileChannel!
// This is a test file.

示例:使用FileChannel写入文件

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;public class FileChannelWriteExample {public static void main(String[] args) {Path filePath = Paths.get("output.txt");String dataToWrite = "Writing using Java NIO FileChannel.\nLine 2.";// 使用 try-with-resourcestry (FileChannel fileChannel = FileChannel.open(filePath,StandardOpenOption.WRITE, // 允许写入StandardOpenOption.CREATE, // 如果文件不存在则创建StandardOpenOption.TRUNCATE_EXISTING)) { // 如果文件存在则清空内容ByteBuffer buffer = ByteBuffer.allocate(1024);// 将字符串数据放入缓冲区buffer.put(dataToWrite.getBytes(StandardCharsets.UTF_8));// 切换Buffer到读模式(写出模式)buffer.flip();System.out.println("Writing to file: " + filePath);while (buffer.hasRemaining()) {int bytesWritten = fileChannel.write(buffer); // 将缓冲区数据写入通道System.out.println("Wrote " + bytesWritten + " bytes.");}System.out.println("Finished writing.");} catch (IOException e) {System.err.println("Error writing file: " + e.getMessage());e.printStackTrace();}}
}

示例:使用transferTo高效复制文件

import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;public class FileChannelTransferExample {public static void main(String[] args) {Path sourcePath = Paths.get("example.txt"); // 源文件Path destPath = Paths.get("example_copy.txt"); // 目标文件try (FileChannel sourceChannel = FileChannel.open(sourcePath, StandardOpenOption.READ);FileChannel destChannel = FileChannel.open(destPath, StandardOpenOption.WRITE, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {long position = 0;long count = sourceChannel.size();System.out.println("Starting file transfer...");long bytesTransferred = sourceChannel.transferTo(position, count, destChannel);// 或者使用 destChannel.transferFrom(sourceChannel, position, count);System.out.println("Transferred " + bytesTransferred + " bytes from " + sourcePath + " to " + destPath);} catch (IOException e) {System.err.println("Error during file transfer: " + e.getMessage());e.printStackTrace();}}
}

2. SocketChannel

SocketChannel用于TCP网络连接的客户端。它可以工作在阻塞或非阻塞模式下。

特点:

  • 用于发起TCP连接到服务器。
  • 可以进行读写操作。
  • 可以配置为非阻塞模式,与Selector配合使用,实现单线程处理多个连接。

如何获取SocketChannel

  • SocketChannel.open(): 创建一个未连接的SocketChannel
  • SocketChannel.open(SocketAddress remote): 创建并直接连接到指定地址。

常用方法:

  • connect(SocketAddress remote): 连接到远程地址(非阻塞模式下立即返回,可能未完成连接)。
  • finishConnect(): 完成非阻塞连接过程。如果连接成功返回true,如果仍在进行中返回false,如果失败则抛出异常。
  • isConnected(): 检查是否已连接。
  • read(ByteBuffer dst): 从通道读取数据到Buffer。
  • write(ByteBuffer src): 将Buffer中的数据写入通道。
  • configureBlocking(boolean block): 设置阻塞/非阻塞模式。true为阻塞(默认),false为非阻塞。
  • register(Selector sel, int ops): 将通道注册到Selector上,监听指定事件(如SelectionKey.OP_CONNECT, OP_READ, OP_WRITE)。
  • close(): 关闭连接。

示例:阻塞模式的SocketChannel客户端

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;public class BlockingSocketClient {public static void main(String[] args) {String hostname = "localhost"; // 服务器地址int port = 9090;         // 服务器端口try (SocketChannel socketChannel = SocketChannel.open()) {// 连接服务器 (阻塞模式下会等待连接成功或失败)System.out.println("Connecting to " + hostname + ":" + port);socketChannel.connect(new InetSocketAddress(hostname, port));System.out.println("Connection established.");// 发送数据String message = "Hello from NIO Client!";ByteBuffer writeBuffer = ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8));System.out.println("Sending message: " + message);while (writeBuffer.hasRemaining()) {socketChannel.write(writeBuffer);}// 接收数据ByteBuffer readBuffer = ByteBuffer.allocate(1024);int bytesRead = socketChannel.read(readBuffer);if (bytesRead > 0) {readBuffer.flip();byte[] receivedBytes = new byte[readBuffer.remaining()];readBuffer.get(receivedBytes);String response = new String(receivedBytes, StandardCharsets.UTF_8);System.out.println("Received response: " + response);} else if (bytesRead == -1) {System.out.println("Server closed connection.");}System.out.println("Closing connection.");} catch (IOException e) {System.err.println("Client error: " + e.getMessage());e.printStackTrace();}}
}
// 这个例子需要一个监听在 localhost:9090 的服务器来响应。

示例:非阻塞模式SocketChannel(概念,通常与Selector配合)

非阻塞模式的SocketChannel通常与Selector一起使用,这里只展示配置和连接部分:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;public class NonBlockingSocketClientConcept {public static void main(String[] args) {String hostname = "localhost";int port = 9090;try {// 1. 创建 Selector 和 SocketChannelSelector selector = Selector.open();SocketChannel socketChannel = SocketChannel.open();// 2. 配置为非阻塞模式socketChannel.configureBlocking(false);// 3. 发起连接 (非阻塞,立即返回)boolean connected = socketChannel.connect(new InetSocketAddress(hostname, port));System.out.println("Initiating connection (non-blocking)...");if (connected) {System.out.println("Connection established immediately.");// 立即连接成功(少见),可以直接注册读写事件socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);} else {// 连接尚未完成,注册 OP_CONNECT 事件,等待连接完成System.out.println("Connection pending, registering OP_CONNECT.");socketChannel.register(selector, SelectionKey.OP_CONNECT);}// --- 之后进入 Selector 循环 ---// while (true) {//     selector.select(); // 阻塞等待事件//     Set<SelectionKey> selectedKeys = selector.selectedKeys();//     Iterator<SelectionKey> keyIterator = selectedKeys.iterator();////     while (keyIterator.hasNext()) {//         SelectionKey key = keyIterator.next();//         if (key.isConnectable()) {//             // 连接完成事件//             handleConnect(key, selector);//         } else if (key.isReadable()) {//             // 可读事件//             handleRead(key);//         } else if (key.isWritable()) {//             // 可写事件//             handleWrite(key);//         }//         keyIterator.remove();//     }// }// --- Selector 循环结束 ---// (实际应用中,Selector 循环会处理连接、读写,并在适当时候关闭 channel 和 selector)System.out.println("Selector loop would start here (conceptual).");// 在实际应用中关闭资源// socketChannel.close();// selector.close();} catch (IOException e) {System.err.println("Client error: " + e.getMessage());e.printStackTrace();}}// 辅助方法 (仅为演示)private static void handleConnect(SelectionKey key, Selector selector) throws IOException {SocketChannel channel = (SocketChannel) key.channel();if (channel.finishConnect()) {System.out.println("Connection successfully established.");// 连接成功,现在可以注册读写事件了key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE);} else {System.err.println("Failed to finish connection.");key.cancel(); // 取消注册channel.close();}}// handleRead 和 handleWrite 方法省略
}

3. ServerSocketChannel

ServerSocketChannel用于TCP网络连接的服务器端。它负责监听指定端口上的连接请求,并为每个接受的连接创建一个SocketChannel。它也可以配置为阻塞或非阻塞模式。

特点:

  • 监听入站TCP连接。
  • 为每个接受的连接创建一个SocketChannel
  • 可以配置为非阻塞模式,与Selector配合实现高并发服务器。

如何获取ServerSocketChannel

  • ServerSocketChannel.open(): 创建一个ServerSocketChannel

常用方法:

  • bind(SocketAddress local): 将通道的套接字绑定到本地地址并开始监听。
  • accept(): 接受一个连接。在阻塞模式下,此方法会阻塞直到有连接进来。在非阻塞模式下,如果没有待处理的连接,它会立即返回null。返回的是代表客户端连接的SocketChannel
  • configureBlocking(boolean block): 设置阻塞/非阻塞模式。
  • register(Selector sel, int ops): 将通道(通常是自身,监听OP_ACCEPT事件)注册到Selector
  • close(): 关闭监听。

示例:阻塞模式的ServerSocketChannel

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;public class BlockingServerSocket {public static void main(String[] args) {int port = 9090;try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {// 绑定端口并开始监听serverSocketChannel.bind(new InetSocketAddress(port));System.out.println("Server started. Listening on port " + port + " (Blocking Mode)");while (true) { // 无限循环接受连接System.out.println("Waiting for a new connection...");// 阻塞,直到有客户端连接进来SocketChannel clientChannel = serverSocketChannel.accept();System.out.println("Accepted connection from: " + clientChannel.getRemoteAddress());// 为每个客户端创建一个新线程处理(简单示例,非最佳实践)new Thread(() -> handleClient(clientChannel)).start();}} catch (IOException e) {System.err.println("Server error: " + e.getMessage());e.printStackTrace();}}private static void handleClient(SocketChannel clientChannel) {try (SocketChannel channel = clientChannel) { // 使用 try-with-resourcesByteBuffer buffer = ByteBuffer.allocate(1024);int bytesRead = channel.read(buffer); // 读取客户端数据if (bytesRead > 0) {buffer.flip();byte[] receivedBytes = new byte[buffer.remaining()];buffer.get(receivedBytes);String message = new String(receivedBytes, StandardCharsets.UTF_8);System.out.println("Received from client " + channel.getRemoteAddress() + ": " + message);// 回显给客户端String response = "Server received: " + message;ByteBuffer writeBuffer = ByteBuffer.wrap(response.getBytes(StandardCharsets.UTF_8));while (writeBuffer.hasRemaining()) {channel.write(writeBuffer);}System.out.println("Sent response to client " + channel.getRemoteAddress());} else if (bytesRead == -1) {System.out.println("Client " + channel.getRemoteAddress() + " closed connection.");}} catch (IOException e) {try {System.err.println("Error handling client " + clientChannel.getRemoteAddress() + ": " + e.getMessage());} catch (IOException ignored) {System.err.println("Error handling client (address unavailable): " + e.getMessage());}} finally {System.out.println("Finished handling client " ); // 地址可能已不可用}}
}

示例:非阻塞模式ServerSocketChannel(概念,通常与Selector配合)

import java.io.IOException;
import java.net.InetSocketAddress;
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 NonBlockingServerSocketConcept {public static void main(String[] args) {int port = 9090;try {// 1. 创建 Selector 和 ServerSocketChannelSelector selector = Selector.open();ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 2. 配置为非阻塞模式serverSocketChannel.configureBlocking(false);// 3. 绑定端口serverSocketChannel.bind(new InetSocketAddress(port));System.out.println("Server started. Listening on port " + port + " (Non-Blocking Mode)");// 4. 将 ServerSocketChannel 注册到 Selector,监听 OP_ACCEPT 事件serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);System.out.println("Waiting for events...");// --- 进入 Selector 循环 ---while (true) {int readyChannels = selector.select(); // 阻塞等待事件if (readyChannels == 0) continue; // 没有事件,继续等待Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> keyIterator = selectedKeys.iterator();while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();if (key.isAcceptable()) {// 有新的连接请求ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();SocketChannel clientChannel = serverChannel.accept(); // 接受连接 (非阻塞)if (clientChannel != null) {clientChannel.configureBlocking(false); // 将接受的客户端Channel也设为非阻塞// 将新的客户端Channel注册到Selector,监听读事件clientChannel.register(selector, SelectionKey.OP_READ);System.out.println("Accepted new connection from: " + clientChannel.getRemoteAddress());}} else if (key.isReadable()) {// 有客户端Channel可读// handleRead(key); // 调用处理读取的方法System.out.println("Readable event for channel: " + key.channel());// 在这里读取数据...// 如果读取完毕或连接关闭,需要 key.cancel() 和 channel.close()} else if (key.isWritable()) {// 有客户端Channel可写// handleWrite(key); // 调用处理写入的方法System.out.println("Writable event for channel: " + key.channel());// 在这里写入数据...// 写完数据后,可能需要取消 OP_WRITE 监听: key.interestOps(SelectionKey.OP_READ);}keyIterator.remove(); // 处理完后移除Key,防止重复处理}}// --- Selector 循环结束 ---} catch (IOException e) {System.err.println("Server error: " + e.getMessage());e.printStackTrace();}// 实际应用中需要正确关闭 serverSocketChannel 和 selector}// handleRead 和 handleWrite 方法省略
}

4. DatagramChannel

DatagramChannel用于UDP(用户数据报协议)网络通信。UDP是无连接的,所以DatagramChannel可以向任何IP地址和端口发送数据报,也可以接收来自任何IP地址和端口的数据报。

特点:

  • 支持无连接的UDP数据报发送和接收。
  • 可以配置为阻塞或非阻塞模式。
  • 可以“连接”(connect)到一个特定地址,这之后就可以像TCP一样使用readwrite方法,只与该特定地址通信。

如何获取DatagramChannel

  • DatagramChannel.open(): 创建一个DatagramChannel

常用方法:

  • bind(SocketAddress local): 将通道的套接字绑定到本地地址以接收数据。
  • send(ByteBuffer src, SocketAddress target): 向指定目标地址发送数据报。
  • receive(ByteBuffer dst): 接收一个数据报,并将数据放入Buffer。返回发送方的地址。在阻塞模式下,会等待直到收到数据报。在非阻塞模式下,如果没有数据报会立即返回null
  • connect(SocketAddress remote): 将通道“连接”到特定的远程地址。连接后,只能向/从此地址发送/接收数据报,并且可以使用read/write方法。
  • read(ByteBuffer dst): (仅在连接后使用)从连接的对等方读取数据报。
  • write(ByteBuffer src): (仅在连接后使用)向连接的对等方发送数据报。
  • disconnect(): 断开连接(如果已连接)。
  • configureBlocking(boolean block): 设置阻塞/非阻塞模式。
  • register(Selector sel, int ops): (非阻塞模式)注册到Selector

示例:DatagramChannel 发送数据

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.charset.StandardCharsets;public class DatagramSender {public static void main(String[] args) {String targetHost = "localhost";int targetPort = 9876;String message = "UDP Packet from NIO DatagramChannel";try (DatagramChannel channel = DatagramChannel.open()) {// 不需要 bind,操作系统会自动分配端口发送SocketAddress targetAddress = new InetSocketAddress(targetHost, targetPort);ByteBuffer buffer = ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8));System.out.println("Sending UDP packet to " + targetAddress);int bytesSent = channel.send(buffer, targetAddress); // 发送数据报System.out.println("Sent " + bytesSent + " bytes.");} catch (IOException e) {System.err.println("Datagram sender error: " + e.getMessage());e.printStackTrace();}}
}

示例:DatagramChannel 接收数据(阻塞模式)

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.charset.StandardCharsets;public class DatagramReceiver {public static void main(String[] args) {int listenPort = 9876;try (DatagramChannel channel = DatagramChannel.open()) {// 绑定到指定端口接收数据channel.bind(new InetSocketAddress(listenPort));System.out.println("UDP Receiver started. Listening on port " + listenPort);ByteBuffer buffer = ByteBuffer.allocate(1024);while (true) { // 循环接收buffer.clear(); // 准备接收System.out.println("Waiting to receive UDP packet...");// 阻塞,直到收到数据报SocketAddress senderAddress = channel.receive(buffer);if (senderAddress != null) {buffer.flip(); // 切换到读模式byte[] receivedBytes = new byte[buffer.remaining()];buffer.get(receivedBytes);String message = new String(receivedBytes, StandardCharsets.UTF_8);System.out.println("Received " + buffer.limit() + " bytes from " + senderAddress + ": " + message);// (可选) 可以向发送方回显消息// String response = "Receiver got: " + message;// ByteBuffer sendBuffer = ByteBuffer.wrap(response.getBytes(StandardCharsets.UTF_8));// channel.send(sendBuffer, senderAddress);}}} catch (IOException e) {System.err.println("Datagram receiver error: " + e.getMessage());e.printStackTrace();}}
}
// 需要先运行 Receiver,再运行 Sender。

总结

  • Channel是NIO中数据传输的管道,连接到I/O源(文件、套接字)。
  • ChannelBuffer紧密配合,读写操作通过Buffer进行。
  • FileChannel用于文件操作,支持随机访问、内存映射和零拷贝。
  • SocketChannelServerSocketChannel用于TCP网络通信,支持阻塞和非阻塞模式。
  • DatagramChannel用于UDP网络通信,支持阻塞和非阻塞模式。
  • 网络相关的ChannelSocketChannel, ServerSocketChannel, DatagramChannel)可以配置为非阻塞模式,并与Selector一起使用,是构建高性能、高并发NIO应用(如Netty框架的基础)的关键。

希望这篇文章的讲解和示例能帮助你理解Java NIO中的Channel组件!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/910264.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在人工智能与计算机技术融合的框架下探索高中教育数字化教学模式的创新路径

一、引言 1.1 研究背景 在数字中国战略与《中国教育现代化 2035》的政策导向下&#xff0c;人工智能与计算机技术的深度融合正深刻地重构着教育生态。随着科技的飞速发展&#xff0c;全球范围内的高中教育都面临着培养具备数字化素养人才的紧迫需求&#xff0c;传统的教学模式…

使用Python爬虫的2大原因和6大常用库

爬虫其实就是请求http、解析网页、存储数据的过程&#xff0c;并非高深的技术&#xff0c;但凡是编程语言都能做&#xff0c;连Excel VBA都可以实现爬虫&#xff0c;但Python爬虫的使用频率最高、场景最广。 这可不仅仅是因为Python有众多爬虫和数据处理库&#xff0c;还有一个…

第五篇:Python面向对象编程(OOP)深度教程

1. 类与对象 1.1 基本概念 ​​类​​是创建对象的蓝图,定义了对象的​​属性​​(数据)和​​方法​​(行为)。​​对象​​是类的实例化实体,每个对象拥有独立的属性值和共享的类方法 ​​示例​​:定义Dog类 class Dog:species = "Canis familiaris" …

【工具】Fiddler抓包

本文主要讲解如何使用Fiddler抓HTTP包&#xff0c;可通过所抓包内容分析HTTP请求/响应的细节 安装与配置 1.下载与安装 下载地址: https://www.telerik.com/fiddler/ 点击了链接后&#xff0c;跳转到以下页面&#xff1a; 点击Fiddler Classic(免费版)后&#xff0c;跳转到以…

第十六届蓝桥杯 省赛C/C++ 大学B组

编程题目现在在洛谷上都可以提交了。 未完待续&#xff0c;写不动了。 C11 编译命令 g A.cpp -o A -Wall -lm -stdc11A. 移动距离 本题总分&#xff1a;5 分 问题描述 小明初始在二维平面的原点&#xff0c;他想前往坐标 ( 233 , 666 ) (233, 666) (233,666)。在移动过程…

如何打造可维护系统

看到这篇文章中有很多内容很有共鸣&#xff0c;所以记录一下 在软件开发领域&#xff0c;代码的"可维护性"常被视作玄学。因为在设计之初很难把握合理设计和过度设计的边界&#xff0c;维护过程中&#xff0c;不能把握设计思想&#xff0c;代码的可维护性也没有明确的…

数据结构与算法——链表OJ题详解(2)

文章目录 一、前言二、OJ续享2.1相交链表2.2环形链表12.2环形链表2 三、总结 一、前言 哦了兄弟们&#xff0c;咱们上次在详解链表OJ题的时候&#xff0c;有一部分OJ题呢up并没有整理完&#xff0c;这一个星期呢&#xff0c;up也是在不断的学习并且沉淀着&#xff0c;也是终于…

java -jar与java -cp的区别

java -jar与java -cp 1、情景描述2、情景分析3、两者区别 通常情况下&#xff0c;我们会看到以下两种命令启动的Java程序&#xff1a; java -jar xxx.jar [args] java -cp xxx.jar mainclass [args]这两种用法有什么区别呢&#xff1f; 1、情景描述 1&#xff09;Java打包单个…