一、serialVersionUID、Externalizable
- 在Java中,软件的兼容性是一个大问题,尤其在使用到对象串行性的时候,那么在某一个对象已经被串行化了,可是这个对象又被修改后重新部署了,那么在这种情况下, 用老软件来读取新文件格式虽然不是什么难事,但是有可能丢失一些信息。 serialVersionUID来解决这些问题,新增的serialVersionUID必须定义成下面这种形式:
static final long serialVersionUID=-12345678L;
- 其中数字后面加上的L表示这是一个long值。 通过这种方式来解决不同的版本之间的串行话问题,如果serialVersionUID不同,则defalutReadObject()不能正常执行,即如果类的serialVersionUID和序列化对象中的serialVersionUID不一致,则说明版本不兼容,不能完成序列化,这在一些需要强制用户进行版本升级的场景非常重要,因为在这种情况下Java会抛出InvalidClassException,可以在异常处理中进行升级操作
- 如果我们不显式提供serialVersionUID的值,则Java会根据以下几个属性进行自动计算: 改动上述任意一项内容(无论是增加或删除),都会引起编码值变化,从而引起类似的异常警报。这个数字序列称为“串行化版本统一标识符”(serial version universal identifier),简称UID。解决这个问题的办法是在类里面新增一个域serialVersionUID,强制类仍旧使用原来的UID
- 类的名字
- 属性字段的名字
- 方法的名字
- 已实现的接口
- 无论是使用transient关键字,还是使用writeObject()和readObject()方法,其实都是基于Serializable接口的序列化
- JDK中还提供了另一个序列化接口:Externalizable,使用该接口之后,之前基于Serializable接口的序列化机制就将失效,对象将按照我们自定义的方式进行序列化或反序列化,这对于一些信息敏感应用或对序列化反序列化性能要求较高来说非常重要
- Externalizable继承于Serializable,当使用该接口时,序列化的细节需要由我们自己完成
- 另外,使用Externalizable进行序列化时,当读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。由于这个原因,实现Externalizable接口的类必须要提供一个无参的构造器,且它的访问权限为public
- Java中对象序列化的一般方法是什么?
- 在Java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化,将对象的状态信息保存到流中的操作,称为序列化,可以使用Java提供的工具ObjectOutputStream. writeObject(Serializable obj)来完成,从流中读取对象状态信息的操作称为反序列化,可以使用Java提供的工具ObjectInputStream.readObject()来完成
二、NIO
NIO和IO最大的区别就是:IO是面向流的,NIO是面向(缓冲区)的。
JavaIO面向流就意味着每次从流中读取一个或多个字节,直至读取所有字节,他们没有被缓存在任何地方。此外,他不能前后移动流中的数据。如果需要前后移动流中的数据,就需要先将它缓存到一个缓冲区。
JavaNIO的缓冲导向方法略有不同。数据读取到一个他稍后处理的缓冲区,需要时可在缓冲区中前后移动,这就增加了处理过程中的灵活性。
JavaNIO中的Buffer用于和NIO通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中。
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIOBuffer对象,并提供了一组方法,用来方便的访问该块内存。
JavaNIO的通道类似流,但又有些不同:
即可以从通道中读取数据,又可以写数据到通道。但流的读写通常是单向的
通道可以异步的读写
通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入
JavaNIO的事件选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,是的一个单独的线程很容易来管理多个通道。
由于有了事件选择器,因此NIO可以以非阻塞的方式读取数据
1 package com.chinasofti.nio; 2 3 import java.io.*; 4 import java.nio.channels.FileChannel; 5 6 public class NioTest { 7 public static void main(String[] args) throws IOException { 8 Long before = System.currentTimeMillis(); 9 File file = new File("D:\icss\Java0715\20200715\01-课堂视频\06-java特点.wmv"); 10 FileChannel in = new FileInputStream(file).getChannel(); 11 FileChannel out = new FileOutputStream("D:\icss\Java0715\20200715\copy.wmv").getChannel(); 12 13 in.transferTo(0,file.length(),out); 14 15 Long after = System.currentTimeMillis(); 16 System.out.println(after-before); 17 out.close(); 18 in.close(); 19 } 20 }
三、网络编程
TCP/IP协议栈包含了一系列构成互联网基础的网络协议:
TCP(传输控制协议):Transmission Control Prorocol,是一种面向连接的、可靠的、基于字节流的传输层通信协议。
UDP(用户数据报协议):User Datagram Protocol,用于处理数据包,是一种无连接、不可靠的通信协议。
IP(网络协议):Internet Protocol,把数据从源传送到目的地,他不负责保证传送的可靠性、流控制、包顺序等。
ICMP(网络控制报文协议):Internet Control Message Protocol,是TCP/IP协议栈的一个子协议,用于在IP主机、路由器之间传递控制消息。
TCP/IP协议栈包含了一系列构成互联网基础的网络协议:
IGMP(网际组报文协议):Internet Group Management Protocol,是一个组播协议,运行在主机和组播路由器之间。
ARP(地址解析协议):Address Resolution Protocol,根据IP地址获取物理地址的协议。
HTTP(超文本传输协议):HyperText Transfer Protocol,用于从www服务器传输超文本到本地浏览器的传输协议,他可以使浏览器更加高效,使网络传输减少。
FTP(文本传输协议):File Transfer Protocol,用于Internet上的控制文件的双向传输。
- 为了确定网络区域,分开主机和路由器的每个接口,从而产生了若干个分离的网络岛,接口端连接了这些独立网络的端点。这些独立的网络岛叫做子网(subnet);
- 网络中的每一个计算机都有一个IP地址,IP地址由四个数字表示,包括网络号和主机号两部分;例如172.16.1.101,其中172.16.1是网络号,也是常说的网段,101是主机号;网络号标识的就是Internet上的一个子网;只有在一个子网中计算机之间才能“直接”互通;
- 划分子网可以使得网络管理更为容易;
四、TCP和UDP的区别
- TCP是面向连接的协议,在正式收发数据前,必须和对方建立可靠的连接,所以速度会慢;UDP是面向无连接的协议,不与对方建立连接,而是直接就发送数据包,相对速度快;
- TCP提供IP环境下的数据可靠传输,保证数据无差错的、按照顺序的进行传输;UDP的传输是不可靠的,不保证数据正确,不保证顺序等,也可能丢包;
- TCP使用字节流模式发送数据,UDP使用数据报模式;
- TCP适用对可靠性要求高的应用环境;UDP适用于一次只传送少量数据、对可靠性要求不高的应用环境;
- HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议;
- 1960年美国人Ted Nelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),这成为了HTTP超文本传输协议标准架构的发展根基
- 设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法;
HTTP协议是互联网上使用最广泛的一种协议;
五、请求方式
- 当我们在浏览器地址栏中输入一个网址(URL)并按下回车键时,或者点击网页上的超级链接时,或者在网页上填写一个表单点击了提交按钮时,都称为“向服务器端提交了一次HTTP请求”;
- HTTP协议中定义了多种请求方式,常用的请求方式有:
- GET:最常见的一种请求方式,当客户端要从服务器中读取文档时,当点击网页上的链接或者通过在浏览器的地址栏输入网址来浏览网页的,使用的都是GET方式。
- POST:POST方法可以允许客户端给服务器提供信息较多。POST方法将请求参数封装在HTTP请求数据中,以名称/值的形式出现,可以传输大量数据。使用表达提交基本都用POST方式。
- HEAD:HEAD和GET类似,只不过服务端接受到HEAD请求后只返回响应头,而不会发送响应内容。
get:明文提交,会把数据以?表达式的方式拼接到url地址栏之后进行提交 数据量比较小 相对不安全 快一些
post密文提交,地址栏没有信息可以查看,现今所有的数据都可以提交 相对安全 慢一些
- HTTP请求信息由请求行、请求头部、空行和请求数据四个部分组成;
HTTP响应也由四个部分组成,分别是:状态行、响应头部、空行、响应正文
- 请求信息中,包含请求头信息,HTTP协议定义了一系列的请求属性,部分如下:
- Accept:浏览器可接受的MIME类型。
- Accept - Charset:浏览器可接受的字符集。
- Accept - Encoding:浏览器能够进行解码的数据编码方式,比如gzip。
- Accept - Language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到。
- Connection:表示是否需要持久连接。
- Content - Length:表示请求消息正文的长度。
- User - Agent:浏览器类型等信息;
- 响应信息中,包含响应头信息,HTTP协议定义了一系列的响应属性,部分如下:
- Content-Base:解析主体中的相对URL时使用的基础URL;
- Content-Language:WEB 服务器告诉浏览器理解主体时最适宜使用的自然语言;
- Content-Location:资源实际所处的位置;
- Content-Type:WEB 服务器告诉浏览器自己响应的对象的类型。例如:Content-Type:application/xml;
- Last-Modified:WEB服务器认为对象的最后修改时间,比如文件的最后修改时间,动态页面的最后产生时间等;
- 响应code即响应的状态码,由3位数字组成,表示请求是否被理解或被满足,常见的有:
- 200 :找到了该资源,并且一切正常;
- 401: 客户端无权访问该资源。这通常会使得浏览器要求用户输入用户名和密码,以登录到服务器;
- 403 :客户端未能获得授权。通常是在401之后输入了不正确的用户名或密码;
- 404 :在指定的位置不存在所申请的资源;
- 500: 内部服务器错误 ;
- TCP协议和UDP协议有什么不同?
- HTTP协议中的GET和POST请求方法有什么不同?
- HTTP的请求信息和响应信息都包含哪几部分?
- HTTP协议常见的响应码有哪些?
- TCP/IP协议栈中有很多常用的、重要的协议;TCP协议是面向连接的、安全的协议;UDP协议是无连接的、不安全的协议;HTTP协议是目前互联网使用最多的协议;
- HTTP协议中定义了多种请求方式,包括GET、POST、HEAD等;GET方式会把请求参数通过URL一起传递,POST方式会把请求参数放在请求体中传递;
- HTTP协议是基于请求/响应模型的,HTTP请求信息由请求行、请求头部、空行和请求数据四个部分组成;
- HTTP响应也由四个部分组成,分别是:状态行、响应头部、空行、响应正文。
- 响应的状态行中会包含响应状态码,其中常见的有200 表示找到了该资源,并且一切正常;404 表示在指定的位置不存在所申请的资源;500表示 内部服务器错误 等。
六、Socket开发
- Java语言对TCP协议网络通信使用java.net包中的Socket和ServerSocket进行支持;Socket被称为“套接字”,用来描述IP地址和端口;
- Socket与ServerSocket的通讯过程简要描述如下:
服务器与客户端的一对一通讯代码:
服务器端:
1 package com.chinasofti.socket; 2 3 import java.io.*; 4 import java.net.ServerSocket; 5 import java.net.Socket; 6 import java.util.Scanner; 7 8 public class Server { 9 public static void main(String[] args) { 10 try { 11 // 创建服务器socket 12 ServerSocket serverSocket = new ServerSocket(12345); 13 // 接受客户端socket 14 Socket server = serverSocket.accept(); 15 System.out.println("服务器已启动,等待"+server.getInetAddress().getHostAddress()+"客户端发送信息:"); 16 // 创建输入流 17 Scanner in = new Scanner(server.getInputStream()); 18 // 创建输出流 19 PrintWriter pw = new PrintWriter(new OutputStreamWriter(server.getOutputStream())); 20 // 循环接收客户端发来的消息 并且回复 21 while (true){ 22 // 接受客户端发送的数据 23 System.out.println("客户端:" + in.next()); 24 System.out.print("我说:"); 25 Scanner sc = new Scanner(System.in); 26 String text = sc.next(); 27 if(text.equals("exit")){ 28 break; 29 } 30 // 输出 31 pw.println(text); 32 pw.flush(); 33 34 } 35 in.close(); 36 37 38 } catch (IOException e) { 39 e.printStackTrace(); 40 } 41 } 42 }
客户端:
1 package com.chinasofti.socket; 2 3 import java.io.*; 4 import java.net.Socket; 5 import java.util.Scanner; 6 7 public class Client { 8 public static void main(String[] args) { 9 try { 10 // 创建客户端socket 11 Socket client = new Socket("127.0.0.1", 12345); 12 // 创建输出流 13 PrintWriter pw = new PrintWriter(client.getOutputStream()); 14 // 创建输入流 15 Scanner in = new Scanner(client.getInputStream()); 16 // 循环接收服务器发送的数据 并且向服务器发送数据 17 while (true){ 18 Scanner sc = new Scanner(System.in); 19 System.out.print("我说:"); 20 String text = sc.next(); 21 if(text.equals("exit")){ 22 break; 23 } 24 pw.println(text); 25 pw.flush(); 26 System.out.println("服务器:"+in.next()); 27 } 28 in.close(); 29 pw.close(); 30 } catch (IOException e) { 31 e.printStackTrace(); 32 } 33 } 34 }