hello! Dalam artikel hari ini, kita akan melihat pengubah sementara di Java. Mari kita bincangkan mengapa pengubah suai ini diperlukan dan cara menggunakannya dengan betul. Pergi!
atom . Mari kita tulis kaedah rasa malu Sepanyol Pengubah suai (akhirnya)
Adakah sesiapa yang keliru bahawa kami menyimpan kata laluan pengguna? Terutama kata laluan sedemikian... Ya, ya, kami sendiri yang menciptanya, tetapi masih... Kadang-kadang terdapat situasi apabila sesetengah medan tidak boleh disiri, atau lebih baik tidak melakukan ini. Dalam contoh di atas, saya ingin menyimpan semua medan kecuali kata laluan. Bagaimana untuk mencapai ini? Jawapan: gunakan pengubah suai
Sesetengah kelas kadangkala mempunyai medan yang dikira berdasarkan medan lain atau maklumat lain. Mereka dikira, boleh dikatakan, dengan cepat. Untuk memberikan contoh bidang sedemikian, mari bayangkan pesanan di kedai dalam talian atau beberapa perkhidmatan penghantaran makanan. Setiap pesanan, antara maklumat lain, terdiri daripada senarai barang dan jumlah kos. Ia pula terdiri daripada jumlah kos setiap produk. Ternyata kos akhir tidak boleh ditetapkan "dengan tangan": ia mesti dikira secara pemrograman, menjumlahkan kos semua barang. Medan seperti ini yang harus dikira secara pemrograman tidak perlu bersiri. Oleh itu, kami menandakannya dengan pengubah suai
Terdapat juga beberapa kelas yang menyimpan maklumat peribadi. Kami melihat contoh kelas sedemikian pada permulaan artikel. Anda tidak seharusnya membenarkan maklumat sedemikian bocor di luar JVM. Oleh itu, medan dengan data sedemikian mesti ditandakan dengan pengubah suai
Kadangkala kelas mengandungi medan - objek kelas lain yang tidak melaksanakan antara muka
Nah, satu perkara terakhir. Tidak perlu menyiri medan yang bukan sebahagian daripada maklumat keadaan objek. Contoh di atas terletak di bawah peraturan ini. Tetapi anda juga boleh memasukkan di sini semua medan lain yang ditambahkan untuk penyahpepijatan atau untuk melaksanakan beberapa jenis fungsi perkhidmatan yang tidak membawa maklumat tentang keadaan objek.
Mari kita ingat bersiri
Pengubah suaitransient
digunakan dalam proses mensiri dan menyahsiri objek. Jadi mari kita bercakap secara ringkas tentang perkara ini terlebih dahulu. Katakan kita mempunyai beberapa objek, dan ia mempunyai medan, setiap satunya mempunyai beberapa nilai. Semua ini dipanggil keadaan objek. Serialisasi ialah penukaran keadaan objek kepada urutan bait. Bait ini biasanya disimpan dalam beberapa fail. Deserialisasi adalah proses sebaliknya. Mari kita bayangkan bahawa kita menyusun objek menjadi bait dan menyimpan set bait ini dalam beberapa fail. Apabila desirialisasi, program memerlukan:
- Baca satu set bait daripada fail.
- Bina objek awal daripada set bait ini dan tetapkan setiap medan kepada nilai yang dimiliki objek pada masa penyirian.
Mari kita ingat bersiri dalam amalan
Nah, sekarang mari kita lihat siri dalam amalan. Jika anda ingin memahami topik ini dengan lebih baik, kami mengesyorkan membaca bahan Pensirian dan penyahserikatan dalam Java . Nah, dalam artikel ini kita akan pergi ke atas dan terus ke contoh. Katakan kita mempunyai kelasUser
dengan set beberapa medan, getter dan setter, dan kaedah 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 + '\'' +
'}';
}
}
Kami mahu mensirikan objek kelas ini pada masa hadapan. Mari tulis kaedah yang mengambil objek User
dan rentetan path
- laluan ke fail di mana kita akan menyimpan bait:
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();
}
}
}
Kami juga akan menulis kaedah untuk penyahserialisasian. Kaedah mengambil rentetan path
(laluan ke fail dari mana objek akan "dimuatkan") dan mengembalikan objek jenis 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();
}
}
}
Semua alatan sedia untuk digunakan. Sudah tiba masanya untuk membahagikan bait kepada main
di mana kita mencipta objek kelas User
dan mensirikannya. Kemudian kami akan memuatkannya dan membandingkannya dengan yang asalnya:
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");
}
Jika kita menjalankan kaedah, kita akan melihat output berikut:
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'}
Seperti yang anda lihat dari output, objek adalah sama. Tetapi ada yang kecil tetapi... Dan di sinilah transient
mula bermain .
Pengubah suai (akhirnya)transient
Adakah sesiapa yang keliru bahawa kami menyimpan kata laluan pengguna? Terutama kata laluan sedemikian... Ya, ya, kami sendiri yang menciptanya, tetapi masih... Kadang-kadang terdapat situasi apabila sesetengah medan tidak boleh disiri, atau lebih baik tidak melakukan ini. Dalam contoh di atas, saya ingin menyimpan semua medan kecuali kata laluan. Bagaimana untuk mencapai ini? Jawapan: gunakan pengubah suai transient
. transient
ialah pengubah suai yang ditentukan sebelum medan kelas (serupa dengan pengubah suai lain seperti public
, final
dsb.) untuk menunjukkan bahawa medan itu tidak perlu bersiri. Medan yang ditanda dengan kata kunci transient
tidak bersiri. Sekarang mari edit contoh dengan pengguna kami untuk membetulkan kekeliruan kecil dan tidak menyimpan kata laluan pengguna. Untuk melakukan ini, tandakan medan yang sepadan dalam kelas dengan kata kunci 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...
*/
}
Jika kami menjalankan kaedah daripada contoh di atas sekali lagi main
, kami akan melihat bahawa kata laluan tidak disimpan:
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'}
Hebat, kami mencapai matlamat kami dan tidak menyimpan maklumat sulit. Terutamanya maklumat sebegini... (maaf)
Bila hendak menggunakan sementara?
Contoh dengan pengguna diperlukan untuk menyelami konteks penyirian. Sekarang mari kita bincangkan dengan lebih khusus tentang masa untuk menggunakan pengubah suaitransient
.
- Medan yang dikira secara pemrograman
Sesetengah kelas kadangkala mempunyai medan yang dikira berdasarkan medan lain atau maklumat lain. Mereka dikira, boleh dikatakan, dengan cepat. Untuk memberikan contoh bidang sedemikian, mari bayangkan pesanan di kedai dalam talian atau beberapa perkhidmatan penghantaran makanan. Setiap pesanan, antara maklumat lain, terdiri daripada senarai barang dan jumlah kos. Ia pula terdiri daripada jumlah kos setiap produk. Ternyata kos akhir tidak boleh ditetapkan "dengan tangan": ia mesti dikira secara pemrograman, menjumlahkan kos semua barang. Medan seperti ini yang harus dikira secara pemrograman tidak perlu bersiri. Oleh itu, kami menandakannya dengan pengubah suai transient
.
class Order implements Serializable {
private List- items;
private transient BigDecimal totalAmount; //вычисляется на ходу
}
- Medan dengan maklumat peribadi
Terdapat juga beberapa kelas yang menyimpan maklumat peribadi. Kami melihat contoh kelas sedemikian pada permulaan artikel. Anda tidak seharusnya membenarkan maklumat sedemikian bocor di luar JVM. Oleh itu, medan dengan data sedemikian mesti ditandakan dengan pengubah suai transient
jika anda akan membuat siri kelas sedemikian.
- Medan yang tidak melaksanakan antara muka
Serializable
Kadangkala kelas mengandungi medan - objek kelas lain yang tidak melaksanakan antara muka Serializable
Serializable
. Contoh medan tersebut ialah pembalak, aliran I/O, objek yang menyimpan sambungan pangkalan data dan kelas utiliti lain. Jika anda cuba mensirikan objek yang mengandungi medan tidak boleh disiri, anda akan menerima ralat java.io.NotSerializableException
. Untuk mengelakkan ini, semua medan yang tidak melaksanakan antara muka Serializable
mesti ditandakan dengan pengubah suai 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();
}
}
}
}
- Medan dengan maklumat tentang keadaan objek
Nah, satu perkara terakhir. Tidak perlu menyiri medan yang bukan sebahagian daripada maklumat keadaan objek. Contoh di atas terletak di bawah peraturan ini. Tetapi anda juga boleh memasukkan di sini semua medan lain yang ditambahkan untuk penyahpepijatan atau untuk melaksanakan beberapa jenis fungsi perkhidmatan yang tidak membawa maklumat tentang keadaan objek.
transient
Danfinal
Keputusan
Itu sahaja. Hari ini kita bercakap tentang pengubah suaitransient
:
- Kami ingat bersiri dalam teori dan amalan.
- Kami menyedari bahawa untuk tidak menyerikan beberapa medan kelas, mereka perlu ditandakan dengan pengubah suai
transient
. - Kami membincangkan dalam situasi apa pengubah suai ini harus digunakan. Terdapat empat situasi sedemikian:
- medan yang dikira secara pemrograman;
- medan yang mengandungi maklumat rahsia;
- medan yang tidak melaksanakan antara muka
Serializable
; - medan yang bukan sebahagian daripada keadaan objek.
GO TO FULL VERSION