JavaRush /Java блогу /Random-KY /Убактылуу модификатор Javaда эмнени жашырат?
Анзор Кармов
Деңгээл
Санкт-Петербург

Убактылуу модификатор Javaда эмнени жашырат?

Группада жарыяланган
Салам! Бүгүнкү макалада биз Javaдагы убактылуу модификаторду карайбыз. Келгиле, бул модификатор эмне үчүн керек жана аны кантип туура колдонуу керектиги жөнүндө сүйлөшөлү. Go! Убактылуу модификатор Javaда эмнени жашырат - 1

Сериализацияны эстейли

Модификатор transientan 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'да Сериялаштыруу жана Сериялаштыруу . Ооба, бул макалада биз жогору жагына өтүп, түздөн-түз мисалдарга барабыз. Келгиле, бизде 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терин сериялаштырууну каалайбыз. 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();
        }
    }
}
Бардык куралдар колдонууга даяр. Байттарды атомдорго бөлүүгө убакыт келди . Келгиле, 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серияланbyte. Эми кичинекей башаламандыкты оңдоо жана колдонуучунун сырсөзүн сактабоо үчүн колдонуучубуз менен мисалды түзөтөлү. Бул үчүн, класстагы тиешелүү талааны ачкыч сөз менен белгилеңиз 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тер жана башка пайдалуу класстар. Сериялаштырылбаган талааларды камтыган 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тин абалы жөнүндө маалымат бербеген кандайдыр бир тейлөө функциясын аткаруу үчүн кошулган бардык башка талааларды кошо аласыз.

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