JavaRush /Java блогы /Random-KK /Өтпелі модификатор Java тілінде нені жасырады?
Анзор Кармов
Деңгей
Санкт-Петербург

Өтпелі модификатор Java тілінде нені жасырады?

Топта жарияланған
Сәлеметсіз бе! Бүгінгі мақалада біз Java тіліндегі өтпелі модификаторды қарастырамыз. Бұл модификатор не үшін қажет және оны қалай дұрыс пайдалану керектігі туралы сөйлесейік. Бар! Java-да өтпелі модификатор нені жасырады - 1

Сериализацияны еске түсірейік

Модификатор transientan objectілерді сериялау және сериядан шығару процесінде қолданылады. Ендеше алдымен осы туралы қысқаша айтып өтейік. Java-да өтпелі модификатор нені жасырады - 2Бізде қандай да бір нысан бар делік және оның әрқайсысы белгілі бір мәнге ие өрістер бар делік. Осының барлығы an objectінің күйі деп аталады. Серияландыру - an object күйін byteтар тізбегіне түрлендіру. Бұл byteтар әдетте кейбір файлда сақталады. Сериядан шығару кері процесс. Біз an objectіні byteтарға сериялап, осы byteтар жинағын қандай да бір файлда сақтадық деп елестетіп көрейік. Сериядан шығару кезінде бағдарламаға қажет:
  1. Файлдан byte жиынын оқыңыз.
  2. Осы byte жиынынан бастапқы нысанды құрастырыңыз және әрбір өрісті сериялау кезінде нысанда болған мәнге орнатыңыз.
Бұл қашан пайдалы болуы мүмкін? Мысалы, біз бағдарламаны өшіру кезінде оның күйін сақтауды және келесі рет қосылғанда оны қалпына келтіруді қалаймыз. 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 + '\'' +
                '}';
    }
}
Біз болашақта осы сыныптың нысандарын сериялауды қалаймыз. 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(нысан «жүктелетін» файлға жол) және түрдегі нысанды қайтарады 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'}
Шығарудан көріп отырғаныңыздай, нысандар бірдей. Бірақ кішкентай, бірақ... Міне, дәл осы жерде испандық ұят 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та кластары болып табылады. Серияланbyteын өрістерді қамтитын нысанды сериялауға әрекеттенсеңіз, сіз қатені аласыз 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();
            }
        }
    }
}

  • Объектінің күйі туралы ақпараты бар өрістер

Ал, соңғы бір нәрсе. Нысанның күй ақпаратының бөлігі болып табылмайтын өрістерді сериялаудың қажеті жоқ. Жоғарыдағы мысалдар осы ережеге жатады. Бірақ сіз мұнда күйін түзету немесе нысанның күйі туралы ақпаратты жеткізбейтін қандай да бір қызмет функциясын орындау үшін қосылған барлық басқа өрістерді қоса аласыз.

transientЖәнеfinal

Нәтижелер

Бар болғаны. Бүгін біз модификатор туралы сөйлестік transient:
  1. Теорияда және практикада сериализация есте қалды.
  2. Біз сыныптың кейбір өрістерін серияламау үшін оларды модификатормен белгілеу керек екенін түсіндік transient.
  3. Біз бұл модификаторды қандай жағдайларда қолдану керектігін талқыладық. Мұндай төрт жағдай болды:
    1. бағдарламалық түрде есептелетін өрістер;
    2. құпия ақпаратты қамтитын өрістер;
    3. интерфейсті жүзеге асырмайтын өрістер Serializable;
    4. нысан күйінің бөлігі болып табылмайтын өрістер.
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION