美文网首页
2018-05-23 java transient关键字

2018-05-23 java transient关键字

作者: MiaLing007 | 来源:发表于2018-05-24 11:50 被阅读0次

    1,transient(临时)关键字

    java中提供了很方便的序列化,只要实现Serializable接口(或Extenalizable),那么就可以被序列化,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化,这样就可以将输出到文件,网络中,对象持久化到硬盘上。
    但是,有时候对象的某些属性我们不想被序列化,必须出于安全考虑,对象包含的不想被序列化的敏感信息(如密码),那么这些信息就可以加上该关键字

    例:

    import java.io.*;
    
    public class login {
    
        public static void main(String args[]) {
            UserInfo info = new UserInfo();
            info.setUsername("zhangssan");
            info.setPassword("123456");
            
            System.out.println("序列化前:");
            System.out.println("username: " + info.getUsername());
            System.out.println("password: " + info.getPassword());
            
            //向UserInfo对象存入到info.txt
            try {
                ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("D:/info.txt"));
                os.writeObject(info);
                os.flush();
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            //从文件中读取UserInfo的对象数据
            try {
                ObjectInputStream is = new ObjectInputStream(new FileInputStream("D:/info.txt"));
                UserInfo inputInfo = (UserInfo) is.readObject();
                is.close();
                System.out.println("\n 序列化读取文件后:");
                System.out.println("username: " + inputInfo.getUsername());
                System.out.println("password: " + inputInfo.getPassword());
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    
    class UserInfo implements Serializable {
        
        private String username;
        private transient String password;
        
        public String getUsername() {
            return username;
        }
        
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    }
    

    输出结果:

    序列化前:
    username: zhangssan
    password: 123456
    
     序列化读取文件后:
    username: zhangssan
    password: null
    
    

    password字段为null,说明该字段并没有被序列化

    2,Externalizable接口

    我们同样可以通过实现Externalizable接口来实现序列化的控制,实现Externalizable接口后,所以东西都将默认不被序列化,需要在writeExternal方法和ReadExternal方法中进行手工指定所要序列化或反序列化的变量,这与是否被transient修饰无关。

    例:

    import java.io.*;
    
    public class LogonTest implements Externalizable{
        private String username;
        private transient String password;
        
        public LogonTest(){}//必须提供无参构造函数,否则会抱错
        public LogonTest (String name, String pwd) {
            username = name;
            password = pwd;
        }
        
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            //out.writeObject(username);
            out.writeObject(password);
        }
    
        @Override
        public void readExternal(ObjectInput in) throws IOException,
                ClassNotFoundException {
            //username = (String)in.readObject();
            password = (String)in.readObject();
        }
        
        public String toString() {
            return ("username="+username+", password="+password);
        }
        
        public static void main(String[] args) {
            LogonTest logonTest = new LogonTest("zhangsan", "123456");
            System.out.println("logonTest value:\n "+logonTest);
            try {
                ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("Logon.out"));
                o.writeObject(logonTest);
                o.close();
                
                System.out.println("-----------------------");
                
                // Now get them back;
                ObjectInputStream in = new ObjectInputStream(new FileInputStream("Logon.out"));
                logonTest = (LogonTest)in.readObject();
                in.close();
                System.out.println("logonTest value:\n " + logonTest);
                
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    

    输出结果:

    logonTest value:
     username=zhangsan, password=123456
    -----------------------
    logonTest value:
     username=null, password=123456
    
    

    LogonTest中方法writeExternal和readExternal里只加了passwod,虽然password有transient,但仍然被序列化,而username并没有作处理,也就没有被序列化。
    所以实现接口Externalizable后序列化跟writeExternal和readExternal方法有关,与关键字transient无关
    注意:这里实现Externalizable接口时,必须有无参构造函数,否则会抱错。这是因为在反序列化时,会调用无参构造函数。
    例如:注释掉上边无参构造函数,则再运行时,就会报 no valid constructor

    logonTest value:
     username=zhangsan, password=123456
    -----------------------
    java.io.InvalidClassException: LogonTest; no valid constructor
        at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:150)
        at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:768)
        at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1775)
        at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
        at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
        at LogonTest.main(LogonTest.java:42)
    

    3,静态变量默认不会被序列化,但可以手动序列化

    例:

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    import java.util.Random;
    import java.util.Vector;
    
    abstract class Shape implements Serializable {
        public static final String
            RED = "red", BLUE ="blue", GREEN ="green";
            
        abstract public void setColor(String newColor);
        abstract public String getColor();
    
        public String toString() {
            return getClass().toString() + 
                " color[" + getColor() +
                "] \n";
        }
    }
    
    class Circle extends Shape {
        private static String color = RED;
        
        @Override
        public void setColor(String newColor) {
            color = newColor;
        }
    
        @Override
        public String getColor() {
            return color;
        }
    }
    
    class Square extends Shape {
        private static String color=RED;
        
        @Override
        public void setColor(String newColor) {
            color = newColor;
        }
        @Override
        public String getColor() {
            return color;
        }
    }
    
    class Line extends Shape {
    
        private static String color = RED;
        public static void serializaStaticState(ObjectOutputStream os) throws IOException {
            os.writeObject(color);
        }
        public static void deserializaStaticState(ObjectInputStream is) throws IOException, ClassNotFoundException {
            color = (String) is.readObject();
        }
    
        @Override
        public void setColor(String newColor) {
            color = newColor;
        }
    
        @Override
        public String getColor() {
            return color;
        }
    }
    
    public class StaticTestSerinal {
        public static void main(String[] args) throws Exception {
            Vector shapes;
            if (args.length == 0) {
                shapes = new Vector();
                // Add handles to the class objects;
                Circle circle = new Circle();
                Square square = new Square();
                Line line = new Line();
                
                circle.setColor("BLACK");
                square.setColor("BLACK");
                line.setColor("BLACK");
                
                shapes.add(circle);
                shapes.add(square);
                shapes.add(line);
    
                ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("statisState.out"));
    /**标记1**/ Line.serializaStaticState(out); //调用writeObject手动将静态变量输出到输出流中     
                out.writeObject(shapes);
            } else {
                ObjectInputStream in = new ObjectInputStream(new FileInputStream(args[0]));
    
    /**标记2**/ Line.deserializaStaticState(in);//调用readObject手动将静态变量输入到输入流中
                shapes = (Vector) in.readObject();
            }
            // Display the shaps
            System.out.println(shapes);
        }
    }
    

    不提供命令行参数时输出结果:

    [class Circle color[BLACK] 
    , class Square color[BLACK] 
    , class Line color[BLACK] 
    ]
    

    加上命令行参数参数输出:

    [class Circle color[red] 
    , class Square color[red] 
    , class Line color[BLACK] 
    ]
    

    通过结果会发现,Circle和Square都没有序列化静态变量,但是因为Line里边手动调用readObject和writeObject将静态变量输入输出,所以静态变量就会被序列化。
    可以注释掉上边带吗中的标记1和标记2,测试会发现此时静态变量并没有被序列化。

    相关文章

      网友评论

          本文标题:2018-05-23 java transient关键字

          本文链接:https://www.haomeiwen.com/subject/demrjftx.html