Почему в Java есть временные поля?

avatar
Animesh
26 мая 2009 в 12:11
736944
15
1576

Почему в Java есть переходные поля ?

Источник

Ответы (15)

avatar
coobird
26 мая 2009 в 12:53
1765

Ключевое слово 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.

Для получения дополнительной информации в статье Откройте для себя секреты Java Serialization API (который изначально был доступен в Sun Developer Network) есть раздел, в котором обсуждается использование и представлен сценарий, в котором transient ключевое слово используется для предотвращения сериализации определенных полей.

Elazar Leibovich
26 марта 2011 в 21:46
245

Но почему это ключевое слово, а не аннотация @DoNotSerialize?

Peter Wippermann
4 апреля 2011 в 13:48
361

Думаю, это относится к тому времени, когда в Java не было аннотаций.

caleb
17 февраля 2012 в 19:30
58

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

Mohammad Jafar Mashhadi
5 июля 2013 в 06:16
1

readObject метод вызывается автоматически или мы должны его вызвать?

Mike Adler
8 августа 2013 в 07:36
8

@MJafar: readObject обычно связан с механизмами десериализации и поэтому вызывается автоматически. Более того, во многих случаях вам не нужно переопределять его - реализация по умолчанию делает свое дело.

rightfold
18 января 2014 в 22:19
16

@caleb, вероятно, потому, что иметь дело с двоичными форматами самостоятельно в Java невероятно болезненно из-за отсутствия целых чисел без знака.

Hugo
1 апреля 2014 в 05:50
5

@ElazarLeibovich Я думаю, это потому, что это ключевое слово старше аннотаций: en.wikipedia.org/wiki/Java_annotation#History

sproketboy
17 сентября 2014 в 11:47
0

Обратите внимание, что сериализация XML в Java по какой-то причине игнорирует это ключевое слово.

zatenzu
1 января 2015 в 13:47
1

Почему я могу установить переходный процесс для переменной экземпляра класса, если этот класс не реализует интерфейс Serializable? Это не имеет никакого смысла...

Novaterata
5 мая 2016 в 14:10
4

@zatenzu Дочерний класс может реализовать Serializable

Holger
9 мая 2016 в 17:48
4

@novaterata: когда дочерний класс Serializable расширяет класс, отличный от Serializable, дочерний класс становится ответственным за хранение и восстановление всего соответствующего состояния своего суперкласса (ов) (и суперкласс должен иметь доступный конструктор без аргументов) . Следовательно, модификаторы transient в полях не Serializable суперкласса все еще не имеют значения. Но спецификация языка не запрещает использование transient для других механизмов хранения, кроме сериализации.

Sarkhan
6 марта 2017 в 19:43
1

почему интерфейс Serializable является рыночным, не включает readResolve, writeObject и т. д., потому что jvm должен вызывать методы подкласса, а также методы readResolve, writeObject и т. д. суперкласса. Если он был переопределяемым, то метод readResolve суперкласса не мог быть вызван

user207421
6 июля 2017 в 01:19
1

@caleb Он не является «внутренним для Java», он является частью API, и он реализован как интерфейс. Ваша точка зрения ускользает от меня.

tgkprog
25 июля 2017 в 11:51
0

Сериализатор по умолчанию может обращаться к родительским классам с помощью небезопасных операций / с использованием собственного кода. Таким образом, ключевое слово transient используется, когда вы используете сериализацию Java по умолчанию. Полезно для отправки состояния класса в RMI или в пользовательском двоичном файле через реализацию REST / http. Быстрее, чем преобразователи json / xml.

sleske
14 июня 2018 в 14:53
3

@caleb: Спустя много лет Oracle соглашается с вами - они хотят отказаться от сериализации: infoworld.com/article/3275924/java/…

kapad
29 мая 2019 в 19:36
0

@Holger какие механизмы хранения кроме сериализации?

Holger
31 мая 2019 в 09:47
0

@kapad какой-то сторонний механизм сохранения. Может быть полностью гипотетически. Но они разрешены спецификацией.

avatar
Rahul Saxena
16 июня 2021 в 10:37
461

Прежде чем понимать ключевое слово 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, поэтому оно не будет храниться в постоянном хранилище.

Krishna
20 ноября 2012 в 10:43
28

Этот пример взят из этого кода, вы можете прочитать его здесь: javabeat.net/2009/02/what-is-transient-keyword-in-java

Garcia Hurtado
24 ноября 2014 в 02:11
12

Эта часть кажется мне странной и, возможно, сбивающей с толку: «Это означает, что состояние объекта преобразуется в поток байтов и сохраняется в файле ». Мне кажется, что в большинстве случаев сериализация не включает запись в файл (показательный пример: сетевые примеры, которые следуют ниже)

Raphael
8 января 2018 в 14:12
6

Пример плохой, поскольку отчество явно , а не временное свойство.

Arefe
5 ноября 2018 в 10:27
4

@Raphael Для меня пример полезен и, по крайней мере, объясняет концепцию. Не могли бы вы привести лучший пример, если бы вы знали?

Raphael
5 ноября 2018 в 10:30
0

@Yoda У нас может быть ссылка на NameFormatter, используемый для управления toString(). Или что-нибудь еще, связанное с конфигурацией, просмотром или бизнес-логикой ... в отличие от данных.

Tarun
18 января 2019 в 09:35
0

@Raphael - практический пример: размер LinkedList может быть временной переменной, так как он может быть пересчитан после десериализации объекта.

Ngọc Hy
5 октября 2020 в 07:25
0

Верно ли, что в случае определения того, изменился ли объект после некоторых операций, эта концепция является одним из путей?

avatar
Yu Jiaao
4 июля 2020 в 03:28
0

Поскольку не все переменные имеют сериализуемую природу.

  1. Сериализация и десериализация - это процессы симметрии, в противном случае вы не можете ожидать, что результат будет определен, в большинстве случаев неопределенные значения бессмысленны;
  2. Сериализация и десериализация идемпотентны, это означает, что вы можете выполнять сериализацию столько раз, сколько захотите, и результат будет тем же.

Итак, если объект может существовать в памяти, но не на диске, тогда объект не может быть сериализуемым, потому что машина не может восстановить карту памяти при десериализации. Например, вы не можете сериализовать объект Stream.

Невозможно сериализовать объект Connection, потому что его состояние также зависит от удаленного сайта.

avatar
Vishal Sheth
24 января 2020 в 09:12
0

Поле, объявленное с модификатором переходного процесса, не будет участвовать в сериализованном процессе. Когда объект сериализуется (сохраняется в любом состоянии), значения его временных полей игнорируются в последовательном представлении, в то время как поле, отличное от временных полей, будет участвовать в процессе сериализации. Это основная цель временного ключевого слова.

avatar
Mohammed H
5 июня 2019 в 03:09
1

Упрощенный пример кода для ключевого слова переходного процесса.

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);
    }
}
avatar
nyulan
14 ноября 2017 в 13:40
0

Проще говоря, временное ключевое слово java защищает поля от сериализации в качестве их непереходных частей счетчика полей.

В этом фрагменте кода наш абстрактный класс 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;

   }
}
avatar
BERGUIGA Mohamed Amine
1 июля 2015 в 13:12
7

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

Когда объект передается по сети / сохраняется на физическом носителе (файл, ...), объект должен быть "сериализован". Сериализация преобразует серию байтовых объектов статуса. Эти байты отправляются в сеть / сохраняются, и объект создается заново из этих байтов.

Пример:

public class Foo implements Serializable 
{
 private String attr1;
 private String attr2;
 ...
}

Теперь, если в этом классе есть поле, которое вы не хотите передавать или сохранять, вы можете использовать ключевое слово transient

private transient attr2;

Это предотвращает включение формы поля при сериализации класса.

avatar
Mateen
2 ноября 2014 в 08:56
4

Согласно Google преходящее значение == длится только на короткое время; непостоянный.

Теперь, если вы хотите сделать что-либо временным в java, используйте ключевое слово transient.

В: где использовать переходный процесс?

A: Обычно в java мы можем сохранять данные в файлы, получая их в переменных и записывая эти переменные в файлы, этот процесс известен как сериализация. Теперь, если мы хотим избежать записи данных переменных в файл, мы сделаем эту переменную временной.

transient int result=10;

Примечание: переходные переменные не могут быть локальными.

avatar
Shreyos Adikari
18 марта 2014 в 22:04
38

Зачем нужны временные поля в Java?

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

Какие поля следует отмечать переходными?

Теперь, когда мы знаем назначение ключевого слова transient и полей переходного процесса, важно знать, какие поля помечать как переходные. Статические поля также не сериализуются, поэтому соответствующее ключевое слово также поможет. Но это может испортить ваш классовый дизайн; здесь на помощь приходит ключевое слово transient. Я стараюсь не допускать сериализации полей, значения которых могут быть получены из других, поэтому я помечаю их как временные. Если у вас есть поле с именем interest, значение которого можно вычислить из других полей (principal, rate и time), сериализовать его нет необходимости.

Еще один хороший пример - подсчет слов в статье. Если вы сохраняете всю статью, в действительности нет необходимости сохранять количество слов, потому что его можно вычислить, когда статья будет «десериализована». Или подумайте о регистраторах; Logger экземпляры почти никогда не нуждаются в сериализации, поэтому их можно сделать временными.

user207421
1 июля 2015 в 13:30
67

Ваше «простое предложение» - всего лишь тавтология. Это ничего не объясняет. Тебе было бы лучше без него.

Arefe
5 ноября 2018 в 10:30
1

Это хорошее объяснение, когда поле должно быть transient

Tarun
18 января 2019 в 09:37
1

Поле интереса и количество слов - хорошие примеры временных полей.

Mohammed Siddiq
14 февраля 2019 в 22:55
1

Еще один хороший вариант использования: если у вашего объекта есть такие компоненты, как сокеты, и если вы хотите сериализовать, что произойдет с сокетом? Если будет сохраняться, после десериализации, что будет удерживать сокет? Имеет смысл сделать этот объект сокета как transient

Zoe
16 июня 2021 в 10:27
0

Единственное, что не относится к полям, которые должны быть помечены как временные, - это классы, которые буквально нельзя сериализовать ни по какой причине. Как уже упоминалось, это может быть Socket или какой-либо другой тип хранилища сеансов, или просто класс, который не допускает сериализацию - дело в том, что, кроме случаев, когда не необходимо сериализовать поле, бывают случаи, когда это активно запрещается, и transient становится требованием для сериализации интересующего класса. Кроме того, экземпляры Logger обычно статичны, и поэтому не обязательно должны быть transient в первую очередь.

avatar
Andrei Ciobanu
26 марта 2010 в 14:16
17

transient используется для обозначения того, что поле класса не требует сериализации. Вероятно, лучший пример - это поле Thread. Обычно нет причин для сериализации Thread, поскольку его состояние очень «зависит от потока».

TFennis
23 июля 2013 в 10:54
0

Поправьте меня, если я ошибаюсь, но Thread не сериализуем, поэтому он все равно будет пропущен?

A.H.
26 ноября 2013 в 22:45
4

@TFennis: если сериализуемый класс A ссылается на несериализуемый класс B (например, Thread в вашем примере), тогда A должен либо пометить ссылку как transient XOR должен переопределить процесс сериализации по умолчанию в порядке чтобы сделать что-нибудь разумное с B XOR, предположим, что на самом деле упоминаются только сериализуемые подклассы B (поэтому фактический подкласс должен позаботиться об их «плохом» родительском B) XOR принимает, что сериализация не удастся. Только в одном случае (помеченном как переходный) B автоматически и тихо пропускается.

user207421
1 июля 2015 в 13:30
3

@TFennis Нет, это вызовет исключение.

supercat
13 мая 2017 в 15:47
1

@ A.H .: Почему XOR? Я бы подумал, что код, который выполняет любую комбинацию этих вещей, будет работать, и некоторые комбинации могут быть полезны (например, переопределение процесса сериализации по умолчанию может быть полезно, даже если упоминаются только сериализуемые подклассы B, и наоборот).

avatar
DragonFax
28 мая 2009 в 02:20
17

Системы сериализации, отличные от родной Java-системы, также могут использовать этот модификатор. Например, Hibernate не будет сохранять поля, отмеченные модификатором @Transient или переходным процессом . Терракота также уважает этот модификатор.

Я полагаю, что переносное значение модификатора таково: «это поле предназначено только для использования в памяти. Не сохраняйте и не перемещайте его за пределы этой конкретной виртуальной машины. Это непереносимое». то есть вы не можете полагаться на его значение в другом пространстве памяти виртуальной машины. Как и volatile, означает, что вы не можете полагаться на определенную семантику памяти и потоков.

Joachim Sauer
26 марта 2010 в 14:13
15

Я думаю, что transient не было бы ключевым словом, если бы оно было разработано в настоящее время. Вероятно, они использовали бы аннотацию.

avatar
setzamora
26 мая 2009 в 12:19
5

Это необходимо, если вы не хотите делиться некоторыми конфиденциальными данными, связанными с сериализацией.

glen3b
9 мая 2014 в 18:24
8

Есть случаи использования, отличные от конфиденциальных данных, в которых вы можете не захотеть сериализовать поле. Например, вы, вероятно, никогда не захотите сериализовать Thread (например, кредит @ A.H.), И в этом случае вы бы отметили его как временный. Однако поток сам по себе не является конфиденциальными данными, просто нет логического смысла сериализовать его (и он не сериализуемый).

user207421
1 июля 2015 в 13:32
1

@ glen3b Этот случай не исключается этим ответом. Это, безусловно, необходимо в данном случае в упомянутом плакате.

avatar
Adrian Grigore
26 мая 2009 в 12:15
28

transient переменная - это переменная, которая не включается при сериализации класса.

Один из примеров, когда это может быть полезно, - это переменные, которые имеют смысл только в контексте конкретного экземпляра объекта и становятся недействительными после сериализации и десериализации объекта. В этом случае полезно, чтобы эти переменные стали null, чтобы вы могли при необходимости повторно инициализировать их полезными данными.

Mateen
20 февраля 2019 в 10:51
0

да, что-то вроде поля "пароль или crediCardPin" для членов класса.

avatar
Silfverstrom
26 мая 2009 в 12:15
7

Поскольку не все переменные имеют сериализуемую природу

Danny Gloudemans
26 марта 2014 в 15:30
50

Пожалуйста, предоставьте дополнительную информацию, когда дадите ответ.

avatar
Brian Agnew
26 мая 2009 в 12:13
87

Чтобы позволить вам определять переменные, которые вы не хотите сериализовать.

В объекте у вас может быть информация, которую вы не хотите сериализовать / сохранять (возможно, ссылка на родительский объект фабрики), или, возможно, нет смысла сериализовать. Пометка их как «переходных» означает, что механизм сериализации игнорирует эти поля.