JavaRush /Блоги Java /Random-TG /Тағирдиҳандаи муваққатӣ дар Java чиро пинҳон мекунад?
Анзор Кармов
Сатҳи
Санкт-Петербург

Тағирдиҳандаи муваққатӣ дар Java чиро пинҳон мекунад?

Дар гурӯҳ нашр шудааст
Салом! Дар мақолаи имрӯза мо тағирдиҳандаи муваққатиро дар Java дида мебароем. Биёед дар бораи он ки чаро ин тағирдиҳанда лозим аст ва чӣ гуна онро дуруст истифода бурдан мумкин аст. Бирав! Тағирдиҳандаи муваққатӣ дар Java чиро пинҳон мекунад - 1

Биёед сериализатсияро ба ёд орем

Тағйирдиҳанда transientдар раванди силсиласозӣ ва ғайрисериализатсияи an objectҳо истифода мешавад. Пас биёед аввал дар ин бора мухтасар сухан ронем. Тағирдиҳандаи муваққатӣ дар Java чиро пинҳон мекунад - 2Фарз мекунем, ки мо ягон an object дорем ва он дорои майдонҳое мебошад, ки ҳар кадоми онҳо арзиш доранд. Хамаи ин холати an object номида мешавад. Сериализатсия табдил додани ҳолати an object ба пайдарпайии byteҳо мебошад. Ин byteҳо одатан дар ягон файл нигоҳ дошта мешаванд. Десериализатсия раванди баръакс аст. Биёед тасаввур кунем, ки мо an objectро ба byteҳо силсилавӣ кардем ва ин маҷмӯи byteҳоро дар ягон файл нигоҳ доштем. Ҳангоми бекор кардани серия, барнома ба инҳо ниёз дорад:
  1. Маҷмӯи byteҳоро аз файл хонед.
  2. Аз ин маҷмӯи byteҳо an objectи ибтидоӣ созед ва ҳар як майдонро ба арзише, ки an object дар вақти сериализатсия дошт, таъин кунед.
Кай ин метавонад муфид бошад? Масалан, вақте ки мо мехоҳем, ки барнома ҳангоми хомӯш шудан ҳолати худро нигоҳ дорад ва дафъаи оянда онро барқарор кунад. Вақте ки шумо IntelliJ IDEA-ро хомӯш мекунед, эҳтимолан дафъаи оянда шумо онро фаъол созед, ҳамон ҷадвалҳо ва синфҳо кушода мешаванд.

Биёед дар амал сериализатсияро ба ёд орем

Хуб, ҳоло биёед ба сериализатсия дар амал назар кунем. Агар шумо хоҳед, ки мавзӯъро хубтар дарк кунед, мо тавсия медиҳем, ки маводро дар Java хонед Serialization ва deserialization . Хуб, дар ин мақола мо аз боло рафта, рост ба мисолҳо меравем. Фарз мекунем, ки мо синфе дорем User, ки дорои як қатор майдонҳо, қабулкунандаҳо ва танзимкунандагон ва як метод аст 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 + '\'' +
                '}';
    }
}
Мо мехоҳем дар оянда an objectҳои ин синфро силсилавӣ кунем. Биёед усулеро нависем, ки an object Userва сатрро мегирад path- роҳ ба файле, ки дар он 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();
        }
    }
}
Мо инчунин усули бесериализатсияро менависем. Усул сатрро мегирад path(роҳ ба файле, ки аз он an object "бор карда мешавад") ва an objectи навъи : -ро бармегардонад 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();
        }
    }
}
Ҳама асбобҳо барои истифода омодаанд. Вақти он расидааст, ки byteҳоро ба атомҳо тақсим кунед . Биёед усулеро нависем main, ки дар он мо an objectи синфро эҷод мекунем Userва онро силсилавӣ мекунем. Пас мо онро бор мекунем ва бо он чизе, ки дар аввал буд, муқоиса мекунем:
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");
}
Агар мо усулро иҷро кунем, мо натиҷаи зеринро мебинем:
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'}
Тавре ки шумо аз баромад мебинед, an objectҳо якхелаанд. Аммо як чизи хурд вуҷуд дорад, аммо ... Ва маҳз дар ин ҷо шармандагии испанӣ transient ба бозӣ меояд .

Тағйирдиҳанда (ниҳоят)transient

Оё касе ошуфтааст, ки мо пароли корбарро захира кардем? Махсусан, чунин парол... Бале, бале, мо худамон офаридем, вале ба ҳар ҳол... Баъзан ҳолатҳое мешаванд, ки баъзе майдонҳоро сериализатсия кардан мумкин нест, ё беҳтараш ин корро накунед. Дар мисоли дар боло овардашуда, ман мехоҳам ҳамаи майдонҳоро ҷуз парол захира кунам. Чӣ тавр ба ин ноил шудан мумкин аст? Ҷавоб: тағирдиҳандаро истифода баред transient. transientтағирдиҳандаест, ки дар назди майдони синф ҷойгир карда шудааст (монанди дигар тағирдиҳандаҳо ба монанди public, finalва ғ.) барои нишон додани он, ки майдон набояд силсилаи карда шавад. Майдонҳое, ки бо калимаи калидӣ қайд карда шудаанд, transientсерия карда намешаванд. Акнун биёед мисолро бо корбари худ таҳрир кунем, то нофаҳмиҳои хурдро ислоҳ кунем ва пароли корбарро захира накунем. Барои ин, майдони мувофиқро дар синф бо калимаи калидӣ қайд кунед 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...
     */
}
Агар мо усулро аз мисоли боло бори дигар иҷро кунем main, мо мебинем, ки парол захира нашудааст:
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'}
Аҷоиб, мо ба ҳадафи худ расидем ва маълумоти махфиро нигоҳ намедорем. Махсусан ин гуна маълумот... (бахшед)

Кай барои истифодаи муваққатӣ?

Барои ворид шудан ба контексти сериализатсия намуна бо корбар лозим буд. Акнун биёед муфассалтар дар бораи кай истифода бурдани тағирдиҳанда сӯҳбат кунем transient.

  • Майдонҳое, ки ба таври барномавӣ ҳисоб карда мешаванд

Баъзе синфҳо баъзан майдонҳое доранд, ки дар асоси дигар соҳаҳо ё маълумоти дигар ҳисоб карда мешаванд. Онхо, гуем, дар парвоз хисоб карда мешаванд. Барои мисол овардани чунин соҳа, биёед фармоишро дар мағозаи онлайн ё ягон хидмати интиқоли ғизо тасаввур кунем. Ҳар як фармоиш, дар байни дигар маълумот, аз рӯйхати молҳо ва арзиши умумӣ иборат аст. Вай дар навбати худ аз арзиши умумии хар як махсулот иборат аст. Маълум мешавад, ки арзиши нихоиро «дастй» мукаррар кардан мумкин нест: он бояд ба таври программавй хисоб карда, арзиши хамаи молхоро чамъбаст кард. Майдонҳои ба ин монанд, ки бояд ба таври барномавӣ ҳисоб карда шаванд, ба силсиласозӣ ниёз надоранд. Аз ин рӯ, мо онҳоро бо тағирдиҳанда қайд мекунем transient.
class Order implements Serializable {

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

}

  • Майдонҳо бо маълумоти хусусӣ

Инчунин баъзе синфҳо мавҷуданд, ки маълумоти шахсиро нигоҳ медоранд. Мо дар аввали мақола як мисоли чунин синфро дида баромадем. Шумо набояд иҷозат надиҳед, ки чунин маълумот берун аз JVM паҳн шавад. Аз ин рӯ, майдонҳое, ки чунин маълумот доранд, бояд бо тағирдиҳанда қайд карда шаванд, transientагар шумо чунин синфро сериализатсия кунед.

  • Майдонҳое, ки интерфейсро амалӣ намекунандSerializable

Баъзан синф дорои майдонҳо - an objectҳои синфҳои дигар аст, ки интерфейсро амалӣ намекунанд Serializable. Намунаҳои чунин майдонҳо логгерҳо, ҷараёнҳои воридот/х, an objectҳое мебошанд, ки пайвастҳои пойгоҳи додаҳо ва дигар синфҳои утorтаҳоро нигоҳ медоранд. Агар шумо кӯшиш кунед, ки an objectеро, ки дорои майдонҳои сериализатсиянашаванда аст, сериализатсия кунед, шумо хатогӣ мегиред java.io.NotSerializableException. Барои пешгирӣ кардани ин, ҳама майдонҳое, ки интерфейсро иҷро намекунанд, Serializableбояд бо тағирдиҳанда қайд карда шаванд 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();
            }
        }
    }
}

  • Майдонҳо бо маълумот дар бораи ҳолати an object

Хуб, як чизи охирин. Барои силсила кардани майдонҳое, ки ҷузъи иттилооти ҳолати an object нестанд, лозим нест. Намунаҳои дар боло овардашуда ба ин қоида дохил мешаванд. Аммо шумо инчунин метавонед дар ин ҷо ҳамаи майдонҳои дигареро, ки барои ислоҳ кардан ё иҷрои ягон вазифаи хидматӣ илова карда шудаанд, дохил кунед, ки дар бораи ҳолати an object маълумот надоранд.

transientВаfinal

Натиҷаҳо

Ҳамааш ҳамин. Имрӯз мо дар бораи тағирдиҳанда сӯҳбат кардем transient:
  1. Мо сериализатсияро дар назария ва амалия ба хотир овардем.
  2. Мо фаҳмидем, ки барои сериализатсия накардани баъзе майдонҳои синф, онҳо бояд бо тағирдиҳанда қайд карда шаванд transient.
  3. Мо муҳокима кардем, ки дар кадом ҳолатҳо ин тағирдиҳанда бояд истифода шавад. Чор чунин ҳолат вуҷуд дошт:
    1. майдонҳое, ки ба таври барномавӣ ҳисоб карда мешаванд;
    2. майдонҳое, ки маълумоти махфӣ доранд;
    3. майдонҳое, ки интерфейсро татбиқ намекунанд Serializable;
    4. майдонҳое, ки қисми ҳолати an object нестанд.
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION