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

1345

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

Теги:
field
transient

14 ответов

1425
Лучший ответ

Ключевое слово 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 используется для предотвращения сериализации определенных полей.

  • 195
    Но почему это ключевое слово, а не аннотация @DoNotSerialize ?
  • 299
    Я думаю, это относится ко времени, когда в Java не было аннотаций.
Показать ещё 13 комментариев
365

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

Источник

  • 20
    Этот пример взят из этого кода, вы можете прочитать его здесь: javabeat.net/2009/02/what-is-transient-keyword-in-java
  • 10
    Эта часть кажется мне странной и, возможно, сбивающей с толку: «Это означает, что состояние объекта преобразуется в поток байтов и сохраняется в файле ». Мне кажется, что в большинстве случаев сериализация не связана с записью в файл (наглядный пример: примеры сетевых подключений)
Показать ещё 4 комментария
76

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

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

30

Мой небольшой вклад:

Что такое переходное поле?
В принципе, любое поле, измененное ключевым словом transient является переходным полем.

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

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

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

  • 60
    Ваше «простое предложение» - просто тавтология. Это ничего не объясняет. Тебе было бы лучше без этого.
  • 1
    Это хорошее объяснение, где поле должно быть transient
Показать ещё 2 комментария
22

transient переменная - это переменная, которая не может быть сериализована.

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

  • 0
    да, что-то вроде членов поля «password or crediCardPin».
13

transient используется, чтобы указать, что поле класса не нужно сериализовать. Вероятно, лучшим примером является поле Thread. Обычно нет причин для сериализации Thread, поскольку его состояние очень "специфично для потока".

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

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

Я считаю, что образный смысл модификатора - это "это поле для использования только в памяти". Не сохраняйте или не перемещайте его за пределы этой конкретной виртуальной машины каким-либо образом. т.е. вы не можете полагаться на его значение в другом пространстве памяти VM. Подобно volatile, вы не можете полагаться на определенную семантику памяти и семантики.

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

Сериализация - это процесс сохранения состояний объектов в постоянном формате (например, поток файлов или базы данных) и последующее восстановление их из потока (де-сериализация). В 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, являются статическими, окончательными, абстрактными, синхронизированными, нативными, летучими, переходными и strictfp.

В следующей таблице приведен список спецификаторов доступа и модификаторов 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
9

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

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

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

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

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

Теперь, если вы не хотите TRANSFERT/ SAVED этого объекта SO, вы можете использовать ключевое слово > transient

private transient attr2;

Пример

3

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

  • 7
    Существуют варианты использования, отличные от конфиденциальных данных, в которых вы можете не захотеть сериализовать поле. Например, вы , вероятно , никогда не хотел бы , чтобы сериализовать Thread (кредит @AH, например), в этом случае вы бы пометить его как переходный. Однако поток сам по себе не является конфиденциальными данными, просто нет логического смысла его сериализовывать (и он не сериализуем).
  • 1
    @ glen3b Этот случай не исключен этим ответом. Это, безусловно, необходимо, так как дела обстоят в случае, когда упоминается постер.
1

Проще говоря, переходное ключевое слово 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;

   }
}
1

согласно google переходный смысл == длится только на короткое время; непостоянно.

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

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

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

transient int result = 10;

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

0

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

    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. Мы можем использовать переменные для тех переменных-членов, которых мы не хотим записывать на диск.

Надеюсь, поможет.!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню