JavaRush /Java Blogu /Random-AZ /Keçid dəyişdirici Java-da nəyi gizlədir?
Анзор Кармов
Səviyyə
Санкт-Петербург

Keçid dəyişdirici Java-da nəyi gizlədir?

Qrupda dərc edilmişdir
Salam! Bugünkü məqaləmizdə Java-da keçid dəyişdiricisinə baxacağıq. Bu modifikatorun nə üçün lazım olduğunu və onu necə düzgün istifadə edəcəyini danışaq. Get! Keçid dəyişdirici Java-da nəyi gizlədir - 1

Serializasiyanı xatırlayaq

Modifikator transientobyektlərin seriallaşdırılması və sıradan çıxarılması prosesində istifadə olunur. Beləliklə, əvvəlcə bu barədə qısaca danışaq. Keçid dəyişdiricisi Java-da nəyi gizlədir - 2Tutaq ki, bizim hansısa obyektimiz var və onun hər biri müəyyən dəyərə malik sahələri var. Bütün bunlara obyektin vəziyyəti deyilir. Serializasiya obyektin vəziyyətinin bayt ardıcıllığına çevrilməsidir. Bu baytlar adətən hansısa faylda saxlanılır. Deserializasiya əks prosesdir. Təsəvvür edək ki, biz bir obyekti baytlara seriallaşdırdıq və bu bayt dəstini hansısa faylda saxladıq. Seriyadan çıxararkən proqrama lazımdır:
  1. Fayldan bayt dəstini oxuyun.
  2. Bu bayt dəstindən ilkin obyekt qurun və hər bir sahəni obyektin seriallaşdırma zamanı malik olduğu qiymətə təyin edin.
Bu nə vaxt faydalı ola bilər? Məsələn, proqramın bağlanarkən vəziyyətini saxlamasını və növbəti dəfə işə salındıqda onu bərpa etməsini istədikdə. IntelliJ IDEA-nı bağladığınız zaman onu növbəti dəfə yandırdığınız zaman çox güman ki, eyni tab və siniflər açılacaq.

Təcrübədə seriallaşdırmanı xatırlayaq

Yaxşı, indi praktikada seriallaşdırmaya baxaq. Mövzunu daha yaxşı başa düşmək istəyirsinizsə, Java-da Serializasiya və seriyadan çıxarma materialını oxumağı tövsiyə edirik . Yaxşı, bu məqalədə yuxarıdan keçəcəyik və birbaşa nümunələrə keçəcəyik. Tutaq ki, bizdə Userbəzi sahələr, alıcılar və təyinedicilər dəsti və metodu olan bir sinifimiz var 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 + '\'' +
                '}';
    }
}
Gələcəkdə bu sinfin obyektlərini seriallaşdırmaq istəyirik. UserObyekt və sətir götürən metodu path- baytları saxlayacağımız fayla gedən yolu yazaq :
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();
        }
    }
}
Seriyadan çıxarma metodunu da yazacağıq. Metod sətir götürür path(obyektin “yüklənəcəyi” fayla gedən yol) və tipli obyekti qaytarır 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();
        }
    }
}
Bütün alətlər istifadəyə hazırdır. Baytları atomlara bölmək vaxtıdır . mainSinif obyekti yaradaraq Useronu seriallaşdırdığımız metodu yazaq . Sonra onu yükləyəcəyik və ilkin ilə müqayisə edəcəyik:
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");
}
Əgər metodu işlədirsək, aşağıdakı çıxışı görəcəyik:
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'}
Çıxışdan göründüyü kimi, obyektlər eynidir. Amma bir kiçik amma var... Və məhz burada İspan utancının transient meydana çıxdığı yerdir .

Modifikator (nəhayət)transient

İstifadəçinin parolunu saxladığımız üçün kimsə çaşdı? Xüsusən də belə bir parol... Bəli, bəli, biz özümüz fikirləşmişik, amma yenə də... Bəzən elə vəziyyətlər olur ki, bəzi sahələri seriallaşdırmaq olmur, ya da bunu etməmək daha yaxşıdır. Yuxarıdakı nümunədə paroldan başqa bütün sahələri saxlamaq istərdim. Buna necə nail olmaq olar? Cavab: dəyişdiricidən istifadə edin transient. transientsinif sahəsindən əvvəl yerləşdirilən dəyişdiricidir (məsələn public, finalvə s. kimi digər dəyişdiricilərə bənzər) sahənin seriallaşdırılmaması lazım olduğunu göstərir. Açar sözlə işarələnmiş sahələr transientseriallaşdırılmır. İndi kiçik bir çaşqınlığı düzəltmək və istifadəçinin parolunu saxlamamaq üçün nümunəni istifadəçimizlə redaktə edək. Bunu etmək üçün sinifdəki müvafiq sahəni açar sözlə qeyd edin 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...
     */
}
Yuxarıdakı misaldakı metodu yenidən işə salsaq main, parolun saxlanmadığını görərik:
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'}
Əla, məqsədimizə nail olduq və məxfi məlumatları saxlamırıq. Xüsusən də bu cür məlumatlar... (bağışlayın)

Nə vaxt keçici istifadə edilməlidir?

Serializasiya kontekstinə daxil olmaq üçün istifadəçi ilə nümunə lazım idi. İndi dəyişdiricinin nə vaxt istifadə ediləcəyi barədə daha dəqiq danışaq transient.

  • Proqramlı olaraq hesablanan sahələr

Bəzi siniflərdə bəzən başqa sahələr və ya digər məlumatlar əsasında hesablanan sahələr olur. Onlar, belə demək mümkünsə, tez hesablanırlar. Belə bir sahəyə misal göstərmək üçün onlayn mağazada sifariş və ya bəzi qida çatdırılması xidmətini təsəvvür edək. Hər bir sifariş, digər məlumatlar arasında, malların siyahısından və ümumi xərcdən ibarətdir. O, öz növbəsində hər bir məhsulun ümumi dəyərindən ibarətdir. Belə çıxır ki, son xərc “əl ilə” təyin edilməməlidir: o, bütün malların maya dəyərini yekunlaşdıraraq proqramlı şəkildə hesablanmalıdır. Proqrama uyğun olaraq hesablanmalı olan bu kimi sahələrin seriallaşdırılmasına ehtiyac yoxdur. Buna görə də onları dəyişdirici ilə qeyd edirik transient.
class Order implements Serializable {

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

}

  • Şəxsi məlumatı olan sahələr

Şəxsi məlumatları saxlayan bəzi siniflər də var. Məqalənin əvvəlində belə bir sinif nümunəsinə baxdıq. Bu cür məlumatların JVM-dən kənara sızmasına icazə verməməlisiniz. transientBuna görə də, belə bir sinfi seriallaşdırmaq niyyətindəsinizsə, belə məlumatların olduğu sahələr dəyişdirici ilə qeyd edilməlidir .

  • İnterfeys həyata keçirməyən sahələrSerializable

Bəzən sinifdə interfeysi həyata keçirməyən digər siniflərin sahələri - obyektləri olur Serializable. Belə sahələrə misal olaraq loggerlər, giriş/çıxış axınları, verilənlər bazası əlaqələrini saxlayan obyektlər və digər kommunal sinifləri göstərmək olar. Seriallaşdırıla bilməyən sahələri ehtiva edən obyekti seriallaşdırmağa cəhd etsəniz, xəta alacaqsınız java.io.NotSerializableException. Bunun qarşısını almaq üçün interfeysi həyata keçirməyən bütün sahələr Serializabledəyişdirici ilə qeyd edilməlidir 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();
            }
        }
    }
}

  • Obyektin vəziyyəti haqqında məlumat olan sahələr

Yaxşı, son bir şey. Obyektin vəziyyət məlumatının bir hissəsi olmayan sahələri seriallaşdırmağa ehtiyac yoxdur. Yuxarıdakı nümunələr bu qaydaya aiddir. Lakin siz həmçinin sazlama və ya obyektin vəziyyəti haqqında məlumat daşımayan bir növ xidmət funksiyasını yerinə yetirmək üçün əlavə edilmiş bütün digər sahələri də buraya daxil edə bilərsiniz.

transientfinal

Nəticələr

Hamısı budur. Bu gün dəyişdirici haqqında danışdıq transient:
  1. Nəzəriyyə və praktikada seriallaşdırmanı xatırladıq.
  2. Biz başa düşdük ki, sinfin bəzi sahələrini seriallaşdırmamaq üçün onları dəyişdirici ilə qeyd etmək lazımdır transient.
  3. Bu dəyişdiricinin hansı hallarda istifadə edilməsini müzakirə etdik. Dörd belə vəziyyət var idi:
    1. proqramlaşdırılmış şəkildə hesablanan sahələr;
    2. məxfi məlumatları ehtiva edən sahələr;
    3. interfeysi həyata keçirməyən sahələr Serializable;
    4. obyektin vəziyyətinin bir hissəsi olmayan sahələr.
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION