ہیلو! آج کے مضمون میں، ہم جاوا میں عارضی ترمیم کار کو دیکھیں گے۔ آئیے اس بارے میں بات کرتے ہیں کہ اس ترمیم کنندہ کی ضرورت کیوں ہے اور اسے صحیح طریقے سے کیسے استعمال کیا جائے۔ جاؤ!
ایٹموں میں تقسیم کرنے کا وقت ہے ۔ آئیے ایک طریقہ لکھتے ہیں ہسپانوی شرم ترمیم کنندہ (آخر میں)
Никого не смутило, что мы пароль пользователя сохранor? Особенно такой пароль… Да-да, мы сами его придумали, но все же… Порой бывают ситуации, когда некоторые поля невозможно сериализовать, or лучше этого не делать. В примере выше хотелось бы сохранять все поля, за исключением пароля. Как это добиться? Ответ: использовать модификатор
В некоторых классах иногда бывают такие поля, которые вычисляются на основе других полей or же другой информации. Вычисляются, так сказать, на лету. Whatбы привести пример такого поля, представим себе заказ в интернет-магазине or же в Howом-нибудь сервисе доставки еды. Каждый заказ, помимо прочей информации, состоит из списка товаров и итоговой стоимости. Она, в свою очередь, складывается из суммарной стоимости каждого товара. Выходит, что итоговую стоимость не стоит задавать “руками”: ее нужно вычислять программно, суммируя стоимость всех товаров. Подобные поля, которые следует вычислять программно, не нужно сериализовывать. Поэтому помечаем их модификатором
Также бывают некоторые классы, которые хранят приватную информацию. Пример такого класса мы рассматривали в начале статьи. Не стоит допускать утечки такой информации за пределы JVM. Поэтому поля с подобными данными необходимо помечать модификатором
Иногда класс содержит поля — an objectы других классов, которые не реализуют интерфейс
Ну и последнее. Не нужно сериализовывать поля, которые не являются частью информации о состоянии an object. Примеры выше попадают под это правило. Но также сюда можно включить и все прочие поля, добавленные для дебага or для выполнения Howой то служебной функции, которые не несут информации о состоянии an object.
آئیے سیریلائزیشن کو یاد رکھیں
موڈیفائرtransient
اشیاء کو سیریلائز کرنے اور ڈی سیریلائز کرنے کے عمل میں استعمال ہوتا ہے۔ تو آئیے پہلے اس پر مختصر بات کرتے ہیں۔ فرض کریں کہ ہمارے پاس کوئی چیز ہے، اور اس میں فیلڈز ہیں، جن میں سے ہر ایک کی کچھ قدر ہے۔ یہ سب چیز کی حالت کہلاتی ہے۔ سیریلائزیشن کسی چیز کی حالت کو بائٹس کی ترتیب میں تبدیل کرنا ہے۔ یہ بائٹس عام طور پر کسی نہ کسی فائل میں محفوظ ہوتی ہیں۔ ڈی سیریلائزیشن ریورس عمل ہے۔ آئیے تصور کریں کہ ہم نے کسی چیز کو بائٹس میں سیریلائز کیا ہے اور بائٹس کے اس سیٹ کو کسی فائل میں محفوظ کیا ہے۔ ڈی سیریلائز کرتے وقت، پروگرام کی ضرورت ہوتی ہے:
- فائل سے بائٹس کا ایک سیٹ پڑھیں۔
- بائٹس کے اس سیٹ سے ایک ابتدائی آبجیکٹ بنائیں اور ہر فیلڈ کو اس قدر پر سیٹ کریں جو سیریلائزیشن کے وقت آبجیکٹ کے پاس تھی۔
آئیے عملی طور پر سیریلائزیشن کو یاد رکھیں
ٹھیک ہے، اب عملی طور پر سیریلائزیشن کو دیکھتے ہیں. اگر آپ موضوع کو بہتر طور پر سمجھنا چاہتے ہیں، تو ہم جاوا میں مواد سیریلائزیشن اور ڈی سیریلائزیشن کو پڑھنے کی تجویز کرتے ہیں ۔ ٹھیک ہے، اس مضمون میں ہم اوپر جائیں گے اور براہ راست مثالوں پر جائیں گے۔ ہم کہتے ہیں کہ ہمارے پاس ایک کلاس ہے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
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
:
- Вспомнor сериализацию в теории и на практике.
- Поняли, что для того, чтобы не сериализовать некоторые поля класса, их нужно помечать модификатором
transient
. - Обсудor, в Howих ситуациях следует использовать данный модификатор. Таких ситуаций оказалось четыре:
- поля, которые вычисляются программно;
- поля, которые содержат секретную информацию;
- поля, которые не реализуют интерфейс
Serializable
; - поля, которые не являются частью состояния an object.
GO TO FULL VERSION