JavaRush /جاوا بلاگ /Random-UR /جاوا میں عارضی ترمیم کنندہ کیا چھپاتا ہے؟
Анзор Кармов
سطح
Санкт-Петербург

جاوا میں عارضی ترمیم کنندہ کیا چھپاتا ہے؟

گروپ میں شائع ہوا۔
ہیلو! آج کے مضمون میں، ہم جاوا میں عارضی ترمیم کار کو دیکھیں گے۔ آئیے اس بارے میں بات کرتے ہیں کہ اس ترمیم کنندہ کی ضرورت کیوں ہے اور اسے صحیح طریقے سے کیسے استعمال کیا جائے۔ جاؤ! What скрывает модификатор transient в Java - 1

آئیے سیریلائزیشن کو یاد رکھیں

موڈیفائر transientاشیاء کو سیریلائز کرنے اور ڈی سیریلائز کرنے کے عمل میں استعمال ہوتا ہے۔ تو آئیے پہلے اس پر مختصر بات کرتے ہیں۔ What скрывает модификатор transient в Java - 2فرض کریں کہ ہمارے پاس کوئی چیز ہے، اور اس میں فیلڈز ہیں، جن میں سے ہر ایک کی کچھ قدر ہے۔ یہ سب چیز کی حالت کہلاتی ہے۔ سیریلائزیشن کسی چیز کی حالت کو بائٹس کی ترتیب میں تبدیل کرنا ہے۔ یہ بائٹس عام طور پر کسی نہ کسی فائل میں محفوظ ہوتی ہیں۔ ڈی سیریلائزیشن ریورس عمل ہے۔ آئیے تصور کریں کہ ہم نے کسی چیز کو بائٹس میں سیریلائز کیا ہے اور بائٹس کے اس سیٹ کو کسی فائل میں محفوظ کیا ہے۔ ڈی سیریلائز کرتے وقت، پروگرام کی ضرورت ہوتی ہے:
  1. فائل سے بائٹس کا ایک سیٹ پڑھیں۔
  2. بائٹس کے اس سیٹ سے ایک ابتدائی آبجیکٹ بنائیں اور ہر فیلڈ کو اس قدر پر سیٹ کریں جو سیریلائزیشن کے وقت آبجیکٹ کے پاس تھی۔
یہ کب مفید ہو سکتا ہے؟ مثال کے طور پر، جب ہم چاہتے ہیں کہ پروگرام بند ہونے پر اپنی حالت کو بچا لے اور اگلی بار آن ہونے پر اسے بحال کرے۔ جب آپ IntelliJ IDEA کو بند کرتے ہیں، تو امکان ہے کہ اگلی بار جب آپ اسے آن کریں گے تو آپ کے پاس وہی ٹیبز اور کلاسیں کھلیں گی۔

آئیے عملی طور پر سیریلائزیشن کو یاد رکھیں

ٹھیک ہے، اب عملی طور پر سیریلائزیشن کو دیکھتے ہیں. اگر آپ موضوع کو بہتر طور پر سمجھنا چاہتے ہیں، تو ہم جاوا میں مواد سیریلائزیشن اور ڈی سیریلائزیشن کو پڑھنے کی تجویز کرتے ہیں ۔ ٹھیک ہے، اس مضمون میں ہم اوپر جائیں گے اور براہ راست مثالوں پر جائیں گے۔ ہم کہتے ہیں کہ ہمارے پاس ایک کلاس ہے 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- فائل کا راستہ جس میں ہم بائٹس کو محفوظ کریں گے:
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جس میں ہم ایک کلاس آبجیکٹ بناتے ہیں 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

Никого не смутило, что мы пароль пользователя сохранor? Особенно такой пароль… Да-да, мы сами его придумали, но все же… Порой бывают ситуации, когда некоторые поля невозможно сериализовать, or лучше этого не делать. В примере выше хотелось бы сохранять все поля, за исключением пароля. Как это добиться? Ответ: использовать модификатор transient. transient — это модификатор, указываемый перед полем класса (подобно другим модификаторам, таким How 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'}
Отлично, мы добorсь поставленной цели и не сохраняем конфиденциальную информацию. Особенно такую информацию… (простите)

Когда использовать transient?

Пример с пользователем был нужен для того, чтобы погрузиться в контекст сериализации. Теперь поговорим предметнее о том, когда следует использовать модификатор transient.

  • Поля, которые вычисляются программно

В некоторых классах иногда бывают такие поля, которые вычисляются на основе других полей or же другой информации. Вычисляются, так сказать, на лету. Whatбы привести пример такого поля, представим себе заказ в интернет-магазине or же в Howом-нибудь сервисе доставки еды. Каждый заказ, помимо прочей информации, состоит из списка товаров и итоговой стоимости. Она, в свою очередь, складывается из суммарной стоимости каждого товара. Выходит, что итоговую стоимость не стоит задавать “руками”: ее нужно вычислять программно, суммируя стоимость всех товаров. Подобные поля, которые следует вычислять программно, не нужно сериализовывать. Поэтому помечаем их модификатором 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. Whatбы избежать этого, все поля, которые не реализуют интерфейс 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. Примеры выше попадают под это правило. Но также сюда можно включить и все прочие поля, добавленные для дебага or для выполнения Howой то служебной функции, которые не несут информации о состоянии an object.

transient и final

Итоги

На этом все. Сегодня мы говорor о модификаторе transient:
  1. Вспомнor сериализацию в теории и на практике.
  2. Поняли, что для того, чтобы не сериализовать некоторые поля класса, их нужно помечать модификатором transient.
  3. Обсудor, в Howих ситуациях следует использовать данный модификатор. Таких ситуаций оказалось четыре:
    1. поля, которые вычисляются программно;
    2. поля, которые содержат секретную информацию;
    3. поля, которые не реализуют интерфейс Serializable;
    4. поля, которые не являются частью состояния an object.
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION