Dlaczego Java ma zmienne przejściowe?


Odpowiedzi:


1672

Słowo transientkluczowe w Javie służy do wskazania, że ​​pole nie powinno być częścią procesu serializacji (co oznacza zapisanie, jak w pliku).

Ze specyfikacji języka Java, Java SE 7 Edition , rozdział 8.3.1.3. transientPola :

Zmienne mogą być zaznaczone, transientaby wskazać, że nie są częścią trwałego stanu obiektu.

Na przykład, możesz mieć pola, które pochodzą z innych pól i powinieneś to zrobić tylko programowo, zamiast utrzymywania stanu przez serializację.

Oto GalleryImageklasa, która zawiera obraz i miniaturę pochodzącą z obrazu:

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

W tym przykładzie thumbnailImagejest to obraz miniatury generowany przez wywołanie generateThumbnailmetody.

thumbnailImagePole jest oznaczone jako transient, więc tylko oryginalna imagejest w odcinkach zamiast utrzymującej zarówno oryginalny obraz i obraz miniatury. Oznacza to, że potrzeba mniej pamięci do zapisania obiektu zserializowanego. (Oczywiście może to być lub nie być pożądane w zależności od wymagań systemu - to tylko przykład.)

W chwili deserializacji readObjectmetoda jest wywoływana w celu wykonania wszelkich operacji niezbędnych do przywrócenia stanu obiektu z powrotem do stanu, w którym nastąpiła serializacja. W tym przypadku należy wygenerować miniaturę, więc readObjectmetoda zostanie zastąpiona, aby miniaturka została wygenerowana przez wywołanie generateThumbnailmetody.

Aby uzyskać dodatkowe informacje, w artykule Poznaj sekrety interfejsu API Java Serialization API (który pierwotnie był dostępny w Sun Developer Network) znajduje się sekcja omawiająca użycie i przedstawiająca scenariusz, w którym transientsłowo kluczowe jest używane do zapobiegania serializacji niektórych pól.


221
Ale dlaczego jest to słowo kluczowe, a nie adnotacja @DoNotSerialize?
Elazar Leibovich

333
Wydaje mi się, że jest to własność do czasu, gdy nie było adnotacji w Javie.
Peter Wippermann

46
Wydaje mi się dziwne, że serializowalne jest wewnętrzne w Javie. Może być zaimplementowany jako interfejs lub klasa abstrakcyjna, która wymaga od użytkowników zastąpienia metod odczytu i zapisu.
caleb

7
@MJafar: readObject jest zwykle połączony w mechanizmy deserializacji i dlatego jest wywoływany automatycznie. Ponadto w wielu przypadkach nie trzeba go zastępować - domyślna implementacja załatwia sprawę.
Mike Adler,

13
@caleb prawdopodobnie dlatego, że radzenie sobie z formatami binarnymi jest niezwykle bolesne w Javie z powodu braku niepodpisanych liczb całkowitych.
prawej

434

Przed zrozumieniem transientsłowa kluczowego należy zrozumieć pojęcie serializacji. Jeśli czytelnik wie o serializacji, pomiń pierwszy punkt.

Co to jest serializacja?

Serializacja to proces utrwalania stanu obiektu. Oznacza to, że stan obiektu jest konwertowany na strumień bajtów, który ma być używany do utrwalania (np. Przechowywania bajtów w pliku) lub przesyłania (np. Wysyłania bajtów przez sieć). W ten sam sposób możemy użyć deserializacji, aby przywrócić stan obiektu z bajtów. Jest to jedna z ważnych koncepcji w programowaniu Java, ponieważ serializacja jest najczęściej stosowana w programowaniu sieciowym. Obiekty, które muszą zostać przesłane przez sieć, muszą zostać przekonwertowane na bajty. W tym celu każda klasa lub interfejs musi implementować Serializableinterfejs. Jest to interfejs znaczników bez żadnych metod.

Teraz jakie jest transientsłowo kluczowe i jakie jest jego przeznaczenie?

Domyślnie wszystkie zmienne obiektu są przekształcane w stan trwały. W niektórych przypadkach możesz chcieć uniknąć utrwalania niektórych zmiennych, ponieważ nie musisz ich utrzymywać. Możesz więc zadeklarować te zmienne jako transient. Jeśli zmienna zostanie zadeklarowana jako transient, nie zostanie utrwalona. To jest główny cel tego transientsłowa kluczowego.

Chcę wyjaśnić powyższe dwa punkty następującym przykładem:

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

A wynik będzie następujący:

First Name : Steve
Middle Name : null
Last Name : Jobs

Drugie imię jest zadeklarowane jako transient, więc nie będzie przechowywane w pamięci trwałej.

Źródło


25
Ten przykład pochodzi z tego kodu, możesz go przeczytać tutaj: javabeat.net/2009/02/what-is-transient-keyword-in-java
Krishna

11
Ta część wydaje mi się dziwna i być może myląca: „Oznacza to, że stan obiektu jest konwertowany na strumień bajtów i przechowywany w pliku ”. Wydaje mi się, że w większości przypadków serializacja nie wymaga zapisania do pliku (przypadek: poniższe przykłady sieci)
Garcia Hurtado

5
Przykład jest zły, ponieważ drugie imię wyraźnie nie jest własnością przejściową.
Raphael

1
@Raphael Dla mnie przykład jest pomocny i przynajmniej wyjaśnia koncepcję. Czy podałbyś lepszy przykład, jeśli jesteś świadomy?
Chaklader Asfak Arefe

@Yoda Możemy mieć odniesienie do NameFormatterużywanego do prowadzenia pojazdu toString(). Lub cokolwiek innego związanego z konfiguracją, przeglądaniem lub logiką biznesową ... w przeciwieństwie do danych.
Raphael,

84

Aby umożliwić zdefiniowanie zmiennych, których nie chcesz serializować.

W obiekcie możesz mieć informacje, których nie chcesz serializować / utrwalać (być może odniesienie do nadrzędnego obiektu fabryki), a może serializacja nie ma sensu. Oznaczenie ich jako „przejściowych” oznacza, że ​​mechanizm serializacji zignoruje te pola.


36

Mój mały wkład:

Co to jest pole przejściowe?
Zasadniczo każde pole zmodyfikowane transientsłowem kluczowym jest polem przejściowym.

Dlaczego pola przejściowe są potrzebne w Javie?
Słowo transientkluczowe daje pewną kontrolę nad procesem serializacji i pozwala wykluczyć niektóre właściwości obiektu z tego procesu. Proces serializacji służy do utrwalania obiektów Java, głównie w celu zachowania ich stanów podczas przesyłania lub nieaktywności. Czasami sensowne jest, aby nie szeregować pewnych atrybutów obiektu.

Które pola należy oznaczyć jako przejściowe?
Teraz znamy celtransientsłowa kluczowego i pola przejściowe, ważne jest, aby wiedzieć, które pola oznaczyć jako przejściowe. Pola statyczne również nie są serializowane, więc odpowiednie słowo kluczowe również załatwi sprawę. Ale może to zrujnować twój projekt klasowy; tutaj transientsłowo kluczowe przychodzi na ratunek. Staram się nie dopuszczać serializacji pól, których wartości można wyprowadzić z innych, więc zaznaczam je jako przejściowe. Jeśli masz pole o nazwie, interestktórego wartość można obliczyć z innych pól ( principal, rate& time), nie ma potrzeby serializowania go.

Innym dobrym przykładem jest liczenie słów w artykułach. Jeśli zapisujesz cały artykuł, naprawdę nie ma potrzeby zapisywania liczby słów, ponieważ można go obliczyć, gdy artykuł zostanie „zdezrializowany”. Lub pomyśl o rejestratorach;Logger instancje prawie nigdy nie muszą być serializowane, dzięki czemu mogą stać się przejściowe.


63
Twoje „proste zdanie” jest jedynie tautologią. To nic nie wyjaśnia. Lepiej byłoby bez niego.
user207421,

1
To dobre wytłumaczenie, gdzie powinno być poletransient
Chaklader Asfak Arefe

1
pola zainteresowań i liczba słów są dobrymi przykładami pól przejściowych.
Tarun

1
Kolejny dobry przypadek użycia: jeśli twój obiekt ma komponenty takie jak gniazda i jeśli chcesz serializować, co stanie się z gniazdem? Jeśli będzie się utrzymywać, po deserializacji, co utrzyma gniazdo? transient
Sensowne jest nadanie

28

transientZmienna jest zmienną, która nie może być w odcinkach.

Jednym z przykładów, kiedy może się to przydać, są zmienne, które mają sens tylko w kontekście konkretnej instancji obiektu i które stają się niepoprawne po serializacji i deserializacji obiektu. W takim przypadku przydatne jest, aby zmienne te stały się nullzamiast nich, aby w razie potrzeby można je ponownie zainicjować przydatnymi danymi.


tak, coś takiego jak członkowie klasy „hasło lub crediCardPin”.
Mateen

17

transientsłuży do wskazania, że ​​pole klasy nie musi być serializowane. Prawdopodobnie najlepszym przykładem jest Threadpole. Zwykle nie ma powodu, aby serializować a Thread, ponieważ jego stan jest bardzo „specyficzny dla przepływu”.


Popraw mnie, jeśli się mylę, ale Wątek nie jest serializowany, więc i tak zostanie pominięty?
TFennis,

3
@TFennis: Jeśli klasa możliwa do serializacji Aodwołuje się do klasy, której nie można serializować B(jak Threadw twoim przykładzie), to Aalbo zaznacz to odwołanie, ponieważ transientXOR musi przesłonić domyślny proces serializacji, aby zrobić coś rozsądnego z BXOR, zakładając, że tylko podklasy możliwe do serializacji Bsą faktycznie przywoływane (więc rzeczywista podklasa musi dbać o swojego „złego” rodzica B). XOR akceptuje, że serializacja się nie powiedzie. Tylko w jednym przypadku (oznaczonym jako przejściowy) Bjest automatycznie i cicho pomijany.
AH

3
@TFennis Nie, spowoduje to wyjątek.
user207421,

1
@AH: Dlaczego XOR? Myślę, że kod, który wykonałby dowolną kombinację tych rzeczy, działałby, a niektóre kombinacje mogą być przydatne (np. Przesłanianie domyślnego procesu serializacji może być przydatne, nawet jeśli przywoływane są tylko możliwe do serializacji podklasy B i vice versa).
supercat

15

W systemach innych niż natywna Java można także użyć tego modyfikatora. Hibernacja, na przykład, nie utrwali pól oznaczonych @Transient lub modyfikatorem transient . Terakota również szanuje ten modyfikator.

Uważam, że symboliczne znaczenie modyfikatora brzmi: „to pole jest przeznaczone wyłącznie do użytku w pamięci. Nie utrwalaj go ani nie przenoś w żaden sposób poza tę konkretną maszynę wirtualną. Nie jest przenośny”. tzn. nie można polegać na jego wartości w innym obszarze pamięci maszyny wirtualnej. Podobnie jak niestabilna oznacza, że ​​nie można polegać na pewnej pamięci i semantyce wątków.


14
Myślę, że transientto nie byłoby słowo kluczowe, gdyby zostało zaprojektowane w tym czasie. Prawdopodobnie użyliby adnotacji.
Joachim Sauer


7

Zanim odpowiem na to pytanie, muszę wyjaśnić SERIALIZACJĘ , ponieważ jeśli rozumiesz, co to znaczy serializacja w komputerze naukowym, możesz łatwo zrozumieć to słowo kluczowe.

Serializacja Gdy obiekt jest przesyłany przez sieć / zapisywany na nośniku fizycznym (plik, ...), obiekt musi zostać „zserializowany”. Serializacja konwertuje serie obiektów statusu bajtów. Te bajty są wysyłane do sieci / zapisywane, a obiekt jest ponownie tworzony z tych bajtów.
Przykład

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

Teraz, jeśli chcesz TO NIE TRANSFERT / Zapisane pola tego obiektu tak , można użyć słów kluczowych transient

private transient attr2;

Przykład


6

Jest to potrzebne, gdy nie chcesz udostępniać poufnych danych związanych z serializacją.


7
Istnieją przypadki użycia inne niż wrażliwe dane, w których możesz nie chcieć serializować pola. Na przykład prawdopodobnie nigdy nie chciałbyś serializować Thread(na przykład @AH), w którym to przypadku oznaczysz go jako przejściowy. Jednak wątek sam w sobie nie jest wrażliwymi danymi, po prostu nie ma logicznego sensu, aby go serializować (i nie można go serializować).
glen3b

1
@ glen3b Ta sprawa nie jest wykluczona z tej odpowiedzi. Jest to z pewnością potrzebne, ponieważ sprawy stoją w przypadku wspomnianego plakatu.
user207421,

3

Zgodnie z Google przejściowe znaczenie == trwające tylko przez krótki czas; nietrwały.

Teraz, jeśli chcesz, aby cokolwiek było przejściowe w Javie, użyj przejściowego słowa kluczowego.

P: gdzie użyć przejściowego?

Odp .: Zasadniczo w Javie możemy zapisywać dane w plikach, gromadząc je w zmiennych i zapisując te zmienne w plikach, proces ten nazywany jest serializacją. Teraz, jeśli chcemy uniknąć zapisywania danych zmiennych do pliku, zmienilibyśmy tę zmienną jako przejściową.

transient int result=10;

Uwaga: zmienne przejściowe nie mogą być lokalne.


0

Mówiąc najprościej, słowo przejściowe java chroni pola przed serializacją, ponieważ ich pola nieprzemijające przeciwstawiają się części.

W tym fragmencie kodu nasza klasa abstrakcyjna implementuje interfejs Serializable BaseJob, rozszerzamy go z BaseJob, ale nie musimy serializować zdalnych i lokalnych źródeł danych; serializuj tylko pola nazwa_organizacji i 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

Uproszczony przykładowy kod przejściowego słowa kluczowego.

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

Pole zadeklarowane za pomocą przejściowego modyfikatora nie będzie brać udziału w procesie serializacji. Gdy obiekt jest szeregowany (zapisywany w dowolnym stanie), wartości jego pól przejściowych są ignorowane w reprezentacji szeregowej, podczas gdy pole inne niż pola przejściowe bierze udział w procesie serializacji. To jest główny cel przejściowego słowa kluczowego.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.