Netty 学习之旅:ByteBuf 篇之 ByteBuf 内部结构与 API 学习,java 免费视频网站
*/
public abstract boolean readBoolean();
/**
Gets a byte at the current {@code readerIndex} and increases
the {@code readerIndex} by {@code 1} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract byte readByte();
/**
Gets an unsigned byte at the current {@code readerIndex} and increases
the {@code readerIndex} by {@code 1} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract short readUnsignedByte();
/**
Gets a 16-bit short integer at the current {@code readerIndex}
and increases the {@code readerIndex} by {@code 2} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract short readShort();
/**
Gets an unsigned 16-bit short integer at the current {@code readerIndex}
and increases the {@code readerIndex} by {@code 2} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract int readUnsignedShort();
/**
Gets a 24-bit medium integer at the current {@code readerIndex}
and increases the {@code readerIndex} by {@code 3} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract int readMedium();
/**
Gets an unsigned 24-bit medium integer at the current {@code readerIndex}
and increases the {@code readerIndex} by {@code 3} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract int readUnsignedMedium();
/**
Gets a 32-bit integer at the current {@code readerIndex}
and increases the {@code readerIndex} by {@code 4} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract int readInt();
/**
Gets an unsigned 32-bit integer at the current {@code readerIndex}
and increases the {@code readerIndex} by {@code 4} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract long readUnsignedInt();
/**
Gets a 64-bit integer at the current {@code readerIndex}
and increases the {@code readerIndex} by {@code 8} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract long readLong();
/**
Gets a 2-byte UTF-16 character at the current {@code readerIndex}
and increases the {@code readerIndex} by {@code 2} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract char readChar();
/**
Gets a 32-bit floating point number at the current {@code readerIndex}
and increases the {@code readerIndex} by {@code 4} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract float readFloat();
/**
Gets a 64-bit floating point number at the current {@code readerIndex}
and increases the {@code readerIndex} by {@code 8} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract double readDouble();
/**
Transfers this buffer's data to a newly created buffer starting at
the current {@code readerIndex} and increases the {@code readerIndex}
by the number of the transferred bytes (= {@code length}).
The returned buffer's {@code readerIndex} and {@code writerIndex} are
{@code 0} and {@code length} respectively.
@param length the number of bytes to transfer
@return the newly created buffer which contains the transferred bytes
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf readBytes(int length);
/**
Returns a new slice of this buffer's sub-region starting at the current
{@code readerIndex} and increases the {@code readerIndex} by the size
of the new slice (= {@code length}).
@param length the size of the new slice
@return the newly created slice
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf readSlice(int length);
/**
Transfers this buffer's data to the specified destination starting at
the current {@code readerIndex} until the destination becomes
non-writable, and increases the {@code readerIndex} by the number of the
transferred bytes. This method is basically same with
{@link #readBytes(ByteBuf, int, int)}, except that this method
increases the {@code writerIndex} of the destination by the number of
the transferred bytes while {@link #readBytes(ByteBuf, int, int)}
does not.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf readBytes(ByteBuf dst);
/**
Transfers this buffer's data to the specified destination starting at
the current {@code readerIndex} and increases the {@code readerIndex}
by the number of the transferred bytes (= {@code length}). This method
is basically same with {@link #readBytes(ByteBuf, int, int)},
except that this method increases the {@code writerIndex} of the
destination by the number of the transferred bytes (= {@code length})
while {@link #readBytes(ByteBuf, int, int)} does not.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf readBytes(ByteBuf dst, int length);
/**
Transfers this buffer's data to the specified destination starting at
the current {@code readerIndex} and increases the {@code readerIndex}
by the number of the transferred bytes (= {@code length}).
@param dstIndex the first index of the destination
@param length the number of bytes to transfer
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf readBytes(ByteBuf dst, int dstIndex, int length);
/**
Transfers this buffer's data to the specified destination starting at
the current {@code readerIndex} and increases the {@code readerIndex}
by the number of the transferred bytes (= {@code dst.length}).
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf readBytes(byte[] dst);
/**
Transfers this buffer's data to the specified destination starting at
the current {@code readerIndex} and increases the {@code readerIndex}
by the number of the transferred bytes (= {@code length}).
@param dstIndex the first index of the destination
@param length the number of bytes to transfer
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf readBytes(byte[] dst, int dstIndex, int length);
/**
Transfers this buffer's data to the specified destination starting at
the current {@code readerIndex} until the destination's position
reaches its limit, and increases the {@code readerIndex} by the
number of the transferred bytes.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf readBytes(ByteBuffer dst);
/**
Transfers this buffer's data to the specified stream starting at the
current {@code readerIndex}.
@param length the number of bytes to transfer
@throws IndexOutOfBoundsException
《一线大厂 Java 面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》
【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享
}
@throws IOException
*/
public abstract ByteBuf readBytes(OutputStream out, int length) throws IOException;
/**
Transfers this buffer's data to the specified stream starting at the
current {@code readerIndex}.
@param length the maximum number of bytes to transfer
@return the actual number of bytes written out to the specified channel
@throws IndexOutOfBoundsException
@throws IOException
*/
public abstract int readBytes(GatheringByteChannel out, int length) throws IOException;
对于上面的方法,我挑如下三个进行重点说明一下,其他的类似:
public?abstract?ByteBuf?readBytes(byte[]?dst)
从 ByteBuf 缓存区中读取 dst.length 个字节到 dst 目标数组中,返回当前的 ByteBuf, 这是级联设计风格,如果 ByteBuf 可剩余可读字节小于 dst.length,则抛出异常。
??public?abstract?ByteBuf?readBytes(int?length)
从 ByteBuf 缓存区读取 length 个字节到新创建的 ByteBuf, 注意返回的 ByteBuf 是先创建的,这不是级联设计风格。
public?abstract?ByteBuf?readBytes(ByteBuf?dst)
从 ByteBuf 缓存区读取 ds t 可写字节长度到 dst 中,返回的 ByteBuf 是级联风格设计,如果 dst 的可剩余写长度大于操作的缓存区时,将抛出异常。
public?abstract?ByteBuf?readSlice(int?length)
从 ButeBuf 缓存区读取 length 个字节到 ByteBuf 中,这里的 ByteBuf 是原 ByteBuf 的视图,独立的 readIndex, writerIndex。
2.2.2 顺序写 API
/**
Sets the specified boolean at the current {@code writerIndex}
and increases the {@code writerIndex} by {@code 1} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeBoolean(boolean value);
/**
Sets the specified byte at the current {@code writerIndex}
and increases the {@code writerIndex} by {@code 1} in this buffer.
The 24 high-order bits of the specified value are ignored.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeByte(int value);
/**
Sets the specified 16-bit short integer at the current
{@code writerIndex} and increases the {@code writerIndex} by {@code 2}
in this buffer. The 16 high-order bits of the specified value are ignored.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeShort(int value);
/**
Sets the specified 24-bit medium integer at the current
{@code writerIndex} and increases the {@code writerIndex} by {@code 3}
in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeMedium(int value);
/**
Sets the specified 32-bit integer at the current {@code writerIndex}
and increases the {@code writerIndex} by {@code 4} in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeInt(int value);
/**
Sets the specified 64-bit long integer at the current
{@code writerIndex} and increases the {@code writerIndex} by {@code 8}
in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeLong(long value);
/**
Sets the specified 2-byte UTF-16 character at the current
{@code writerIndex} and increases the {@code writerIndex} by {@code 2}
in this buffer. The 16 high-order bits of the specified value are ignored.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeChar(int value);
/**
Sets the specified 32-bit floating point number at the current
{@code writerIndex} and increases the {@code writerIndex} by {@code 4}
in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeFloat(float value);
/**
Sets the specified 64-bit floating point number at the current
{@code writerIndex} and increases the {@code writerIndex} by {@code 8}
in this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeDouble(double value);
/**
Transfers the specified source buffer's data to this buffer starting at
the current {@code writerIndex} until the source buffer becomes
unreadable, and increases the {@code writerIndex} by the number of
the transferred bytes. This method is basically same with
{@link #writeBytes(ByteBuf, int, int)}, except that this method
increases the {@code readerIndex} of the source buffer by the number of
the transferred bytes while {@link #writeBytes(ByteBuf, int, int)}
does not.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeBytes(ByteBuf src);
/**
Transfers the specified source buffer's data to this buffer starting at
the current {@code writerIndex} and increases the {@code writerIndex}
by the number of the transferred bytes (= {@code length}). This method
is basically same with {@link #writeBytes(ByteBuf, int, int)},
except that this method increases the {@code readerIndex} of the source
buffer by the number of the transferred bytes (= {@code length}) while
{@link #writeBytes(ByteBuf, int, int)} does not.
@param length the number of bytes to transfer
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeBytes(ByteBuf src, int length);
/**
Transfers the specified source buffer's data to this buffer starting at
the current {@code writerIndex} and increases the {@code writerIndex}
by the number of the transferred bytes (= {@code length}).
@param srcIndex the first index of the source
@param length the number of bytes to transfer
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeBytes(ByteBuf src, int srcIndex, int length);
/**
Transfers the specified source array's data to this buffer starting at
the current {@code writerIndex} and increases the {@code writerIndex}
by the number of the transferred bytes (= {@code src.length}).
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeBytes(byte[] src);
/**
Transfers the specified source array's data to this buffer starting at
the current {@code writerIndex} and increases the {@code writerIndex}
by the number of the transferred bytes (= {@code length}).
@param srcIndex the first index of the source
@param length the number of bytes to transfer
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeBytes(byte[] src, int srcIndex, int length);
/**
Transfers the specified source buffer's data to this buffer starting at
the current {@code writerIndex} until the source buffer's position
reaches its limit, and increases the {@code writerIndex} by the
number of the transferred bytes.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeBytes(ByteBuffer src);
/**
Transfers the content of the specified stream to this buffer
starting at the current {@code writerIndex} and increases the
{@code writerIndex} by the number of the transferred bytes.
@param length the number of bytes to transfer
@return the actual number of bytes read in from the specified stream
@throws IndexOutOfBoundsException
@throws IOException
*/
public abstract int writeBytes(InputStream in, int length) throws IOException;
/**
Transfers the content of the specified channel to this buffer
starting at the current {@code writerIndex} and increases the
{@code writerIndex} by the number of the transferred bytes.
@param length the maximum number of bytes to transfer
@return the actual number of bytes read in from the specified channel
@throws IndexOutOfBoundsException
@throws IOException
*/
public abstract int writeBytes(ScatteringByteChannel in, int length) throws IOException;
/**
Fills this buffer with <tt>NUL (0x00)</tt> starting at the current
{@code writerIndex} and increases the {@code writerIndex} by the
specified {@code length}.
@param length the number of <tt>NUL</tt>s to write to the buffer
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf writeZero(int length);
重点强调一下如下方法,其他的类似。
public?abstract?ByteBuf?writeBytes(byte[]?src)
将字节数组 src 全部写入到缓存区中,如果 src.length 大于 ByteBuf 可写区域的话,会抛出异常。
2.2.3 随机读 API
/**
Gets a boolean at the specified absolute (@code index) in this buffer.
This method does not modify the {@code readerIndex} or {@code writerIndex}
of this buffer.
@throws IndexOutOfBoundsException
*/
public abstract boolean getBoolean(int index);
/**
Gets a byte at the specified absolute {@code index} in this buffer.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer.
@throws IndexOutOfBoundsException
*/
public abstract byte getByte(int index);
/**
Gets an unsigned byte at the specified absolute {@code index} in this
buffer. This method does not modify {@code readerIndex} or
{@code writerIndex} of this buffer.
@throws IndexOutOfBoundsException
*/
public abstract short getUnsignedByte(int index);
/**
Gets a 16-bit short integer at the specified absolute {@code index} in
this buffer. This method does not modify {@code readerIndex} or
{@code writerIndex} of this buffer.
@throws IndexOutOfBoundsException
*/
public abstract short getShort(int index);
/**
Gets an unsigned 16-bit short integer at the specified absolute
{@code index} in this buffer. This method does not modify
{@code readerIndex} or {@code writerIndex} of this buffer.
@throws IndexOutOfBoundsException
*/
public abstract int getUnsignedShort(int index);
/**
Gets a 24-bit medium integer at the specified absolute {@code index} in
this buffer. This method does not modify {@code readerIndex} or
{@code writerIndex} of this buffer.
@throws IndexOutOfBoundsException
*/
public abstract int getMedium(int index);
/**
Gets an unsigned 24-bit medium integer at the specified absolute
{@code index} in this buffer. This method does not modify
{@code readerIndex} or {@code writerIndex} of this buffer.
@throws IndexOutOfBoundsException
*/
public abstract int getUnsignedMedium(int index);
/**
Gets a 32-bit integer at the specified absolute {@code index} in
this buffer. This method does not modify {@code readerIndex} or
{@code writerIndex} of this buffer.
@throws IndexOutOfBoundsException
*/
public abstract int getInt(int index);
/**
Gets an unsigned 32-bit integer at the specified absolute {@code index}
in this buffer. This method does not modify {@code readerIndex} or
{@code writerIndex} of this buffer.
@throws IndexOutOfBoundsException
*/
public abstract long getUnsignedInt(int index);
/**
Gets a 64-bit long integer at the specified absolute {@code index} in
this buffer. This method does not modify {@code readerIndex} or
{@code writerIndex} of this buffer.
@throws IndexOutOfBoundsException
*/
public abstract long getLong(int index);
/**
Gets a 2-byte UTF-16 character at the specified absolute
{@code index} in this buffer. This method does not modify
{@code readerIndex} or {@code writerIndex} of this buffer.
@throws IndexOutOfBoundsException
*/
public abstract char getChar(int index);
/**
Gets a 32-bit floating point number at the specified absolute
{@code index} in this buffer. This method does not modify
{@code readerIndex} or {@code writerIndex} of this buffer.
@throws IndexOutOfBoundsException
*/
public abstract float getFloat(int index);
/**
Gets a 64-bit floating point number at the specified absolute
{@code index} in this buffer. This method does not modify
{@code readerIndex} or {@code writerIndex} of this buffer.
@throws IndexOutOfBoundsException
*/
public abstract double getDouble(int index);
/**
Transfers this buffer's data to the specified destination starting at
the specified absolute {@code index} until the destination becomes
non-writable. This method is basically same with
{@link #getBytes(int, ByteBuf, int, int)}, except that this
method increases the {@code writerIndex} of the destination by the
number of the transferred bytes while
{@link #getBytes(int, ByteBuf, int, int)} does not.
This method does not modify {@code readerIndex} or {@code writerIndex} of
the source buffer (i.e. {@code this}).
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf getBytes(int index, ByteBuf dst);
/**
Transfers this buffer's data to the specified destination starting at
the specified absolute {@code index}. This method is basically same
with {@link #getBytes(int, ByteBuf, int, int)}, except that this
method increases the {@code writerIndex} of the destination by the
number of the transferred bytes while
{@link #getBytes(int, ByteBuf, int, int)} does not.
This method does not modify {@code readerIndex} or {@code writerIndex} of
the source buffer (i.e. {@code this}).
@param length the number of bytes to transfer
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf getBytes(int index, ByteBuf dst, int length);
/**
Transfers this buffer's data to the specified destination starting at
the specified absolute {@code index}.
This method does not modify {@code readerIndex} or {@code writerIndex}
of both the source (i.e. {@code this}) and the destination.
@param dstIndex the first index of the destination
@param length the number of bytes to transfer
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length);
/**
Transfers this buffer's data to the specified destination starting at
the specified absolute {@code index}.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf getBytes(int index, byte[] dst);
/**
Transfers this buffer's data to the specified destination starting at
the specified absolute {@code index}.
This method does not modify {@code readerIndex} or {@code writerIndex}
of this buffer.
@param dstIndex the first index of the destination
@param length the number of bytes to transfer
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length);
/**
Transfers this buffer's data to the specified destination starting at
the specified absolute {@code index} until the destination's position
reaches its limit.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer while the destination's {@code position} will be increased.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf getBytes(int index, ByteBuffer dst);
/**
Transfers this buffer's data to the specified stream starting at the
specified absolute {@code index}.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer.
@param length the number of bytes to transfer
@throws IndexOutOfBoundsException
@throws IOException
*/
public abstract ByteBuf getBytes(int index, OutputStream out, int length) throws IOException;
/**
Transfers this buffer's data to the specified channel starting at the
specified absolute {@code index}.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer.
@param length the maximum number of bytes to transfer
@return the actual number of bytes written out to the specified channel
@throws IndexOutOfBoundsException
@throws IOException
*/
public abstract int getBytes(int index, GatheringByteChannel out, int length) throws IOException;
重点解读如下 API,其他类似。
public?abstract?ByteBuf?getBytes(int?index,?byte[]?dst,?int?dstIndex,?int?length)
从源 ByteBuf 的 index 处开始读 length 个字节到目标 byte 中,从 dstIndex 开始。
2.2.4 随机写 API
/**
Sets the specified boolean at the specified absolute {@code index} in this
buffer.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf setBoolean(int index, boolean value);
/**
Sets the specified byte at the specified absolute {@code index} in this
buffer. The 24 high-order bits of the specified value are ignored.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf setByte(int index, int value);
/**
Sets the specified 16-bit short integer at the specified absolute
{@code index} in this buffer. The 16 high-order bits of the specified
value are ignored.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf setShort(int index, int value);
/**
Sets the specified 24-bit medium integer at the specified absolute
{@code index} in this buffer. Please note that the most significant
byte is ignored in the specified value.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf setMedium(int index, int value);
/**
Sets the specified 32-bit integer at the specified absolute
{@code index} in this buffer.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf setInt(int index, int value);
/**
Sets the specified 64-bit long integer at the specified absolute
{@code index} in this buffer.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf setLong(int index, long value);
/**
Sets the specified 2-byte UTF-16 character at the specified absolute
{@code index} in this buffer.
The 16 high-order bits of the specified value are ignored.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf setChar(int index, int value);
/**
Sets the specified 32-bit floating-point number at the specified
absolute {@code index} in this buffer.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf setFloat(int index, float value);
/**
Sets the specified 64-bit floating-point number at the specified
absolute {@code index} in this buffer.
This method does not modify {@code readerIndex} or {@code writerIndex} of
this buffer.
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf setDouble(int index, double value);
/**
Transfers the specified source buffer's data to this buffer starting at
the specified absolute {@code index} until the source buffer becomes
unreadable. This method is basically same with
{@link #setBytes(int, ByteBuf, int, int)}, except that this
method increases the {@code readerIndex} of the source buffer by
the number of the transferred bytes while
{@link #setBytes(int, ByteBuf, int, int)} does not.
This method does not modify {@code readerIndex} or {@code writerIndex} of
the source buffer (i.e. {@code this}).
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf setBytes(int index, ByteBuf src);
/**
Transfers the specified source buffer's data to this buffer starting at
the specified absolute {@code index}. This method is basically same
with {@link #setBytes(int, ByteBuf, int, int)}, except that this
method increases the {@code readerIndex} of the source buffer by
the number of the transferred bytes while
{@link #setBytes(int, ByteBuf, int, int)} does not.
This method does not modify {@code readerIndex} or {@code writerIndex} of
the source buffer (i.e. {@code this}).
@param length the number of bytes to transfer
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf setBytes(int index, ByteBuf src, int length);
/**
Transfers the specified source buffer's data to this buffer starting at
the specified absolute {@code index}.
This method does not modify {@code readerIndex} or {@code writerIndex}
of both the source (i.e. {@code this}) and the destination.
@param srcIndex the first index of the source
@param length the number of bytes to transfer
@throws IndexOutOfBoundsException
*/
public abstract ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length);
/**
最后
在面试前我整理归纳了一些面试学习资料,文中结合我的朋友同学面试美团滴滴这类大厂的资料及案例
由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!
大家看完有什么不懂的可以在下方留言讨论也可以关注。
觉得文章对你有帮助的话记得关注我点个赞支持一下!
评论