Java基础知识(13)(包括网络编程,反射,动态代理)

Java基础知识(13)

(包括网络编程,反射,.动态代理)

目录

Java基础知识(13)

一.网络编程

1. 网络编程基础

(1)什么是网络编程

(2)应用场景:

(3)Java中可以使用java.net包下的技术轻松开发出常见的网络应用程序。

(4)常见的软件架构

(5)BS架构的优缺点

(6)CS架构的优缺点

2. 网络编程三要素

(1)简介

(2)IP

1) IPV4

2) IPv6

3)小结

4)IPv4的地址分类形式

5)InetAddress

(3)端口号

(4)协议

1)计算机网络中,连接和通信的规则被称为网络通信协议

2)TCP/IP参考模型

3)UDP协议

4)TCP协议

(5)UDP通信程序

1)发送数据

①步骤

②案例

2)接收数据

①步骤

②案例

(6) UDP的三种通信方式(代码实现)

1)单播:以前的代码就是单播(1对1发送)

2)组播

3)广播

(7)TCP通信程序

1)TCP通信协议简介

2)客户端

①创建客户端的Socket对象(Socket)与指定服务端连接

②获取输出流,写数据

③释放资源

④案例

3)服务器

①创建服务器端的Socket对象(Serversocket)

②监听客户端连接,返回一个Socket对象

③获取输入流,读数据,并把数据显示在控制台

④释放资源

⑤案例

4)TCP通信程序(三次握手)(确保连接建立)

5)TCP通信程序(四次挥手)(确保连接断开,且数据处理完毕)

二. 反射

1.基础知识

(1)反射:反射允许对成员变量,成员方法和构造方法的信息进行编程访问

(2)多种类

2. 获取class对象的三种方式

(1)分类

(2)案例

3. 利用反射获取构造方法

(1)Class类中用于获取构造方法的方法

(2)Constructor类中用于创建对象的方法

4. 利用反射获取成员变量

(1)Class类中用于获取成员变量的方法

(2)Field类中用于创建对象的方法

5. 利用反射获取成员方法

(1)Class类中用于获取成员方法的方法

(2)Method类中用于创建对象的方法

6. 反射的作用

三.动态代理

1.基础知识

(1)为什么需要代理?

(2)代理长什么样?

(3)Java通过什么来保证代理的样子?

2. 如何为Java对象创建一个代理对象

(1)方法

(2)案例

1)主体

2)创建代理


一.网络编程

1. 网络编程基础

(1)什么是网络编程

在网络通信协议下,不同计算机上运行的程序,进行的数据传输

(2)应用场景:

即时通信、网游对战、金融证券、国际贸易、邮件、等等

不管是什么场景,都是计算机跟计算机之间通过网络进行数据传输。

(3)Java中可以使用java.net包下的技术轻松开发出常见的网络应用程序。
(4)常见的软件架构

1)C/S: Client/Server客户端/服务器(需要安装)

2)B/S: Browser/Server浏览器/服务器(不需要安装)

(5)BS架构的优缺点

1)不需要开发客户端,只需要页面+服务端

2)用户不需要下载,打开浏览器就能使用

3)但如果应用过大,用户体验受到影响

(6)CS架构的优缺点

1)画面可以做的非常精美,用户体验好

2)需要开发客户端,也需要开发服务端

3)用户需要下载和更新的时候太麻烦

2. 网络编程三要素

(1)简介

IP:设备在网络中的地址,是唯一的标识,

端口号:应用程序在设备中唯一的标识

协议:数据在网络中传输的规则,常见的协议有UDP、TCP、http、https、ftp。

(2)IP

全称:Internet Protocol,是互联网协议地址,也称IP地址,是分配给上网设备的数字标签。

通俗理解:上网设备在网络中的地址,是唯一的

常见的IP分类为:IPv4、IPv6

1) IPV4

全称:Internet Protocolversion4,互联网通信协议第四版。

采用32位地址长度,分成4组

2) IPv6

全称:InternetProtocolversion6,互联网通信协议第六版。

由于互联网的蓬勃发展,IP地址的需求量愈来愈大,而IPv4的模式下IP的总数是有限的。

采用128位地址长度,分成8组。

3)小结

①IP的作用

设备在网络中的地址,是唯一的标识

②IPv4有什么特点

目前的主流方案

最多只有2^32次方个ip,目前已经用完了

③IPv6有什么特点

为了解决IPv4不够用而出现的

最多有2^128次方个ip

可以为地球上的每一粒沙子都设定ip

4)IPv4的地址分类形式

①公网地址(万维网使用)和私有地址(局域网使用)。

②192.168.开头的就是私有址址,范围即为192.168.0.0--192.168.255.255,专门为组织机构内部使用,以此节省IP

③特殊IP地址

127.0.0.1,也可以是localhost:是回送地址也称本地回环地址,也称本机IP,永远只会寻找当前所在本机。

5)InetAddress

static InetAddress getByName(string host):确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址

String getHostName() 获取此IP地址的主机名

String getHostAddress() 返回文本显示中的IP地址字符串

//1.获取InetAddress的对象

//IP的对象 一台电脑的对象

InetAddress address = InetAddress.getByName("z");

System.out.println(address); //192.168.1.108

String name = address.getHostName();

System.out.println(name)://z

String ip = address.getHostAddress();

System.out.println(ip)://192.168.1.108

(3)端口号

1)应用程序在设备中唯一的标识。

2)端口号:由两个字节表示的整数,取值范围:0~65535,其中0~1023之间的端口号用于一些知名的网络服务或者应用。我们自己使用1024以上的端口号就可以了。

3)注意:一个端口号只能被一个应用程序使用,

(4)协议
1)计算机网络中,连接和通信的规则被称为网络通信协议

①OSI参考模型:世界互联协议标准,全球通信规范,单模型过于理想化,未能在因特网上进行广泛推厂

②TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。

2)TCP/IP参考模型

应用层 HTTP、FTP、Telnet、 DNs...

传输层 TCP、 UDP.

网络层 TCP、 UDP.

物理链路层 硬件设备010101010101

3)UDP协议

①用户数据报协议(User Datagram Protocol)

②UDP是面向无连接通信协议。速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据

4)TCP协议

①传输控制协议TCP(Transmission Control Protocol)

②TCP协议是面向连接的通信协议。速度慢,没有大小限制,数据安全

(5)UDP通信程序
1)发送数据
①步骤

创建发送端的DatagramSocket对象

数据打包(DatagramPacket)

发送数据

释放资源

②案例

//1.创建Datagramsocket对象(快递公司)

/细节:

//绑定端口,以后我们就是通过这个端口往外发送

//空参:所有可用的端口中随机一个进行使用

//有参:指定端口号进行绑定

DatagramSocket ds=new DatagramSocket();

//2.打包数据

String str="你好!!!"

bytell bytes = str.getBytes();

InetAddress address = InetAddress.getByName("127.0.0.1");

int port = 10086;

DatagramPacket dp = new DatagramPacket (bytes, bytes.length, address, port),

//3.发送数据

ds.send(dp);

//4.释放资源

ds.close();

2)接收数据
①步骤

创建接收端的Datagramsocket对象

接收打包好的数据

解析数据包

释放资源

②案例

//1.创建Datagramsocket对象(快递公司)

//细节:

//在接收的时候,一定要绑定端口

//而且绑定的端口一定要跟发送的口保持一致

DatagramSocket ds=new DatagramSocket( port: 10086);

//2.接收数据包

bytel] bytes = new byte[1024];

DatagramPacket dp= new DatagramPacket(bytes,bytes.length),

//该方法是阻寒的(receive)

//程序执行到这一步的时候,会在这里死等

//等发送端发送消息

ds .receive(dp);

//3.解析数据包

bytel] data = dp.getData();

int len = dp.getLength();

InetAddress address = dp.getAddress();

int port = dp.getPort();

System.out.println("按收数据"+ new string(data,offset: 0,len));

System.out.print1n("该数据是从"+ address +"这台电脑中的"+ port +"这个端口发出的");

//4.释放资源

ds.close();

(6) UDP的三种通信方式(代码实现)
1)单播:以前的代码就是单播(1对1发送)
2)组播

组播地址:224.0.0.0~239.255.255.255

其中224.0.0.0~224.0.0.255为预留的组播地址

接收代码跟以前几乎一样,只是要指定组播地址

InetAddress address = InetAddress.getByName("224.0.0.1“);

接收代码多了一步

//2.将将当前本机,添加到224.0.0.1的这一组当中

InetAddress address = InetAddress.getByName("224.0.0.1");

ms.joinGroup(address);

3)广播

广播地址:255.255.255.255

接收代码跟以前几乎一样,只是要指定组播地址

InetAddress address = InetAddress.getByName("255.255.255.255“);

发送代码跟以前一样

(7)TCP通信程序
1)TCP通信协议简介

TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象

通信之前要保证连接已经建立

通过Socket产生I0流来进行网络通信

2)客户端
①创建客户端的Socket对象(Socket)与指定服务端连接

Socket(string host, int port)

②获取输出流,写数据

Outputstream getoutputstream()

③释放资源

void close()

④案例

//TCP协议,发送数据

//1.创建socket对象

//细节:在创建对象的同时会连接服务端,如果连接不上,代码会报错

Socket socket = new Socket( host:"127.0.0.1",port: 10000);

//2.可以从连接通道中获取输出流

Outputstream os=socket.getoutputstream();

//写出数据

os.write("你好你好".getBytes());(不能传中文)

//3.释放资源

os.close();

socket.close();

3)服务器
①创建服务器端的Socket对象(Serversocket)

Serversocket(int port)

②监听客户端连接,返回一个Socket对象

Socket accept()

③获取输入流,读数据,并把数据显示在控制台

Inputstream getInputstream()

④释放资源

void close()

⑤案例

//TCP协议,接收数据

//1.创建对象serversocker

ServerSocketss =new serverSocket( port:10080);

//2.监听客户端的链接

Socket socket= ss.accept();

//3.从连接通道中获取输入流读取数据

Inputstream is = socket.getInputStream();

InputstreamReader isr =new InputstreamReader(is);

int b;

while((b=isr.read())!=-1){

System.out.print((char)b);

//4.释放资源

socket.close();

ss.close();

4)TCP通信程序(三次握手)(确保连接建立)

①客户端向服务器发出连接请求,等待服务器确认

②服务器向客户端返回一个响应,告诉客户端收到了请求

③客户端向服务器再次发出确认信息,连接建立

5)TCP通信程序(四次挥手)(确保连接断开,且数据处理完毕)

①客户端向服务器发出取消连接请求

②服务器向客户端返回一个响应,表示收到客户端取消请求(服务器将最后的数据,处理完毕)

③服务器向客户端发出确认取消信息

④客户端再次发送确认消息,连接取消

二. 反射

1.基础知识

(1)反射:反射允许对成员变量,成员方法和构造方法的信息进行编程访问
(2)多种类

获取class对象 Class

构造方法 Constructor

字段(成员变量) Field

成员方法 Method

2. 获取class对象的三种方式

(1)分类

Class.forName("全类名");

类名.class

对象.getclass();

(2)案例

//1.第一种方式

//全类名: 包名 +名

//最为常用的

Class clazz1 =class,forName("com,itheima.myreflect1.student");

//2.第二种方式

//一般更多的是当做参数进行传递

Class clazz2 = Student,class;

//3.第三种方式

//当我们已经有了这个类的对象时,才可以使用。

student s= new student();

Class clazz3=s.getclass();

3. 利用反射获取构造方法

(1)Class类中用于获取构造方法的方法

①Constructor<?>[]getConstructors():返回所有公共构造方法对象的数组

②Constructor<?>[]getDeclaredConstructors():返回所有构造方法对象的数组(包括私有)

③Constructor<T>getConstructor(Class<?>... parameterTypes):返回单个公共构造方法对象

④Constructor<T>getDeclaredConstructor(Class<?>.. parameterTypes):返回单个构造方法对象(包括私有)

⑤案例

Class clazz= Class.forName("com.itheima.myreflect2.student");

Constructor[]cons1=clazz.getconstructors();

for(constructor con:cons1){

System.out.println(con);

Constructor con2=clazz.getDeclaredconstructor(string.class);

(2)Constructor类中用于创建对象的方法

①T newInstance(Object...initargs):根据指定的构造方法创建对象

②setAccessible(boolean flag):设置为true,表示取消访问检查

③案例

//暴力反射:表示临时取消权限校验(可以使用私有构造)

con4.setAccessible(true);

Student stu=(student)con4.newInstance("张”,23);

System.out.printin(stu);

4. 利用反射获取成员变量

(1)Class类中用于获取成员变量的方法

①Field[]getFields():返回所有公共成员变量对象的数组

②Field[}getDeclaredFields():返回所有成员变量对象的数组

③Field getField(String name): 返回单个公共成员变量对象

④Field getDeclaredField(String name):返回单个成员变量对象

⑤案例

//获取单个的成员变量

Field name= clazz.getDeclaredField( name:"name");

System.out.println(name);

//获取权限修饰符

int modifiers = name.getModifiers(),

System.out.println(modifiers);

//获取成员变量的名字

String n= name.getName();

System.out.println(n);

//获取成员变量的数据类型

Class<?> type = name.getType();

System.out.printin(type);

//获取成员变量记录的值

Student s= new student( name:"zhangsan",age: 23, gender:"”");

name.setAccessible(true);

String value =(string) name.get(s);

System.out.println(value);

//修改对象里面记录的值

name.set(s,"lisi");

(2)Field类中用于创建对象的方法

①void set(Object obj, Object value):赋值

②Object get(Object obj)获取值。

5. 利用反射获取成员方法

(1)Class类中用于获取成员方法的方法

①Method[lgetMethods():返回所有公共成员方法对象的数组,包括继承的

②Method[]getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的

③Method getMethod(String name, Class<?>.. parameterTypes):返回单个公共成员方法对象

④Method getDeclaredMethod(String name, Class<?>.. parameterTypes):返回单个成员方法对象

⑤案例

(2)Method类中用于创建对象的方法

①Object invoke(Object obj, Object..args):运行方法

参数一:用obi对象调用该方法

参数二:调用方法的传递的参数(如果没有就不写)

返回值:方法的返回值(如果没有就不写)

②一系列get…方法。

③案例

student s= new student();

m.setAccessible(true);

//参数一s:表示方法的调用者

//参数二"汉堡包":表示在调用方法的时候传递的实际参数

Object result =m.invoke(s,"汉堡包");

System.out.printin(result);

6. 反射的作用

①获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑

②结合配置文件,动态的创建对象并调用方法

三.动态代理

1.基础知识

(1)为什么需要代理?

代理可以无侵入式的给对象增强其他的功能

调用者 -> 代理 -> 对象

(2)代理长什么样?

代理里面就是对象要被代理的方法

(3)Java通过什么来保证代理的样子?

通过接口保证,后面的对象和代理需要实现同一个接口

接口中就是被代理的所有方法

2. 如何为Java对象创建一个代理对象

(1)方法

java.lang.reflect.Proxy类:提供了为对象产生代理对象的方法:

public static object newProxyInstance(classLoader loader, Class<?>[] interfaces, InvocationHandler h)

参数一:用于指定用哪个类加载器,去加载生成的代理类

参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法

参数三:用来指定生成的代理对象要于什么事情

(2)案例
1)主体

需求:

外面的人想要大明星唱一首歌

①获取代理的对象:代理对象 = ProxyUtil.createProxy(大明星的对象);

②再调用代理的唱歌方法:代理对象.唱歌的方法("只因你太美")

//1.获取代理的对象

Bigstar bigstar = new Bigstar( name:"鸡拼");

star proxy= ProxyUtil.createProxy(bigstar);

//2.调用唱歌的方法

String result = proxy.sing( "只内你太美");

System.out.println(result);

2)创建代理

public static star createProxy(Bigstar bigstar){

Star star=(star)Proxy.newProxyInstance(

Proxyuti1.class.getclassLoader(),//参数一:用于指定用哪个类加载器,去加载生成的代理类

new class[]{star.class},//参数二:指定接口,这些接口用于指定生成的代理长什么,也就是有哪些方法

//参数三:用来指定生成的代理对象要干什么事情

new InvocationHandler(){

@override

public object invoke(object proxy, Method method, object[] args) throws Throwable {

*参数一:代理的对象

*参数二:要运行的方法 sing

*参数三:调用sing方法时,传递的实参

if("sing".equals(method.getName())){

System.out.println("准备话简,收钱”);

}else if("dance".equals(method.getName())){

System.out.println("准备场地,收钱”);

//去找大明星开始唱歌或者跳舞

//代码的表现形式:调用大明星里面唱歌或者跳舞的方法

return method.invoke(bigstar,args);

}

}

};

Return star;

}

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

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

相关文章

项目构思以及相关ER图

首先是登录界面&#xff0c;我们首先绘制一个界面&#xff0c;在界面里面存储两个文本框&#xff0c;用于读取用户输入的文本&#xff0c;然后由客户端传到服务器里面和数据库进行对比&#xff0c;如果密码和账号对应的时候就可以进入到学习通的主界面 注册&#xff0c;首先注…

内网工具之ADFind的使用

ADFind是一款C语言编写的域中信息查询工具&#xff0c;可以在域中任何一台主机上使用&#xff0c;在内网渗透中的使用率较高 下载地址&#xff0c;该地址下载工具不需要压缩包密码 https://github.com/mai-lang-chai/AD-Penetration-Testing-Tools/blob/master/AdFind.zip参数…

什么是 IIS

什么是 IIS 一、什么是 IIS二、IIS 的功能三、IIS 几点说明四、IIS 的版本五、IIS 常见的组合 欢迎关注【云边小网安】 一、什么是 IIS IIS&#xff1a;指 Internet Information Services &#xff0c;是一种由微软公司开发的 Web 服务器应用程序。IIS&#xff1a;是一种 Web …

【busybox记录】【shell指令】ls

目录 内容来源&#xff1a; 【GUN】【ls】指令介绍 【busybox】【ls】指令介绍 【linux】【ls】指令介绍 使用示例-默认输出&#xff1a; 列出目录内容 - 默认输出 列出目录内容 - 不忽略以.开头的文件 列出目录内容 - 不忽略以.开头的文件&#xff0c;只忽略.和..文件…

猜猜歇后语

页面 在输入框中填写你猜的答案&#xff0c;点击“显示答案”按钮&#xff0c;显示正确答案。 页面代码 function showAnswer(element){var elem$(element);elem.next().show();} //# // 初始化DataGrid对象 $(#dataGrid).dataGrid({searchForm: $(#searchForm),columnModel:…

effective c++ 和 more effective c++中知识点

Effective C 视 C 为一个语言联邦&#xff08;C、Object-Oriented C、Template C、STL&#xff09; 宁可以编译器替换预处理器&#xff08;尽量以 const、enum、inline 替换 #define&#xff09; 编译器可以进行类型检查&#xff0c;避免预处理宏可能导致的类型错误。而且比预…

Webstorm免费安装教程

一、介绍 WebStorm 具有智能化的代码编辑功能&#xff0c;如代码补全、重构、代码导航、错误检测等等&#xff0c;这些功能可以帮助开发人员提高编码效率&#xff0c;减少出错的可能性。同时&#xff0c;WebStorm 也集成了各种流行的前端框架和库&#xff0c;如 React、Angula…

每日OJ题_贪心算法四④_力扣397. 整数替换

目录 力扣397. 整数替换 解析代码 力扣397. 整数替换 397. 整数替换 难度 中等 给定一个正整数 n &#xff0c;你可以做如下操作&#xff1a; 如果 n 是偶数&#xff0c;则用 n / 2替换 n 。如果 n 是奇数&#xff0c;则可以用 n 1或n - 1替换 n 。 返回 n 变为 1 所需…

1057: 有向图的出度计算

解法&#xff1a; #include<iostream> using namespace std; int arr[100][100]; int main() {int vertex, edge;cin >> vertex >> edge;int i, j;while (edge--) {cin >> i >> j;arr[i][j] 1;}for (int i 0; i < vertex; i) {int sum 0;…

【Java难点】多线程-高级

悲观锁和乐观锁 悲观锁 synchronized关键字和Lock的实现类都是悲观锁。 它很悲观&#xff0c;认为自己在使用数据的时候一定有别的线程来修改数据&#xff0c;因此在获取数据的时候会一不做二不休的先加锁&#xff0c;确保数据不会被别的线程修改。 适合写操作多的场景&…

TypeScript学习日志-第二十四天(webpack构建ts+vue3)

webpack构建tsvue3 一、构建项目目录 如图&#xff1a; shim.d.ts 这个文件用于让ts识别.vue后缀的 后续会说 并且给 tsconfig.json 增加配置项 "include": ["src/**/*"] 二、基础构建 安装依赖 安装如下依赖&#xff1a; npm install webpack -D …

Vue简介

Vue.js 是一款流行的 JavaScript 前端框架&#xff0c;用于构建用户界面和单页面应用程序&#xff08;SPA&#xff09;。它的核心库专注于视图层的渲染&#xff0c;同时也提供了诸如路由(VueRouter)、状态管理(Vuex,Pinia)等功能的插件&#xff0c;使得开发复杂的交互式应用变得…

ACC-UNet: A Completely Convolutional UNet Model for the 2020s

文章目录 ACC-UNet: A Completely Convolutional UNet Model for the 2020s摘要方法实验结果 ACC-UNet: A Completely Convolutional UNet Model for the 2020s 摘要 这十年以来&#xff0c;计算机视觉领域引入了 Vision Transformer&#xff0c;标志着广泛的计算机视觉发生了…

基于SpringBoot+Vue社区老人健康信息管理系统

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统社区老人健康信息管理系统信息管理难度大&#xff0c;容错…

Linux上的监控工具:Zabbix、Prometheus、APM和ELK

2024年5月12日&#xff0c;周日上午 在Linux上有很多监控工具&#xff0c;比如Zabbix、Prometheus、APM和ELK 监控工具是确保系统稳定运行的关键组件之一&#xff0c;它可以帮助系统管理员和开发人员及时发现并解决问题。 以下是几种流行的监控工具的简要介绍&#xff1a; Z…

JETBRAINS IDES 分享一个2099通用试用码!IDEA 2024 版 ,支持一键升级

文章目录 废话不多说上教程&#xff1a;&#xff08;动画教程 图文教程&#xff09;一、动画教程激活 与 升级&#xff08;至最新版本&#xff09; 二、图文教程 &#xff08;推荐&#xff09;Stage 1.下载安装 toolbox-app&#xff08;全家桶管理工具&#xff09;Stage 2 : 下…

vs2019 STL库里 判断函数类型的模板 is_function_v 与 is_const_v

&#xff08;1&#xff09;源代码如下&#xff1a; 经简单代码测试后&#xff0c;得出 vs2019 的 c 编译器 和 其 STL 库的观点与设计&#xff1a;is_const_v 用来判断类型 T 内是否含有 const 修饰符&#xff0c;含有 const 则返回真。但若 T 是含有 const 的引用类型&#xf…

链表与顺序表的比较

目录 1.链表与顺序表的区别 1.1 存储空间 1.2 插入删除 1.3 扩容 1.4 使用场景 1.5 缓存使用率 1.链表与顺序表的区别 1.1 存储空间 顺序表在物理上与逻辑上都是连续的 链表在逻辑上连续物理不一定连续 因此顺序表我们可以任意访问而链表不可以随机访问 链表每次访问都…

什么是XXE漏洞,日常如何做好web安全,避免漏洞威胁

随着网络技术的不断发展&#xff0c;网站安全问题日益受到人们的关注。当前随着技术发展&#xff0c;网站存在一些常见的可能被攻击者利用的漏洞&#xff0c;而在众多网站安全漏洞中&#xff0c;XXE&#xff08;XML External Entity&#xff09;漏洞是一个不容忽视的问题。今天…

Sass深度解析:性能优化的秘密

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…