Чому у Java є перехідні поля?


Відповіді:


1672

transientКлючове слово в Java використовується для вказівки того, що поле не повинно бути частиною сериализации (що означає порятунок, як в файл) процес.

З специфікації мови Java, видання Java SE 7 , розділ 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) є розділ, в якому обговорюється використання та представлений сценарій, коли transientключове слово використовується для запобігання серіалізації певних полів.


221
Але чому це ключове слово, а не анотація @DoNotSerialize?
Елазар Лейбович

333
Я здогадуюсь, це належить до того часу, коли в Java не було анотацій.
Пітер Віпперман

46
Мені дивно, що serializable є внутрішнім для Java. Він може бути реалізований як інтерфейс або абстрактний клас, який вимагає від користувачів способів перекриття методів читання та запису.
кале

7
@MJafar: readObject зазвичай прикутий до механізмів десеріалізації і, таким чином, викликається автоматично. Крім того, у багатьох випадках вам не потрібно її переосмислювати - реалізація за замовчуванням робить свою справу.
Майк Адлер

13
@caleb, ймовірно, через те, що сама робота з бінарними форматами є надзвичайно болісною на Java через відсутність непідписаних цілих чисел.
праворуч

434

Перш ніж зрозуміти 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, тому воно не зберігатиметься в постійному сховищі.

Джерело


25
Цей приклад взято з цього коду, ви можете прочитати його тут: javabeat.net/2009/02/what-is-transient-keyword-in-java
Кришна

11
Ця частина вважає мене дивним і, можливо, заплутаним: "Це означає, що стан об'єкта перетворюється в потік байтів і зберігається у файлі ". Мені здається, що більшість часу серіалізація не передбачає написання файлу (справа в точці: наступні приклади мереж)
Гарсія Хуртадо,

5
Приклад поганий, оскільки прізвище явно не є перехідною властивістю.
Рафаель

1
@Raphael Для мене приклад корисний і принаймні пояснює концепцію. Чи можете ви надати кращий приклад, якщо ви не знаєте?
Chaklader Asfak Arefe

@Yoda Ми можемо мати посилання на NameFormatterвикористаний для керування автомобілем toString(). Або все, що стосується конфігурації, перегляду чи ділової логіки ... на відміну від даних.
Рафаель

84

Щоб ви могли визначити змінні, які ви не хочете серіалізувати.

В об’єкті у вас може бути інформація, яку ви не хочете серіалізувати / зберігати (можливо, посилання на батьківський заводський об'єкт), або, можливо, не має сенсу серіалізувати. Позначення їх як "перехідних" означає, що механізм серіалізації ігнорує ці поля.


36

Мій невеликий внесок:

Що таке перехідне поле?
По суті, будь-яке поле, модифіковане transientключовим словом, є тимчасовим полем.

Чому потрібні перехідні поля на Java? Ключове слово дає деякий контроль над процесом сериализации і дозволяє виключити деякі властивості об'єктів з цього процесу. Процес серіалізації використовується для збереження об'єктів Java, здебільшого для того, щоб їхні стани зберігалися під час їх перенесення чи неактивності. Іноді має сенс не серіалізувати певні атрибути об’єкта. Які поля слід позначити перехідними? Тепер ми знаємо мету
transient


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

Ще один хороший приклад - кількість підрахунків у статті. Якщо ви зберігаєте всю статтю, насправді не потрібно зберігати кількість слів, оскільки її можна обчислити, коли стаття стає "дезаріалізованою". Або подумайте про лісоруби;Logger екземпляри майже ніколи не потребують серіалізації, тому вони можуть бути перехідними.


63
Ваше "просте речення" - це лише тавтологія. Це нічого не пояснює. Вам буде краще без цього.
користувач207421

1
Це гарне пояснення, де має бути полеtransient
Chaklader Asfak Arefe

1
поле зацікавлень та кількість слів є хорошими прикладами перехідних полів.
Тарун

1
Ще один вигідний випадок використання: Якщо у вашого об'єкта є такі компоненти, як сокети, і якщо ви хочете серіалізувати, то що відбувається з сокетом? Якщо б ви збереглися, після того, як ви дезаріалізуєте, що би тримало розетку? transient
Мухаммед

28

transientЗмінна є змінною , яка не може бути серіалізациі.

Один з прикладів, коли це може бути корисним, - це змінні, які мають сенс лише в контексті конкретного об'єкта, які стають недійсними після того, як ви серіалізуєте та десеріалізуєте об'єкт. У цьому випадку корисно, щоб ці змінні стали nullзамість них, щоб ви могли повторно ініціалізувати їх з корисними даними, коли це необхідно.


так, такі речі, як "пароль або crediCardPin", члени поля класу.
Матін

17

transientвикористовується для вказівки, що поле класу не потрібно серіалізувати. Напевно, найкращий приклад - Threadполе. Зазвичай не існує причин для серіалізації Thread, оскільки його стан дуже «специфічний для потоку».


Виправте мене, якщо я помиляюся, але нитка не є серіалізаційною, тому вона все одно буде пропущена?
TFennis

3
@TFennis: Якщо серіалізаційний клас Aпосилається на не серіалізаційний клас B(як Threadу вашому прикладі), то Aповинен або позначити посилання, оскільки transientXOR повинен переосмислити процес серіалізації за замовчуванням, щоб зробити щось розумне з BXOR, припустимо, що Bнасправді посилаються лише серіалізаційні підкласи (тому власне підклас повинен піклуватися про свого «поганого» батька B) XOR приймає, що серіалізація не вдасться. Лише в одному випадку (позначеному як перехідний) Bавтоматично і безшумно пропускається.
AH

3
@TFennis Ні, це спричинить виняток.
користувач207421

1
@AH: Чому XOR? Я думаю, що код, який робив би будь-яку комбінацію цих речей, спрацював, і деякі комбінації можуть бути корисними (наприклад, переосмислення процесу серіалізації за замовчуванням може бути корисним, навіть якщо на них посилаються лише серіалізаційні підкласи B, і навпаки).
supercat

15

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

Я вважаю, що переносне значення модифікатора полягає в тому, що "це поле призначене лише для використання в пам'яті. Не зберігайте і не переміщуйте його за межами цієї конкретної ВМ. Нічим не переносяться". тобто ви не можете розраховувати на його значення в іншому просторі пам'яті VM. Так само, як летючі засоби, ви не можете розраховувати на певну семантику пам'яті та потоків.


14
Я думаю, transientце не було б ключовим словом, якби воно було розроблено в цей час. Вони, ймовірно, будуть використовувати примітку.
Йоахім Зауер


7

Перш ніж відповісти на це запитання, я мушу пояснити вам СЕРІАЛІЗАЦІЮ , адже якщо ви зрозумієте, що це означає серіалізація в науковому комп’ютері, ви можете легко зрозуміти це ключове слово.

Серіалізація Коли об'єкт передається через мережу / зберігається на фізичному носії (файл, ...), об'єкт повинен бути "серіалізований". Серіалізація перетворює ряд об'єктів статусу байт. Ці байти надсилаються в мережу / зберігаються, і об'єкт заново створюється з цих байтів.
Приклад

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

Тепер , якщо ви хочете зробити НЕ TRANSFERT / збереження поле цього об'єкта SO , ви можете використовувати ключове слово transient

private transient attr2;

Приклад


6

Це потрібно, коли ви не хочете ділитися чутливими даними, які йдуть із серіалізацією.


7
Існують випадки використання, крім чутливих даних, у яких ви, можливо, не хочете серіалізувати поле. Наприклад, ви, ймовірно, ніколи не хочете серіалізувати Thread(наприклад, кредит на @AH), і в такому випадку ви позначите його як перехідне. Однак нитка сама по собі не є чутливими даними, вона просто не має ніякого логічного сенсу її серіалізувати (і це не можна серіалізувати).
glen3b

1
@ glen3b Ця відповідь не виключена цією відповіддю. Це, безумовно, потрібно, коли речі стоять у випадку згаданого плаката.
користувач207421

3

Згідно з перехідним значенням google == триває лише короткий час; непостійний.

Тепер, якщо ви хочете зробити що-небудь тимчасове в Java, використовуйте ключове слово перехідне.

Q: де використовувати перехідне?

Відповідь: Як правило, у Java ми можемо зберігати дані у файли, отримуючи їх у змінних і записуючи ці змінні у файли, цей процес відомий як серіалізація. Тепер, якщо ми хочемо уникнути запису змінних даних у файл, ми зробимо цю змінну перехідною.

transient int result=10;

Примітка: перехідні змінні не можуть бути локальними.


0

Простіше кажучи, перехідне ключове слово java захищає поля від Serialize як їх непрохідні поля, що зустрічаються.

У цьому фрагменті коду наш абстрактний клас BaseJob реалізує інтерфейс Serializable, ми поширюємося з BaseJob, але нам не потрібно серіалізувати віддалені та локальні джерела даних; серіалізувати лише поля організаціїName та 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;

   }
}

0

Спрощений приклад коду для перехідних ключових слів.

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);
    }
}

0

Поле, яке оголошується перехідним модифікатором, не братиме участі в серіалізованому процесі. Коли об'єкт серіалізується (зберігається в будь-якому стані), значення його перехідних полів ігноруються в послідовному поданні, тоді як поля, відмінні від перехідних полів, будуть брати участь у процесі серіалізації. Саме це і є основною метою перехідного ключового слова.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.