首先静态域与网络传输没有关系,静态域不可以被序列化,也不会在网络中被传输。我们先通过一个例子验证这个问题,后面再分析静态域到底是怎样的一种存在。
以下是一个socket通信过程,Client端负责实例的构造和发送,Server端负责监听和接收来自端口的实例,User类拥有静态变量和成员变量,这里将User的实例作为目标进行传输。
import java.io.*;
import java.net.Socket;
/**
* User: zzzz76
* Date: 2018-07-07
*/
public class Client {
public static void main(String[] args) throws Exception {
User.setTag("client");
for (int i = 0; i < 5; i++) {
Socket socket = null;
BufferedOutputStream bos = null;
ObjectOutputStream oos = null;
try {
socket = new Socket("localhost", 10000);
bos = new BufferedOutputStream(socket.getOutputStream());
oos = new ObjectOutputStream(bos);
User user = new User("user_" + i, "password_" + i);
oos.writeObject(user);
oos.flush();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
IOUtils.closeQuietly(oos);
IOUtils.closeQuietly(bos);
IOUtils.closeQuietly(socket);
}
}
}
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* User: zzzz76
* Date: 2018-07-07
*/
public class Server {
public static void main(String[] args) {
User.setTag("server");
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(10000);
serverSocket.setSoTimeout(10000);
// Listen for the connection to accept socket
while (true) {
Socket socket = serverSocket.accept();
launch(socket);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(serverSocket);
}
}
/**
* Launch socket to receive the input of task
*
* @param socket
*/
private static void launch(Socket socket) {
new Thread(() -> {
BufferedInputStream bis = null;
ObjectInputStream ois = null;
try {
bis = new BufferedInputStream(socket.getInputStream());
ois = new ObjectInputStream(bis);
Object obj = ois.readObject();
User user = (User) obj;
System.out.println("Get socket user: " + user.getTag() +
"/" + user.getName() +
"/" + user.getPassword());
} catch (IOException | ClassNotFoundException ex) {
ex.printStackTrace();
} finally {
IOUtils.closeQuietly(ois);
IOUtils.closeQuietly(bis);
IOUtils.closeQuietly(socket);
}
}).start();
}
}
import java.io.Serializable;
/**
* User: zzzz76
* Date: 2018-07-07
*/
public class User implements Serializable {
//类加载时在方法区分配内存,并初始化
private static String tag = "clinit";
static {
System.out.println("Init static tag: " + tag);
}
private String name;
private String password;
//构造实例时在堆上分配内存,并初始化
public User() {
System.out.println("Init instance user");
}
public User(String name, String password) {
this.name = name;
this.password = password;
System.out.println("Init Instance user: " + name + "/" +password);
}
public String getName() {
return name;
}
public User setName(String name) {
this.name = name;
return this;
}
public String getPassword() {
return password;
}
public User setPassword(String password) {
this.password = password;
return this;
}
public static String getTag() {
return tag;
}
public static void setTag(String tag) {
System.out.println("Update static tag: " + tag);
User.tag = tag;
}
}
输出结果:
➜ Desktop java Client
Init static tag: clinit
Update static tag: client
Init Instance user: user_0/password_0
Init Instance user: user_1/password_1
Init Instance user: user_2/password_2
Init Instance user: user_3/password_3
Init Instance user: user_4/password_4
➜ Desktop java Server
Init static tag: clinit
Update static tag: server
Get socket user: server/user_2/password_2
Get socket user: server/user_3/password_3
Get socket user: server/user_4/password_4
Get socket user: server/user_0/password_0
Get socket user: server/user_1/password_1
从输出结果可以看出:
- 在Server端中,User的构造函数没有经过调用,说明User实例是从端口处获取的。
- 静态域在传输开始之前就已经产生并且经过初始化,每一个User实例都指向位于本JVM进程中的静态域,而并非网络端口(其他JVM进程),所以静态域没有到参与整个传输过程中。
其实这里产生了两个JVM实例,每个实例都具有独立的堆栈,其中静态域就位于堆栈的方法区中。User实例在不同的JVM实例上指向不同的静态域,导致通信前后静态变量的不同。关于静态域和类加载的过程可以看看我的上篇文章。