JavaRush /Java Blog /Random-TL /Ano ang itinatago ng transient modifier sa Java?
Анзор Кармов
Antas
Санкт-Петербург

Ano ang itinatago ng transient modifier sa Java?

Nai-publish sa grupo
Kamusta! Sa artikulong ngayon, titingnan natin ang lumilipas na modifier sa Java. Pag-usapan natin kung bakit kailangan ang modifier na ito at kung paano ito gamitin nang tama. Go! Ano ang itinatago ng transient modifier sa Java - 1

Tandaan natin ang serialization

Ginagamit ang modifier transientsa proseso ng pagse-serialize at pag-deserialize ng mga bagay. Kaya't pag-usapan muna natin ito nang maikli. Ano ang itinatago ng transient modifier sa Java - 2Ipagpalagay na mayroon kaming ilang bagay, at mayroon itong mga patlang, na ang bawat isa ay may ilang halaga. Ang lahat ng ito ay tinatawag na estado ng bagay. Ang serialization ay ang conversion ng estado ng isang object sa isang sequence ng mga byte. Ang mga byte na ito ay karaniwang nakaimbak sa ilang file. Ang deserialization ay ang kabaligtaran na proseso. Isipin natin na na-serialize natin ang isang bagay sa mga byte at iniimbak ang hanay ng mga byte na ito sa ilang file. Kapag deserializing, kailangan ng programa:
  1. Magbasa ng isang hanay ng mga byte mula sa isang file.
  2. Bumuo ng isang paunang bagay mula sa hanay ng mga byte na ito at itakda ang bawat field sa halaga na mayroon ang bagay sa oras ng serialization.
Kailan ito maaaring maging kapaki-pakinabang? Halimbawa, kapag gusto naming i-save ng program ang estado nito kapag isinara at i-restore ito sa susunod na pag-on nito. Kapag isinara mo ang IntelliJ IDEA, malamang na magkakaroon ka ng parehong mga tab at klase na bukas sa susunod na i-on mo ito

Tandaan natin ang serialization sa pagsasanay

Well, ngayon tingnan natin ang serialization sa pagsasanay. Kung gusto mong mas maunawaan ang paksa, inirerekomenda naming basahin ang materyal na Serialization at deserialization sa Java . Buweno, sa artikulong ito ay pupunta tayo sa itaas at dumiretso sa mga halimbawa. Sabihin nating mayroon tayong klase Userna may set ng ilang field, getter at setter, at isang paraan toString:
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    private String firstName;
    private String lastName;
    private String email;
    private LocalDate birthDate;
    private String login;
    private String password;

    public User() {}

    public User(String firstName, String lastName, String email, LocalDate birthDate, String login, String password) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
        this.birthDate = birthDate;
        this.login = login;
        this.password = password;
    }

    /*
        Геттеры, Сеттеры
     */

    @Override
    public String toString() {
        return "User{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", email='" + email + '\'' +
                ", birthDate=" + birthDate +
                ", login='" + login + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
Gusto naming i-serialize ang mga bagay ng klase na ito sa hinaharap. Sumulat tayo ng isang pamamaraan na kumukuha ng isang bagay Userat isang string path- ang landas sa file kung saan ise-save natin ang mga byte:
static void serialize(User user, String path) throws IOException {
    FileOutputStream outputStream = null;
    ObjectOutputStream objectOutputStream = null;
    try {
        //create 2 threads to serialize the object and save it to a file
        outputStream = new FileOutputStream(path);
        objectOutputStream = new ObjectOutputStream(outputStream);

        // сохраняем an object в файл
        objectOutputStream.writeObject(user);
    } finally {
        // Закроем потоки в блоке finally
        if (objectOutputStream != null) {
            objectOutputStream.close();
        }
        if (outputStream != null) {
            outputStream.close();
        }
    }
}
Magsusulat din kami ng isang paraan para sa deserialization. Ang pamamaraan ay tumatagal ng isang string path(ang landas patungo sa file kung saan ang bagay ay "mai-load") at nagbabalik ng isang bagay na may uri User:
static User deserialize(String path) throws IOException, ClassNotFoundException {
    FileInputStream fileInputStream = null;
    ObjectInputStream objectInputStream = null;

    try {

        //создаем 2 потока для десериализации an object из file
        fileInputStream = new FileInputStream(path);
        objectInputStream = new ObjectInputStream(fileInputStream);

        //загружаем an object из file
        return  (User) objectInputStream.readObject();
    } finally {
        if (fileInputStream != null) {
            fileInputStream.close();
        }
        if (objectInputStream != null) {
            objectInputStream.close();
        }
    }
}
Ang lahat ng mga tool ay handa nang gamitin. Oras na para hatiin ang mga byte sa mga atom . Sumulat tayo ng paraan mainkung saan gumagawa tayo ng object ng klase Userat i-serialize ito. Pagkatapos ay ilo-load namin ito at ihahambing sa kung ano ang orihinal:
public static void main(String[] args) throws IOException, ClassNotFoundException {
    // вставьте свой путь до file
    final String path = "/home/zor/user.ser";

    // create our object
    User user = new User();
    user.setFirstName("Stefan");
    user.setLastName("Smith");
    user.setEmail("ssmith@email.com");
    user.setBirthDate(LocalDate.of(1991, 7, 16));
    user.setLogin("ssmith");
    user.setPassword("gemma_arterton_4ever_in_my_heart91");

    System.out.println("Initial user: " + user + "\r\n");


    serialize(user, path);
    User loadedUser = deserialize(path);
    System.out.println("Loaded user from file: " + loadedUser + "\r\n");
}
Kung patakbuhin natin ang pamamaraan, makikita natin ang sumusunod na output:
Initial user: User{firstName='Stefan', lastName='Smith', email='ssmith@email.com', birthDate=1991-07-16, login='ssmith', password='gemma_arterton_4ever_in_my_heart91'}

Loaded user from file: User{firstName='Stefan', lastName='Smith', email='ssmith@email.com', birthDate=1991-07-16, login='ssmith', password='gemma_arterton_4ever_in_my_heart91'}
Tulad ng nakikita mo mula sa output, ang mga bagay ay magkapareho. Ngunit may maliit ngunit... At dito mismo pumapasok ang kahihiyan ng mga Espanyol transient .

Modifier (sa wakas)transient

May nalilito ba na na-save namin ang password ng user? Lalo na ang ganoong password... Oo, oo, kami mismo ang nakaisip nito, ngunit pa rin... Minsan may mga sitwasyon kung saan ang ilang mga patlang ay hindi mai-serialize, o mas mahusay na huwag gawin ito. Sa halimbawa sa itaas, gusto kong i-save ang lahat ng field maliban sa password. Paano ito makakamit? Sagot: gamitin ang modifier transient. transientay isang modifier na inilagay bago ang isang field ng klase (katulad ng iba pang mga modifier tulad ng public, finalatbp.) upang ipahiwatig na ang field ay hindi dapat na serialized. Ang mga field na minarkahan ng keyword transientay hindi serialized. Ngayon, i-edit natin ang halimbawa kasama ang ating user upang itama ang isang maliit na kalituhan at hindi i-save ang password ng user. Upang gawin ito, markahan ang kaukulang field sa klase gamit ang keyword transient:
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    private String firstName;
    private String lastName;
    private String email;
    private LocalDate birthDate;
    private String login;
    private transient String password;

    /*
        Конструкторы, геттеры, сеттеры, toString...
     */
}
Kung patakbuhin namin ang pamamaraan mula sa halimbawa sa itaas muli main, makikita namin na ang password ay hindi nai-save:
Initial user: User{firstName='Stefan', lastName='Smith', email='ssmith@email.com', birthDate=1991-07-16, login='ssmith', password='gemma_arterton_4ever_in_my_heart91'}

Loaded user from file: User{firstName='Stefan', lastName='Smith', email='ssmith@email.com', birthDate=1991-07-16, login='ssmith', password='null'}
Mahusay, nakamit namin ang aming layunin at hindi nag-iimbak ng kumpidensyal na impormasyon. Lalo na ang ganitong uri ng impormasyon... (sorry)

Kailan gagamitin ang transient?

Ang isang halimbawa sa isang user ay kailangan upang sumisid sa konteksto ng serialization. Ngayon, pag-usapan natin nang mas partikular kung kailan gagamitin ang modifier transient.

  • Mga field na kinakalkula gamit ang programmatically

Minsan ang ilang mga klase ay may mga field na kinakalkula batay sa iba pang mga field o iba pang impormasyon. Ang mga ito ay kalkulado, kaya na magsalita, sa mabilisang. Upang magbigay ng halimbawa ng ganoong larangan, isipin natin ang isang order sa isang online na tindahan o ilang serbisyo sa paghahatid ng pagkain. Ang bawat order, bukod sa iba pang impormasyon, ay binubuo ng isang listahan ng mga kalakal at isang kabuuang halaga. Ito naman ay binubuo ng kabuuang halaga ng bawat produkto. Ito ay lumalabas na ang pangwakas na gastos ay hindi dapat itakda "sa pamamagitan ng kamay": dapat itong kalkulahin sa programmatically, pagbubuod ng halaga ng lahat ng mga kalakal. Ang mga field na tulad nito na dapat kalkulahin sa programmatically ay hindi kailangang i-serialize. Samakatuwid, minarkahan namin sila ng isang modifier transient.
class Order implements Serializable {

    private List items;
    private transient BigDecimal totalAmount; //вычисляется на ходу

}

  • Mga field na may pribadong impormasyon

Mayroon ding ilang mga klase na nag-iimbak ng pribadong impormasyon. Tiningnan namin ang isang halimbawa ng ganoong klase sa simula ng artikulo. Hindi mo dapat payagan ang naturang impormasyon na tumagas sa labas ng JVM. Samakatuwid, ang mga patlang na may ganoong data ay dapat na minarkahan ng isang modifier transientkung ikaw ay magse-serialize ng ganoong klase.

  • Mga field na hindi nagpapatupad ng interfaceSerializable

Minsan ang isang klase ay naglalaman ng mga field - object ng ibang klase na hindi nagpapatupad ng interface Serializable. Ang mga halimbawa ng naturang mga field ay mga logger, I/O stream, mga bagay na nag-iimbak ng mga koneksyon sa database at iba pang mga utility class. Kung susubukan mong i-serialize ang isang object na naglalaman ng mga non-serialize na field, makakatanggap ka ng error java.io.NotSerializableException. Upang maiwasan ito, ang lahat ng mga patlang na hindi nagpapatupad ng interface Serializableay dapat na markahan ng isang modifier transient.
public class FileReader implements Serializable {
    // Первые 2 поля не реализуют Serializable
    // Помечаем их How transient поля
    private transient InputStream is;
    private transient BufferedReader buf;
    private String fileName;

    // Constructors, Getters, Setters

    public String readFile() throws IOException {
        try {
            is = new FileInputStream(fileName);
            buf = new BufferedReader(new InputStreamReader(is));
            String line = buf.readLine();
            StringBuilder sb = new StringBuilder();
            while (line != null) {
                sb.append(line).append("\n");
                line = buf.readLine();
            }
            return sb.toString();
        } finally {
            if (buf != null) {
                buf.close();
            }
            if (is != null) {
                is.close();
            }
        }
    }
}

  • Mga patlang na may impormasyon tungkol sa estado ng bagay

Well, isang huling bagay. Hindi na kailangang i-serialize ang mga field na hindi bahagi ng impormasyon ng estado ng object. Ang mga halimbawa sa itaas ay nasa ilalim ng panuntunang ito. Ngunit maaari mo ring isama dito ang lahat ng iba pang mga field na idinagdag para sa pag-debug o upang magsagawa ng ilang uri ng function ng serbisyo na hindi nagdadala ng impormasyon tungkol sa estado ng bagay.

transientAtfinal

Mga resulta

Iyon lang. Ngayon ay pinag-usapan natin ang modifier transient:
  1. Naalala namin ang serialization sa teorya at kasanayan.
  2. Napagtanto namin na upang hindi ma-serialize ang ilang mga field ng klase, kailangan nilang markahan ng modifier transient.
  3. Tinalakay namin kung anong mga sitwasyon ang dapat gamitin ng modifier na ito. Mayroong apat na ganoong sitwasyon:
    1. mga patlang na kinakalkula gamit ang program;
    2. mga patlang na naglalaman ng lihim na impormasyon;
    3. mga patlang na hindi nagpapatupad ng interface Serializable;
    4. mga field na hindi bahagi ng estado ng object.
Mga komento
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION