BIO,NIO,AIO编程实战

news2024/9/18 21:07:04

写在前面

关于IO分类以及IO模型等理论知识,可以参考io之io分类和io模型这篇文章。本文主要来实现Java中相关IO模型实现程序。

1:BIO

blocking io,是Java io中对阻塞IO模型的具体实现。

因为不管是server端还是client端,都需要发送消息给对端,所以我们先来定义一个通道的处理器类负责完成消息发送的工作:

package com.dahuyou.io.model.bio;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.Charset;

public class ChannelHandler {

    private Socket socket;
    private Charset charset;

    public ChannelHandler(Socket socket, Charset charset) {
        this.socket = socket;
        this.charset = charset;
    }

    public void writeAndFlush(Object msg) {
        OutputStream out = null;
        try {
            out = socket.getOutputStream();
            out.write((msg.toString()).getBytes(charset));
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public Socket socket() {
        return socket;
    }

}

再有就是client和server又是有所不同的,哪里不同呢?一个是通道建立成功是行为,以及读取到消息时的行为可能是不同的,所以再来定义一个适配器类来适配这些不同,并且在该类中依赖ChannleHandler,从而拥有向通道中发送消息的能力,代码如下:

package com.dahuyou.io.model.bio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.nio.charset.Charset;

public abstract class ChannelAdapter extends Thread {

    private Socket socket;
    private ChannelHandler channelHandler;
    private Charset charset;

    public ChannelAdapter(Socket socket, Charset charset) {
        this.socket = socket;
        this.charset = charset;
        while (!socket.isConnected()) {
            break;
        }
        channelHandler = new ChannelHandler(this.socket, charset);
        channelActive(channelHandler);
    }

    @Override
    public void run() {
        try {
            BufferedReader input = new BufferedReader(new InputStreamReader(this.socket.getInputStream(), charset));
            String str = null;
            while ((str = input.readLine()) != null) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                channelRead(channelHandler, str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 链接通知抽象类
    public abstract void channelActive(ChannelHandler ctx);

    // 读取消息抽象类
    public abstract void channelRead(ChannelHandler ctx, Object msg);

}

其中channelActive通道建立方法和channelRead通道数据读取方法作为钩子方法供子类来提供各自场景下的具体实现。

接着,来定义具体的client类:

package com.dahuyou.io.model.bio.client;

import com.dahuyou.io.model.bio.ChannelAdapter;
import com.dahuyou.io.model.bio.ChannelHandler;
import java.net.Socket;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;

public class BioClientHandler extends ChannelAdapter {

    public BioClientHandler(Socket socket, Charset charset) {
        super(socket, charset);
    }

    @Override
    public void channelActive(ChannelHandler ctx) {
        System.out.println("链接报告LocalAddress:" + ctx.socket().getLocalAddress());
        ctx.writeAndFlush("hi! BioClient to msg for you \r\n");
    }

    @Override
    public void channelRead(ChannelHandler ctx, Object msg) {
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " 接收到消息:" + msg);
        ctx.writeAndFlush("hi, 我是client,我已经收到你的消息Success!\r\n");
    }

}

定义具体的server类:

package com.dahuyou.io.model.bio.server;

import com.dahuyou.io.model.bio.ChannelAdapter;
import com.dahuyou.io.model.bio.ChannelHandler;

import java.net.Socket;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;

public class BioServerHandler extends ChannelAdapter {

    public BioServerHandler(Socket socket, Charset charset) {
        super(socket, charset);
    }

    @Override
    public void channelActive(ChannelHandler ctx) {
        System.out.println("链接报告LocalAddress:" + ctx.socket().getLocalAddress());
        ctx.writeAndFlush("hi! BioServer to msg for you \r\n");
    }

    @Override
    public void channelRead(ChannelHandler ctx, Object msg) {
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " 接收到消息:" + msg);
        ctx.writeAndFlush("hi 我是server, 我已经收到你的消息Success!\r\n");
    }

}

接下来就可以定义server和client的服务启动类了,定义server启动类:

package com.dahuyou.io.model.bio.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;

//public class BioServer extends Thread {
public class BioServer {

    private ServerSocket serverSocket = null;

    public static void main(String[] args) {
        BioServer bioServer = new BioServer();
//        bioServer.start();
        bioServer.startServer();
    }

    private void startServer() {
        try {
            serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress(7397));

            System.out.println("bio server start suc!");
            while (true) {
                Socket socket = serverSocket.accept();
//                BioServerHandler handler = new BioServerHandler(socket, Charset.forName("GBK"));
                BioServerHandler handler = new BioServerHandler(socket, Charset.forName("UTF-8"));
                handler.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /*@Override
    public void run() {
        try {
            serverSocket = new ServerSocket();
            serverSocket.bind(new InetSocketAddress(7397));

            System.out.println("bio server start suc!");
            while (true) {
                Socket socket = serverSocket.accept();
//                BioServerHandler handler = new BioServerHandler(socket, Charset.forName("GBK"));
                BioServerHandler handler = new BioServerHandler(socket, Charset.forName("UTF-8"));
                handler.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }*/
}

定义client启动类:

package com.dahuyou.io.model.bio.client;

import java.io.IOException;
import java.net.Socket;
import java.nio.charset.Charset;

public class BioClient {

    public static void main(String[] args) {
        try {
            Socket socket = new Socket("192.168.10.91", 7397);
            System.out.println("bio client start suc!");

            BioClientHandler bioClientHandler = new BioClientHandler(socket, Charset.forName("utf-8"));
            bioClientHandler.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

运行server:
在这里插入图片描述
运行client:
在这里插入图片描述
运行过程中:
在这里插入图片描述
附UML图:
在这里插入图片描述

2:NIO

new io,是Java io中对多路复用IO模型的具体实现。

因为不管是server端还是client端,都需要发送消息给对端,所以我们先来定义一个通道的处理器类负责完成消息发送的工作:

package com.dahuyou.io.model.nio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;

public class ChannelHandler {

    private SocketChannel channel;
    private Charset charset;

    public ChannelHandler(SocketChannel channel, Charset charset) {
        this.channel = channel;
        this.charset = charset;
    }

    public void writeAndFlush(Object msg) {
        try {
            byte[] bytes = msg.toString().getBytes(charset);
            ByteBuffer writeBuffer = ByteBuffer.allocate(bytes.length);
            writeBuffer.put(bytes);
            writeBuffer.flip();
            channel.write(writeBuffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public SocketChannel channel() {
        return channel;
    }
}

再有就是client和server又是有所不同的,哪里不同呢?一个是通道建立成功是行为,以及读取到消息时的行为可能是不同的,所以再来定义一个适配器类来适配这些不同,并且在该类中依赖ChannleHandler,从而拥有向通道中发送消息的能力,代码如下:

package com.dahuyou.io.model.nio;

import java.io.IOException;
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.nio.charset.Charset;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.TimeUnit;

public abstract class ChannelAdapter extends Thread {

    private Selector selector;

    private ChannelHandler channelHandler;
    private Charset charset;

    public ChannelAdapter(Selector selector, Charset charset) {
        this.selector = selector;
        this.charset = charset;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
                selector.select(1000);  //Selects a set of keys whose corresponding channels are ready for I/O
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                Iterator<SelectionKey> it = selectedKeys.iterator();
                SelectionKey key = null;
                while (it.hasNext()) {
                    key = it.next();
                    it.remove();
                    handleInput(key);
                }
            } catch (Exception ignore) {
            }
        }
    }

    private void handleInput(SelectionKey key) throws IOException {
        if (!key.isValid()) return;

        // 客户端SocketChannel
        Class<?> superclass = key.channel().getClass().getSuperclass();
        if (superclass == SocketChannel.class){
            SocketChannel socketChannel = (SocketChannel) key.channel();
            if (key.isConnectable()) {
                if (socketChannel.finishConnect()) {
                    channelHandler = new ChannelHandler(socketChannel, charset);
                    channelActive(channelHandler);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                } else {
                    System.exit(1);
                }
            }
        }

        // 服务端ServerSocketChannel
        if (superclass == ServerSocketChannel.class){
            if (key.isAcceptable()) {
                ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
                SocketChannel socketChannel = serverSocketChannel.accept();
                socketChannel.configureBlocking(false);
                socketChannel.register(selector, SelectionKey.OP_READ);

                channelHandler = new ChannelHandler(socketChannel, charset);
                channelActive(channelHandler);
            }
        }

        if (key.isReadable()) {
            SocketChannel socketChannel = (SocketChannel) key.channel();
            ByteBuffer readBuffer = ByteBuffer.allocate(1024);
            int readBytes = socketChannel.read(readBuffer);
            if (readBytes > 0) {
                readBuffer.flip();
                byte[] bytes = new byte[readBuffer.remaining()];
                readBuffer.get(bytes);
                channelRead(channelHandler, new String(bytes, charset));
            } else if (readBytes < 0) {
                key.cancel();
                socketChannel.close();
            }
        }
    }

    // 链接通知抽象类
    public abstract void channelActive(ChannelHandler ctx);

    // 读取消息抽象类
    public abstract void channelRead(ChannelHandler ctx, Object msg);

}

其中channelActive通道建立方法和channelRead通道数据读取方法作为钩子方法供子类来提供各自场景下的具体实现。

接着,来定义具体的client处理器类,server处理器类:

package com.dahuyou.io.model.nio.client;

import com.dahuyou.io.model.nio.ChannelAdapter;
import com.dahuyou.io.model.nio.ChannelHandler;
import java.io.IOException;
import java.nio.channels.Selector;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;

public class NioClientHandler extends ChannelAdapter {

    public NioClientHandler(Selector selector, Charset charset) {
        super(selector, charset);
    }

    @Override
    public void channelActive(ChannelHandler ctx) {
        try {
            System.out.println("链接报告LocalAddress:" + ctx.channel().getLocalAddress());
            ctx.writeAndFlush("hi! NioClient to msg for you \r\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void channelRead(ChannelHandler ctx, Object msg) {
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " 接收到消息:" + msg);

        ctx.writeAndFlush("hi i am client, already receive your message!\r\n");
    }

}
package com.dahuyou.io.model.nio.server;

import com.dahuyou.io.model.nio.ChannelAdapter;
import com.dahuyou.io.model.nio.ChannelHandler;

import java.io.IOException;
import java.nio.channels.Selector;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Date;

public class NioServerHandler extends ChannelAdapter {

    public NioServerHandler(Selector selector, Charset charset) {
        super(selector, charset);
    }

    @Override
    public void channelActive(ChannelHandler ctx) {
        try {
            System.out.println("链接报告LocalAddress:" + ctx.channel().getLocalAddress());
            ctx.writeAndFlush("hi! NioServer to msg for you \r\n");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void channelRead(ChannelHandler ctx, Object msg) {
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + " 接收到消息:" + msg);
        ctx.writeAndFlush("hi i am nio server!\r\n");
    }

}

server,client main类:

package com.dahuyou.io.model.nio.client;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;

public class NioClient {

    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);

        boolean isConnect = socketChannel.connect(new InetSocketAddress("127.0.0.1", 7397));
        System.out.println("nio client started suc!");
        if (isConnect) {
            socketChannel.register(selector, SelectionKey.OP_READ);
        } else {
            socketChannel.register(selector, SelectionKey.OP_CONNECT);
        }
        new NioClientHandler(selector, Charset.forName("GBK")).start();
    }

}
package com.dahuyou.io.model.nio.server;

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.charset.Charset;

public class NioServer {

    private Selector selector;
    private ServerSocketChannel socketChannel;

    public static void main(String[] args) throws IOException {
        new NioServer().bind(7397);
        System.out.println("nio server started suc!");
    }

    public void bind(int port) {
        try {
            selector = Selector.open();
            socketChannel = ServerSocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.socket().bind(new InetSocketAddress(port), 1024);
            socketChannel.register(selector, SelectionKey.OP_ACCEPT);
            new NioServerHandler(selector, Charset.forName("GBK")).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

运行测试:
在这里插入图片描述
附UML图:
在这里插入图片描述

3:AIO

主要类:

AsynchronousServerSocketChannel:服务端的异步通道类
AsynchronousSocketChannel:客户端的异步通道类
CompletionHandler:事件回调规范接口,连接建立事件,消息可读事件等

所以,异步其实就是基于事件驱动的方式来进行编程了,到处都是回调这种,不是很符合人类的线性思维,需要习惯下。
整体代码结构和bio以及nio比较类似,不同之处在于server类,定义了初始化ChannelInitializer,来做一下初始化的工作,其中数据读取的监听类初始化如下:

public class AioServerChannelInitializer extends ChannelInitializer {

    @Override
    protected void initChannel(AsynchronousSocketChannel channel) throws Exception {
//        channel.read(ByteBuffer.allocate(1024), 10, TimeUnit.SECONDS, null, new AioServerHandler(channel, Charset.forName("GBK")));
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        channel.read(buffer, buffer, new AioServerHandler(channel, Charset.forName("GBK")));
    }

}

这样当有数据可读时就会调用AioServerHandler,当然AioServerHandler也是CompletionHandler的子类了,也是一个事件回调类。
server启动类如下:

public class AioServer extends Thread {

    private AsynchronousServerSocketChannel serverSocketChannel;

    @Override
    public void run() {
        try {
            serverSocketChannel = AsynchronousServerSocketChannel.open(AsynchronousChannelGroup.withCachedThreadPool(Executors.newCachedThreadPool(), 10));
            serverSocketChannel.bind(new InetSocketAddress(7397));
            System.out.println("dahuyou-study-netty aio server start done.");
            // 等待
            CountDownLatch latch = new CountDownLatch(1);
            // 通过AioServerChannelInitializer,初始化数据读取的处理器(实现了接口CompletionHandler)
            serverSocketChannel.accept(this, new AioServerChannelInitializer());
            // 防止退出
            latch.await();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public AsynchronousServerSocketChannel serverSocketChannel() {
        return serverSocketChannel;
    }

    public static void main(String[] args) {
        new AioServer().start();
    }

}

client启动类如下:

package com.dahuyou.io.model.aio.client;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.util.concurrent.Future;

public class AioClient {

    public static void main(String[] args) throws Exception {
        AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();
//        Future<Void> future = socketChannel.connect(new InetSocketAddress("127.0.0.1", 7397));
//        socketChannel.connect(new InetSocketAddress("127.0.0.1", 7397));
        // aio的a体现:指定一个回调类,建立连接成功时回调
        socketChannel.connect(new InetSocketAddress("127.0.0.1", 7397), null, new CompletionHandler<Void, Object>() {
            @Override
            public void completed(Void result, Object attachment) {
                System.out.println("connect to nio server suc!");
                ByteBuffer allocate = ByteBuffer.allocate(1024);
                socketChannel.read(allocate, allocate, new AioClientHandler(socketChannel, Charset.forName("GBK")));

            }

            @Override
            public void failed(Throwable exc, Object attachment) {

            }
        });

        System.out.println("dahuyou-study-netty aio client start done.");
//        future.get();
        // 读数据
        // clientChannel.read(readBuffer, readBuffer, new ReadHandler(clientChannel, latch));
//        socketChannel.read(ByteBuffer.allocate(1024), null, new AioClientHandler(socketChannel, Charset.forName("GBK")));
        Thread.sleep(10000000);
    }

}

运行cient输出:

dahuyou-study-netty aio client start done.
connect to nio server suc!
链接报告信息:/127.0.0.1:7397
nio client receive: congratulations, connected to aio server suc!

server对应输出:

dahuyou-study-netty aio server start done.
链接报告信息:/127.0.0.1:63537
nio server receive:nio client send back msg!

程序有点问题,就是,server只能给client发一个消息,用netassit测试也有这个问题,对这块不太熟,哪位大哥大姐有空帮给看看,发现问题还请留言告知,感谢!!!,问题对应的代码位置如下:
在这里插入图片描述

写在后面

参考文章列表

io之io分类和io模型 。

UML一一 类图关系 (泛化、实现、依赖、关联、聚合、组合) 。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaSE的【反射】和【动态代理】

作为JavaSE的两个个基础知识&#xff0c;【反射】和【动态代理】被广泛运用到spring、spring boot、mybatis......等等各种地方&#xff0c;等到后面的学习中反复提到这个知识点就会开始懵逼&#xff0c;而且这两个知识点其实也是紧密相连的&#xff0c;很多文章和课程里也并没…

零基础STM32单片机编程入门(三十七) MPU6050陀螺仪传感器详解及实战源码

文章目录 一.概要二.MPU6050芯片介绍1.MEMS传感器原理2.MPU6050芯片简介3.芯片引脚定义4.XYZ轴方向5.芯片内部框图6.芯片常用寄存器 三.MPU6050模块原理图及与模块接口定义使用四.STM32单片机驱动MPU6050读取加速度角速度值实验五.CubeMX工程源代码下载六.小结 一.概要 MPU605…

嵌入式面经篇六——寄存器与存储器

文章目录 前言一、寄存器与存储器1、ARM 的 31 个通用寄存器 R0~R15 中&#xff0c;程序计数器 PC 为 R15、程序链接寄存器 LR 为 R14、堆栈指针寄存器 SP 为 R13。2、寄存器掉电会丢失数据吗&#xff1f;3、NOR Flash 与 NAND Flash 的区别&#xff1f;4、SRAM、DRAM、SDRAM的…

使用Python创建省份城市地图选择器

在这篇博客中&#xff0c;我们将探讨如何使用Python创建一个简单而实用的省份城市地图选择器。这个项目不仅能帮助我们学习Python的基础知识&#xff0c;还能让我们了解如何处理JSON数据和集成网页浏览器到桌面应用程序中。 C:\pythoncode\new\geographicgooglemap.py 全部代码…

Camtasia 2024破解版安装教程+汉化补丁激活2024 破解版激活码

最近&#xff0c;我在网上冲浪的时候&#xff0c;发现了一款录屏软件——Camtasia 2024。它不仅功能丰富&#xff0c;而且操作简单&#xff0c;简直是我的录屏利器&#xff01;今天&#xff0c;我就来给大家分享一下这款软件的最新功能&#xff0c;让你们也感受一下它的魔力&am…

【LeetCode:3137. K 周期字符串需要的最少操作次数 | 哈希表 + 子串计数】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

政务网站(.gov)专用SSL/HTTPS证书

政府网站在选择SSL证书时不仅需要遵循网络安全法规以及密评整改&#xff0c;更要提升公众信任度。国产服务商提供的专业版SSL证书&#xff0c;全方位符合政务部门对SSL证书的要求 1 算法要求 政务服务网站需要落实等保制度、密评制度&#xff0c;在密码应用上可选择国密算法S…

从0到1教你搭建Android自动化python+appium环境(超详细~)

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 一、需要软件 1. JDK:JAVA安装后配置JDK环境 2. SDK:SDK下载后配置adb环境 3. Python:pyhton语言 4. Pycharm:python脚本编译工具 5. Appium-python-clien…

如何巧妙构建“LDAPS”服务器利用JNDI注入

前段时间看到群友问了这样一个问题&#xff1a; ldap:和rmi:关键字被拦截了&#xff0c;是否还可以进行JNDI注入。方法很简单&#xff0c;就是使用ldaps&#xff0c;但后来发现很多人并不知道怎么搭建LDAPS服务器&#xff0c;正好CoNote里有这个功能&#xff0c;写篇简单的文章…

【大模型】LLM工作原理简述

LLM&#xff0c;即large-language-model&#xff0c;大语言模型。 我们可以观察LLM大模型比如豆包在回复的时候&#xff0c;是不是一个一个字&#xff0c;行业里称之为流式输出的方式给你呈现内容的。为什么会这样呢&#xff1f;这是因为&#xff0c;大模型确实是在一个字一个…

Libero编译怪事(1)计数达不到目标值

最近在开发Libero工程&#xff0c;芯片是AGLN250V2。 其中一段计数的程序&#xff0c;声明了一个integer参数。当该参数大于某一值时&#xff0c;执行状态跳转。 编译烧写后&#xff0c;程序一直无法实现跳转。 以为是由于integer是有符号的&#xff0c;可能出现负值&#x…

IDEA中查看接口的所有实现类和具体实现类

1.IDEA中接口的所有实现类查看 1.CTRLH(hierarchy 结构) 我们选中要查看的接口 按住快捷键ctrlh 在界面右侧可以看到该接口的所有可能实现类 2.右击diagrams->show diagram 选中要查看的接口 右击选择diagrams->show diagram 即可以以图表的方式查看接口和所有实现类…

英智金融行业AI Agent,在金融领域全场景下的业务创新与应用实践

随着全球经济的数字化转型&#xff0c;金融行业也在迅速演变。传统的金融服务已经无法完全满足现代客户对快速、个性化和高效服务的需求。与此同时&#xff0c;市场竞争的加剧、监管环境的变化以及客户期望的提升&#xff0c;促使金融机构不断寻求新的技术来优化运营效率、提升…

设计模式---简单工厂模式

简单工厂模式&#xff08;Simple Factory Pattern&#xff09; 是一种创建型设计模式&#xff0c;它定义了一个工厂类&#xff0c;通过这个工厂类可以创建不同类型的对象。简单工厂模式的主要目的是将对象的创建逻辑集中在一个地方&#xff0c;简化客户端的代码&#xff0c;使得…

代码复现改进

代码复现&#xff0c;文献复现&#xff0c;文章复现&#xff0c; 算法复现&#xff0c;科研复现 Matlab,Python中英文均可 保证质量&#xff0c;加快你的研究速度 代码改进跑通&#xff0c;模型优化改进

Java - IDEA开发

使用IDEA开发Java程序步骤&#xff1a; 创建工程 Project&#xff1b;创建模块 Module&#xff1b;创建包 Package&#xff1b;创建类&#xff1b;编写代码&#xff1b; 如何查看JDK版本 Package介绍: package是将项目中的各种文件,比如源代码、编译生成的字节码、配置文件、…

Linux驱动开发基础(设备树)

所学来自百问网 目录 1. 引入设备树的原因 2. 设备树语法 2.1 Devicetree格式 2.1.1 DTS文件格式 2.1.2 node的格式 2.1.3 properties的格式 2.1.4 dts 文件包含dtsi文件 2.2 常用属性 2.2.1 #address-cells、#size-cells 2.2.2 compatible 2.2.3 model 2.2.4 st…

使用 Go 语言将 Base64 编码转换为 PDF 文件

使用Go语言将PDF文件转换为Base64编码-CSDN博客文章浏览阅读104次&#xff0c;点赞2次&#xff0c;收藏5次。本文介绍了如何使用 Go 语言将 PDF 文件转换为 Base64 编码&#xff0c;并保存到文件中。https://blog.csdn.net/qq_45519030/article/details/141224319 在现代编程中…

一、前后端分离通用权限系统(1)

&#x1f33b;&#x1f33b; 目录 一、项目介绍1.1 项目简介1.1.1 项目特色1.1.2 项目背景1.1.3 前置知识1.1.4 项目大纲 1.2 项目详细介绍1.2.1 介绍1.2.2 核心技术1.2.3 项目模块1.2.4 数据库设计 二、搭建环境2.1、搭建项目结构2.1.1、搭建父工程 gansu-auth-parent2.1.2、搭…

Unity 求坐标点在扇形区域内的投影

视频效果&#xff1a; 代码: /// <summary>/// 投影在扇形区域内的点/// </summary>/// <param name"targetPos">目标点</param>/// <param name"fanRadius">扇形半径</param>/// <param name"fanAngle"…