Почему у Java есть временные поля?
Почему у Java есть временные поля?
13 ответов
transient
Ключевое слово в Java используется, чтобы указать, что поле не должно быть частью процесса сериализации (что означает сохранение, как в файл).
Из спецификации языка Java, Java SE 7 Edition, раздел 8.3.1.3.transient
Поля:
Переменные могут быть помечены
transient
указать, что они не являются частью постоянного состояния объекта.
Например, у вас могут быть поля, которые получены из других полей, и должны выполняться только программно, а не сохраняться в состоянии посредством сериализации.
ВотGalleryImage
класс, который содержит изображение и эскиз, полученный из изображения:
class GalleryImage implements Serializable
{
private Image image;
private transient Image thumbnailImage;
private void generateThumbnail()
{
// Generate thumbnail.
}
private void readObject(ObjectInputStream inputStream)
throws IOException, ClassNotFoundException
{
inputStream.defaultReadObject();
generateThumbnail();
}
}
В этом примереthumbnailImage
это миниатюрное изображение, которое генерируется путем вызоваgenerateThumbnail
метод.
thumbnailImage
поле помечено какtransient
так что только оригиналimage
сериализуется, а не сохраняется как исходное изображение, так и миниатюра изображения. Это означает, что для сохранения сериализованного объекта потребуется меньше места. (Конечно, это может или не может быть желательно в зависимости от требований системы - это только пример.)
Во время десериализации,readObject
Метод вызывается для выполнения любых операций, необходимых для восстановления состояния объекта обратно в состояние, в котором произошла сериализация. Здесь, эскиз должен быть сгенерирован, поэтому readObject
метод переопределен, так что миниатюра будет сгенерирована путем вызова generateThumbnail
метод.
Для получения дополнительной информации статья " Раскройте секреты API Java Serialization" (которая первоначально была доступна в Sun Developer Network) содержит раздел, в котором обсуждается использование и представлен сценарий, в котором transient
Ключевое слово используется для предотвращения сериализации определенных полей.
Прежде чем понять transient
Ключевое слово, нужно понимать концепцию сериализации. Если читатель знает о сериализации, пропустите первый пункт.
Что такое сериализация?
Сериализация - это процесс сохранения состояния объекта. Это означает, что состояние объекта преобразуется в поток байтов и сохраняется в файле. Таким же образом, мы можем использовать десериализацию, чтобы вернуть состояние объекта из байтов. Это одна из важных концепций в Java-программировании, потому что сериализация в основном используется в сетевом программировании. Объекты, которые должны быть переданы через сеть, должны быть преобразованы в байты. Для этого каждый класс или интерфейс должен реализовывать Serializable
интерфейс. Это маркерный интерфейс без каких-либо методов.
Теперь, что является transient
Ключевое слово и его цель?
По умолчанию все переменные объекта преобразуются в постоянное состояние. В некоторых случаях вы можете избежать сохранения некоторых переменных, потому что вам не нужно сохранять эти переменные. Таким образом, вы можете объявить эти переменные как transient
, Если переменная объявлена как transient
, то это не будет сохраняться. Это главная цель transient
ключевое слово.
Я хочу объяснить вышеупомянутые два пункта следующим примером:
package javabeat.samples;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class NameStore implements Serializable{
private String firstName;
private transient String middleName;
private String lastName;
public NameStore (String fName, String mName, String lName){
this.firstName = fName;
this.middleName = mName;
this.lastName = lName;
}
public String toString(){
StringBuffer sb = new StringBuffer(40);
sb.append("First Name : ");
sb.append(this.firstName);
sb.append("Middle Name : ");
sb.append(this.middleName);
sb.append("Last Name : ");
sb.append(this.lastName);
return sb.toString();
}
}
public class TransientExample{
public static void main(String args[]) throws Exception {
NameStore nameStore = new NameStore("Steve", "Middle","Jobs");
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("nameStore"));
// writing to object
o.writeObject(nameStore);
o.close();
// reading from object
ObjectInputStream in = new ObjectInputStream(new FileInputStream("nameStore"));
NameStore nameStore1 = (NameStore)in.readObject();
System.out.println(nameStore1);
}
}
И вывод будет следующим:
First Name : Steve
Middle Name : null
Last Name : Jobs
Отчество объявляется как transient
, поэтому он не будет храниться в постоянном хранилище.
Чтобы позволить вам определить переменные, которые вы не хотите сериализовать.
В объекте у вас может быть информация, которую вы не хотите сериализовать / сохранять (возможно, ссылка на родительский объект фабрики), или, возможно, нет смысла сериализовать. Отметив их как "переходные" означает, что механизм сериализации будет игнорировать эти поля.
Мой маленький вклад:
Что такое переходное поле?
По сути, любое поле, измененное с помощью transient
Ключевое слово является переходным полем.
Зачем нужны переходные поля в Java?transient
Ключевое слово дает вам некоторый контроль над процессом сериализации и позволяет исключить некоторые свойства объекта из этого процесса. Процесс сериализации используется для сохранения Java-объектов, главным образом для того, чтобы их состояния могли сохраняться во время их передачи или неактивности. Иногда имеет смысл не сериализовать определенные атрибуты объекта.
Какие поля следует пометить как переходные?
Теперь мы знаем цель transient
Ключевое слово и переходные поля, важно знать, какие поля помечать переходные. Статические поля также не сериализуются, поэтому соответствующее ключевое слово также поможет. Но это может испортить дизайн вашего класса; это где transient
Ключевое слово приходит на помощь. Я стараюсь не допускать сериализации полей, значения которых могут быть получены из других, поэтому я отмечаю их как временные. Если у вас есть поле с именем interest
чье значение может быть вычислено из других полей (principal
, rate
& time
), нет необходимости его сериализации.
Еще один хороший пример - количество слов в статье. Если вы сохраняете всю статью, вам не нужно сохранять количество слов, потому что оно может быть вычислено, когда статья будет "десериализована". Или подумайте о регистраторах; Logger
экземпляры почти никогда не нужно сериализовать, поэтому их можно сделать временными.
transient
Переменная - это переменная, которая не может быть сериализована.
Один из примеров того, когда это может оказаться полезным, - это переменные, которые имеют смысл только в контексте конкретного экземпляра объекта и становятся недействительными после сериализации и десериализации объекта. В этом случае полезно, чтобы эти переменные стали null
вместо этого, чтобы вы могли повторно инициализировать их с полезными данными, когда это необходимо.
Системы сериализации, кроме нативной Java, также могут использовать этот модификатор. Например, Hibernate не сохранит поля, помеченные @Transient или модификатором transient. Терракота также уважает этот модификатор.
Я полагаю, что переносное значение модификатора таково: "Это поле предназначено только для использования в памяти. Не сохраняйте и не перемещайте его вне этой конкретной виртуальной машины. Это непереносимо". то есть вы не можете полагаться на его значение в другом пространстве памяти виртуальной машины. Как и volatile, вы не можете полагаться на определенную семантику памяти и потоков.
transient
используется, чтобы указать, что поле класса не должно быть сериализовано. Вероятно, лучший пример Thread
поле. Там обычно нет причин для сериализации Thread
, поскольку его состояние очень "специфично для потока".
Прежде чем ответить на этот вопрос, я должен объяснить вам СЕРИАЛИЗАЦИЮ, потому что если вы понимаете, что означает сериализация в научном компьютере, вы легко поймете это ключевое слово.
Сериализация Когда объект передается по сети / сохраняется на физическом носителе (файл,...), объект должен быть "сериализован". Сериализация преобразует байты серии объектов статуса. Эти байты отправляются по сети / сохраняются, и объект воссоздается из этих байтов.
пример
public class Foo implements Serializable
{
private String attr1;
private String attr2;
...
}
Теперь, если ВЫ ХОТИТЕ НЕ ПЕРЕДАТЬ/СОХРАНИТЬ поле этого объекта ТАК, вы можете использовать ключевое слово transient
private transient attr2;
Сериализация - это процесс сохранения состояний объекта в постоянном формате (например, файлового потока или базы данных) с последующим восстановлением их из потока (десериализация). В Java объект класса является сериализуемым, если класс реализует интерфейс java.io.Serializable. Это интерфейс маркера, который сообщает JVM, что класс пригоден для сериализации.
public class User implements Serializable {
private static final long serialVersionUID = 1234L;
private String username;
private String email;
private transient String password;
private Date birthday;
private int age;
public User(String username, String email, String password, Date birthday,
int age) {
this.username = username;
this.email = email;
this.password = password;
this.birthday = birthday;
this.age = age;
}
public void printInfo() {
System.out.println("username: " + username);
System.out.println("email: " + email);
System.out.println("password: " + password);
System.out.println("birthday: " + birthday);
System.out.println("age: " + age);
}
// getters and setters
}
Этот класс модели имеет три важных момента: он должен реализовывать интерфейс Serializable. В противном случае мы получим исключение java.io.NotSerializableException при попытке сериализации объекта класса. Константа с именем serialVersionUID объявляется и ей присваивается длинное значение:
private static final long serialVersionUID = 1234L;
Это обычная константа, которая должна быть объявлена, когда класс реализует интерфейс Serializable. UID последовательной версии надежно обеспечивает совместимость между сериализованными и десериализованными версиями объектов класса, поскольку процесс сериализации и десериализации может происходить на разных компьютерах и системах. Хотя это объявление является необязательным, всегда рекомендуется объявлять serialVersionUID для сериализуемого класса.
Обратите внимание, что поле пароля помечено как временное:
private transient String password;
Потому что мы не хотим хранить пароль при сериализации объекта. Правило гласит: если переменная помечена как временная, ее объект не будет сериализован во время сериализации.
Временная переменная - это переменная, которая не может быть сериализована. Вы используете ключевое слово transient, чтобы указать виртуальной машине Java, что указанная переменная не является частью постоянного состояния объекта.
Модификаторы доступа, поддерживаемые Java, являются статическими, окончательными, абстрактными, синхронизированными, нативными, энергозависимыми, временными и строгими.
В следующей таблице приведен список спецификаторов доступа и модификаторов Java, которые можно применять к переменным, методам и классам.
SPECIFIER/MODIFIER LOCAL VARIABLE INSTANCEVARIABLE METHOD CLASS
public NA A A A
protected NA A A NA
default A A A A
private NA A A NA
final A A A A
static NA A A NA
synchronized NA NA A NA
native NA NA A NA
volatile NA A NA NA
transient NA A NA NA
strictfp NA NA A A
Это необходимо, когда вы не хотите делиться некоторыми конфиденциальными данными, которые идут с сериализацией.
Согласно переходному значению google == длительность только в течение короткого времени; непостоянно.
Теперь, если вы хотите сделать что-то временное в Java, используйте ключевое слово transient.
Q: где использовать переходный процесс?
A: Обычно в Java мы можем сохранять данные в файлы, собирая их в переменные и записывая эти переменные в файлы, этот процесс известен как сериализация. Теперь, если мы хотим избежать записи переменных данных в файл, мы бы сделали эту переменную переходной.
переходный процесс int=10;
Примечание: временные переменные не могут быть локальными.
Упрощенный пример кода для ключевого слова переходного процесса.
import java.io.*;
class NameStore implements Serializable {
private String firstName, lastName;
private transient String fullName;
public NameStore (String fName, String lName){
this.firstName = fName;
this.lastName = lName;
buildFullName();
}
private void buildFullName() {
// assume building fullName is compuational/memory intensive!
this.fullName = this.firstName + " " + this.lastName;
}
public String toString(){
return "First Name : " + this.firstName
+ "\nLast Name : " + this.lastName
+ "\nFull Name : " + this.fullName;
}
private void readObject(ObjectInputStream inputStream)
throws IOException, ClassNotFoundException
{
inputStream.defaultReadObject();
buildFullName();
}
}
public class TransientExample{
public static void main(String args[]) throws Exception {
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("ns"));
o.writeObject(new NameStore("Steve", "Jobs"));
o.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("ns"));
NameStore ns = (NameStore)in.readObject();
System.out.println(ns);
}
}
Потому что не все переменные имеют сериализуемую природу.
- Сериализация и десериализация - это процессы симметрии, в противном случае вы не можете ожидать, что результат будет определен, в большинстве случаев неопределенные значения бессмысленны;
- Сериализация и десериализация идемпотентны, это означает, что вы можете выполнять сериализацию столько раз, сколько хотите, и результат будет тем же.
Таким образом, если объект может существовать в памяти, но не на диске, то объект не может быть сериализован, поскольку машина не может восстановить карту памяти при десериализации. Например, вы не можете сериализоватьStream
объект.
Вы не можете сериализовать Connection
объект, потому что его состояние также зависит от удаленного сайта.
Проще говоря, временное ключевое слово java защищает поля от бывшего Serialize в качестве их непереходных полей.
В этом фрагменте кода наш абстрактный класс BaseJob реализует интерфейс Serializable, который мы расширяем от BaseJob, но нам не нужно сериализовать удаленные и локальные источники данных; сериализовать только поля organizationName и isSynced.
public abstract class BaseJob implements Serializable{
public void ShouldRetryRun(){}
}
public class SyncOrganizationJob extends BaseJob {
public String organizationName;
public Boolean isSynced
@Inject transient RemoteDataSource remoteDataSource;
@Inject transient LocalDaoSource localDataSource;
public SyncOrganizationJob(String organizationName) {
super(new
Params(BACKGROUND).groupBy(GROUP).requireNetwork().persist());
this.organizationName = organizationName;
this.isSynced=isSynced;
}
}
Дайте еще один пример, чтобы прояснить ситуацию. Пожалуйста, прочитайте принятый ответ. Здесь я буду объяснять только еще один пример.
class Employee{
String name;
Date dob;
transient int age;
public int calculateAge(Date dob){
int age = 0;
//calculate age based on Date of birth
return age;
}
}
Здесь в приведенном выше примере я сделал "возраст" как переходный. Когда я записываю возраст в файл, его значение не нужно хранить. У меня есть функция, которая рассчитывает возраст на основе DOB. Мы можем использовать переменные для тех переменных-членов, которые мы не хотим записывать на диск.
Надеюсь, поможет.!
Поле, объявленное с модификатором transient, не будет участвовать в сериализованном процессе. Когда объект сериализуется (сохраняется в любом состоянии), значения его временных полей игнорируются в последовательном представлении, в то время как поле, отличное от временных полей, будет участвовать в процессе сериализации. Это основная цель ключевого слова transient.