Увы, хотя я наиболее хорошо знаком с Java, есть много базовых знаний по Java, которых я не знаю. Например, я никогда раньше не использовал ключевое слово transient, поэтому не знал, что оно делает. Сегодня, выполняя письменный тест, я наткнулся на вопрос о нём, поэтому потратил немного времени, чтобы систематизировать использование ключевого слова transient и пополнить свои знания~~~ Ладно, хватит ерунды, давайте начнём ниже:

1. Назначение и использование transient

Мы все знаем, что если объект реализует интерфейс Serializable, то объект можно сериализовать. Механизм сериализации Java предоставляет разработчикам множество удобств. Нам не нужно беспокоиться о конкретном процессе сериализации; если класс реализует интерфейс Serializable, все свойства и методы класса будут автоматически сериализованы.

Однако в реальной разработке мы часто сталкиваемся с такой проблемой: некоторые свойства класса нужно сериализовать, а другие — нет. Например, если у пользователя есть некоторая конфиденциальная информация (например, пароли, номера банковских карт и т. д.), из соображений безопасности мы не хотим, чтобы она передавалась во время сетевых операций (в основном это касается операций сериализации; локальное кэширование сериализации также применимо). Переменные, соответствующие этой информации, можно пометить ключевым словом transient. Иными словами, жизненный цикл этого поля существует только в памяти вызывающей стороны и не будет записан на диск для сохранения.

Короче говоря, ключевое слово transient в Java обеспечивает нам удобство. Вам просто нужно реализовать интерфейс Serializable и добавить ключевое слово transient перед атрибутами, которые не нужно сериализовать. При сериализации объекта этот атрибут не будет сериализован в указанное место назначения.

Пример

import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * @description Используйте ключевое слово transient, чтобы не сериализовать переменную * Обратите внимание, что при чтении порядок чтения данных должен совпадать с порядком, в котором данные были сохранены * * @author Alexia * @date 2013-10-15 */ public class TransientTest { public static void main(String[] args) { User user = new User(); user.setUsername("Alexia"); user.setPasswd("123456"); System.out.println("прочитано до Serializable: "); System.out.println("имя пользователя: " + user.getUsername()); System.err.println("пароль: " + user.getPasswd()); try { ObjectOutputStream os = new ObjectOutputStream( new FileOutputStream("C:/user.txt")); os.writeObject(user); //Записать объект User в файл os.flush(); os.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { ObjectInputStream is = new ObjectInputStream(new FileInputStream( "C:/user.txt")); user = (User) is.readObject(); //Считать данные User из потока is.close(); System.out.println("\nчтение после Serializable: "); System.out.println("имя пользователя: " + user.getUsername()); System.err.println("пароль: " + user.getPasswd()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } class User implements Serializable { private static final long serialVersionUID = 8294180014912103005L; private String username; private transient String passwd; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } }

Вывод:

read before Serializable: 
username: Alexia
password: 123456

read after Serializable: 
username: Alexia
password: null

Поле пароля равно null, что указывает на то, что при десериализации из файла не было получено никакой информации.

2. Сводка по использованию transient

1) Как только переменная изменяется с помощью transient, переменная больше не является частью сохраняемого состояния объекта, и к содержимому переменной нельзя получить доступ после сериализации.

2) Ключевое слово transient может изменять только переменные, но не методы или классы. Обратите внимание, что локальные переменные не могут быть изменены ключевым словом transient. Если переменная является переменной пользовательского класса, то этот класс должен реализовывать интерфейс Serializable.

3) Переменная, изменённая ключевым словом transient, больше не может быть сериализована. Статическая переменная не может быть сериализована независимо от того, изменена ли она с помощью transient.

Некоторые могут запутаться насчёт третьего пункта, потому что они обнаруживают, что после добавления ключевого слова static перед полем username в классе User вывод программы остаётся неизменным; то есть статическое username также считывается как "Alexia". Разве это не противоречит третьему пункту? На самом деле всё обстоит так: третий пункт действительно верен (статическая переменная не может быть сериализована независимо от того, изменена ли она с помощью transient). После десериализации значение статической переменной username в классе — это значение соответствующей статической переменной в текущей JVM. Это значение берётся из JVM, а не из десериализации. Не верите? Хорошо, ниже я это докажу:

Пример

import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; /** * @description Используйте ключевое слово transient, чтобы не сериализовать переменную * Обратите внимание, что при чтении порядок чтения данных должен совпадать с порядком, в котором данные были сохранены * * @author Alexia * @date 2013-10-15 */ public class TransientTest { public static void main(String[] args) { User user = new User(); user.setUsername("Alexia"); user.setPasswd("123456"); System.out.println("прочитано до Serializable: "); System.out.println("имя пользователя: " + user.getUsername()); System.err.println("пароль: " + user.getPasswd()); try { ObjectOutputStream os = new ObjectOutputStream( new FileOutputStream("C:/user.txt")); os.writeObject(user); //Записать объект User в файл os.flush(); os.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { //Измените значение username перед десериализацией User.username = "jmwang"; ObjectInputStream is = new ObjectInputStream(new FileInputStream( "C:/user.txt")); user = (User) is.readObject(); //Считать данные User из потока is.close(); System.out.println("\nчтение после Serializable: "); System.out.println("имя пользователя: " + user.getUsername()); System.err.println("пароль: " + user.getPasswd()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } class User implements Serializable { private static final long serialVersionUID = 8294180014912103005L; public static String username; private transient String passwd; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } }

Результат выполнения:

read before Serializable: 
username: Alexia
password: 123456

read after Serializable: 
username: jmwang
password: null

Это показывает, что после десериализации значение статической переменной username в классе — это значение соответствующей статической переменной в текущей JVM, которое после изменения равно jmwang, а не значение Alexia из сериализации.

3. Подробности использования transient — действительно ли переменные, изменённые ключевым словом transient, не сериализуются?

Рассмотрим следующий пример:

Пример

import java.io.Externalizable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; /** * @descripiton Использование интерфейса Externalizable * * @author Alexia * @date 2013-10-15 * */ public class ExternalizableTest implements Externalizable { private transient String content = "Да, я буду сериализован, независимо от того, модифицирован ли я с помощью ключевого слова transient"; @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeObject(content); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { content = (String) in.readObject(); } public static void main(String[] args) throws Exception { ExternalizableTest et = new ExternalizableTest(); ObjectOutput out = new ObjectOutputStream(new FileOutputStream( new File("test"))); out.writeObject(et); ObjectInput in = new ObjectInputStream(new FileInputStream(new File( "test"))); et = (ExternalizableTest) in.readObject(); System.out.println(et.content); out.close(); in.close(); } }

Будет ли переменная content сериализована? Хорошо, я уже вывел ответ. Да, результат выполнения:

是的,我将会被序列化,不管我是否被transient关键字修饰

Почему так? Разве мы не говорили, что после того, как переменная класса изменена ключевым словом transient, она не может быть сериализована?

Мы знаем, что в Java сериализация объектов может быть достигнута путём реализации двух интерфейсов. Если реализован интерфейс Serializable, вся сериализация будет выполняться автоматически. Если реализован интерфейс Externalizable, ничего не может быть сериализовано автоматически; вам нужно вручную указать переменные для сериализации в методе writeExternal, независимо от того, изменены ли они с помощью transient. Поэтому во втором примере выводом является инициализированное содержимое переменной content, а не null.

Источник: http://www.cnblogs.com/lanxuezaipiao/p/3369962.html