zoukankan      html  css  js  c++  java
  • 为什么静态域与网络传输无关

    首先静态域与网络传输没有关系,静态域不可以被序列化,也不会在网络中被传输。我们先通过一个例子验证这个问题,后面再分析静态域到底是怎样的一种存在。

    以下是一个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实例上指向不同的静态域,导致通信前后静态变量的不同。关于静态域和类加载的过程可以看看我的上篇文章

  • 相关阅读:
    JSONObject和JSONArray区别及基本用法
    MySQL中UTF8编码的数据在cmd下乱码
    js页面刷新跳转的几种方式及区别
    JS中使用EL表达式
    $.ajax()方法参数详解
    Firefox默认英文修改中文
    配置文件的相对地址和绝对地址设置
    IntelliJ IDEA设置统一编码utf-8
    java.lang.SecurityException: Prohibited package name:
    flask的多个url对应同一个视图函数
  • 原文地址:https://www.cnblogs.com/zzzz76/p/9338671.html
Copyright © 2011-2022 走看看