CodeGym /Java Blogu /Rastgele /Java'da haricileştirilebilir arayüz
John Squirrels
Seviye
San Francisco

Java'da haricileştirilebilir arayüz

grupta yayınlandı
MERHABA! Bugün Java nesnelerinin serileştirilmesini ve seriden çıkarılmasını öğrenmeye devam edeceğiz . Son derste, Seri hale getirilebilir işaretleyici arayüzünü tanıdık , kullanım örneklerini inceledik ve ayrıca serileştirme sürecini kontrol etmek için geçici anahtar kelimeyi nasıl kullanabileceğinizi öğrendik . Pekala, 'süreci kontrol ediyoruz' demek onu abartıyor olabilir. Bir anahtar kelimemiz, bir sürüm tanımlayıcımız var ve hepsi bu. Sürecin geri kalanı Java'nın içinde gizli ve ona erişemiyoruz. Elbette kolaylık açısından bu iyi. Ancak bir programcıya yalnızca kendi rahatlığı rehberlik etmemelidir, değil mi? :) Göz önünde bulundurmanız gereken başka faktörler de var. Bu yüzden SerileştirilebilirJava'da seri hale getirme-seriyi kaldırma için tek mekanizma değildir. Bugün, Externalizable arayüzü ile tanışacağız . Ancak onu incelemeye başlamadan önce makul bir sorunuz olabilir: neden başka bir mekanizmaya ihtiyacımız var? Serializableişini yaptı ve tüm sürecin otomatik olarak uygulanmasında sevilmeyecek ne var? Ve baktığımız örnekler de karmaşık değildi. Öyleyse sorun nedir? Temelde aynı görevler için neden başka bir arayüze ihtiyacımız var? Gerçek şu ki, Serializablebirkaç eksikliği var. Bazılarını listeliyoruz:
  1. Verim. Arayüzün Serializablebirçok avantajı vardır, ancak yüksek performans açıkça bunlardan biri değildir.

    Dışsallaştırılabilir arayüzün tanıtımı - 2

    İlk olarak, Serializable 'ın dahili uygulaması büyük miktarda hizmet bilgisi ve her türden geçici veri üretir.

    İkincisi, Serializable Reflection API'ye dayanır (şu anda bu konuya derinlemesine dalmak zorunda değilsiniz; ilgileniyorsanız, boş zamanlarınızda daha fazlasını okuyabilirsiniz). Bu şey, Java'da imkansız gibi görünen şeyleri yapmanızı sağlar: örneğin, özel alanların değerlerini değiştirmek. CodeGym'de Reflection API hakkında mükemmel bir makale var . Orada okuyabilirsiniz.

  2. Esneklik. Arayüzü kullandığımızda seri hale getirme-seri hale getirme sürecini kontrol etmiyoruz Serializable.

    Bir yandan, çok uygun, çünkü özellikle performansla ilgilenmiyorsak, o zaman kod yazmak zorunda kalmamak güzel görünüyor. Peki ya serileştirme mantığına gerçekten kendi bazı özelliklerimizi (aşağıda bir örnek vereceğiz) eklememiz gerekirse?

    Temel olarak, süreci kontrol etmemiz gereken tek şey, transientbazı verileri hariç tutmak için anahtar kelimedir. Bu kadar. Tüm araç kutumuz bu :/

  3. Güvenlik. Bu öğe kısmen önceki öğeden türemiştir.

    Bunu daha önce düşünmek için fazla zaman harcamadık, ama ya sınıfınızdaki bazı bilgiler başkalarının meraklı gözlerine ve kulaklarına yönelik değilse? Basit bir örnek, günümüz dünyasında bir dizi yasa tarafından yönetilen bir şifre veya diğer kişisel kullanıcı verileridir.

    Eğer kullanırsak Serializable, bu konuda gerçekten hiçbir şey yapamayız. Her şeyi olduğu gibi seri hale getiriyoruz.

    Ancak doğru şekilde yaparsak, bu tür verileri bir dosyaya yazmadan veya bir ağ üzerinden göndermeden önce şifrelememiz gerekir. Ama Serializablebunu mümkün kılmaz.

Dışsallaştırılabilir arayüzün tanıtımı - 3Sonunda, arayüzü kullanırsak sınıfın nasıl görüneceğine bir bakalım Externalizable.

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

public class UserInfo implements Externalizable {

   private String firstName;
   private String lastName;
   private String superSecretInformation;

private static final long SERIAL_VERSION_UID = 1L;

   // ...constructor, getters, setters, toString()...

   @Override
   public void writeExternal(ObjectOutput out) throws IOException {

   }

   @Override
   public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {

   }
}
Gördüğünüz gibi, önemli değişikliklerimiz var! Ana olan açıktır: Externalizablearayüzü uygularken, gerekli iki yöntemi uygulamanız gerekir: writeExternal()vereadExternal(). Daha önce de söylediğimiz gibi, seri hale getirme ve seriden kaldırma sorumluluğu programcıya aittir. Ancak artık süreç üzerinde kontrol olmaması sorununu çözebilirsiniz! Tüm süreç doğrudan sizin tarafınızdan programlanır. Doğal olarak, bu çok daha esnek bir mekanizmaya izin verir. Ek olarak, güvenlik sorunu çözüldü. Görüldüğü üzere sınıfımızda şifresiz saklanamayan bir kişisel veri alanı bulunmaktadır. Artık bu kısıtlamayı karşılayan kodu kolayca yazabiliriz. Örneğin, hassas verileri şifrelemek ve şifresini çözmek için sınıfımıza iki basit özel yöntem ekleyebiliriz. Verileri dosyaya yazacağız ve dosyadan şifreli biçimde okuyacağız. Geri kalan veriler olduğu gibi yazılacak ve okunacaktır :) Sonuç olarak sınıfımız şöyle bir şeye benziyor:

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Base64;

public class UserInfo implements Externalizable {

   private String firstName;
   private String lastName;
   private String superSecretInformation;

   private static final long serialVersionUID = 1L;

   public UserInfo() {
   }

   public UserInfo(String firstName, String lastName, String superSecretInformation) {
       this.firstName = firstName;
       this.lastName = lastName;
       this.superSecretInformation = superSecretInformation;
   }

   @Override
   public void writeExternal(ObjectOutput out) throws IOException {
       out.writeObject(this.getFirstName());
       out.writeObject(this.getLastName());
       out.writeObject(this.encryptString(this.getSuperSecretInformation()));
   }

   @Override
   public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
       firstName = (String) in.readObject();
       lastName = (String) in.readObject();
       superSecretInformation = this.decryptString((String) in.readObject());
   }

   private String encryptString(String data) {
       String encryptedData = Base64.getEncoder().encodeToString(data.getBytes());
       System.out.println(encryptedData);
       return encryptedData;
   }

   private String decryptString(String data) {
       String decrypted = new String(Base64.getDecoder().decode(data));
       System.out.println(decrypted);
       return decrypted;
   }

   public String getFirstName() {
       return firstName;
   }

   public String getLastName() {
       return lastName;
   }

   public String getSuperSecretInformation() {
       return superSecretInformation;
   }
}
Hakkında derste zaten tanıştığımız aynı parametreleri ObjectOutputve parametreleri kullanan iki yöntem uyguladık . Doğru anda, gerekli verileri şifreler veya şifresini çözeriz ve şifrelenmiş verileri nesnemizi seri hale getirmek için kullanırız. Bunun pratikte nasıl göründüğüne bakalım: ObjectInputSerializable

import java.io.*;

public class Main {

   public static void main(String[] args) throws IOException, ClassNotFoundException {

       FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\save.ser");
       ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);

       UserInfo userInfo = new UserInfo("Paul", "Piper", "Paul Piper's passport data");

       objectOutputStream.writeObject(userInfo);

       objectOutputStream.close();

   }
}
encryptString()and yöntemlerinde decryptString(), gizli verilerin yazılacağı ve okunacağı formu doğrulamak için özellikle konsol çıktısı ekledik. Yukarıdaki kod aşağıdaki satırı görüntüledi: SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRh Şifreleme başarılı oldu! Dosyanın tam içeriği şuna benzer: ¬н sr UserInfoГ!}ҐџC‚ћ xpt Ivant Ivanovt $SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRhx Şimdi seri durumdan çıkarma mantığımızı kullanmayı deneyelim.

public class Main {

   public static void main(String[] args) throws IOException, ClassNotFoundException {

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\save.ser");
       ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);


       UserInfo userInfo = (UserInfo) objectInputStream.readObject();
       System.out.println(userInfo);

       objectInputStream.close();

   }
}
Burada hiçbir şey karmaşık görünmüyor. İşe yaramalı! Çalıştırıyoruz ve şunu alıyoruz... "main" dizisindeki istisna java.io.InvalidClassException: UserInfo; geçerli kurucu yok Dışsallaştırılabilir arayüzün tanıtımı - 4 Hata! :( Görünüşe göre bu o kadar kolay değil! Seri kaldırma mekanizması bir istisna attı ve varsayılan bir kurucu oluşturmamızı istedi. Nedenini merak ediyorum. ile bir Serializabletane olmadan idare ettik... :/ Burada önemli bir nüansla daha karşılaştık. Serializableve arasındaki fark Externalizableyalnızca programcının 'genişletilmiş' erişiminde ve süreci daha esnek bir şekilde kontrol etme yeteneğinde değil, aynı zamanda sürecin kendisinde de yatmaktadır .Serializable, bellek basitçe nesne için ayrılır ve ardından değerler akıştan okunur ve nesnenin alanlarını ayarlamak için kullanılır. kullanırsak Serializable, nesnenin yapıcısı çağrılmaz! Tüm iş yansıma (son derste kısaca bahsettiğimiz Reflection API) aracılığıyla gerçekleşir. ile Externalizableseri durumdan çıkarma mekanizması farklıdır. İlk önce varsayılan kurucu çağrılır. Ancak bundan sonra yaratılan UserInfonesnenin readExternal()yöntemi çağrılır. Nesnenin alanlarını ayarlamaktan sorumludur. Bu nedenle, arayüzü uygulayan herhangi bir sınıfın Externalizablevarsayılan bir yapıcıya sahip olması gerekir . Sınıfımıza bir tane ekleyelim UserInfove kodu tekrar çalıştıralım:

import java.io.*;

public class Main {

   public static void main(String[] args) throws IOException, ClassNotFoundException {

       FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\save.ser");
       ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);


       UserInfo userInfo = (UserInfo) objectInputStream.readObject();
       System.out.println(userInfo);

       objectInputStream.close();
   }
}
Konsol çıktısı: Paul Piper'ın pasaport verileri UserInfo \ firstName = 'Paul', lastName = 'Piper', superSecretInformation = 'Paul Piper'ın pasaport verileri' } Şimdi bu tamamen farklı bir şey! İlk olarak, gizli bilgiler içeren şifresi çözülmüş dizi konsolda görüntülendi. Ardından dosyadan kurtardığımız nesne bir dizi olarak görüntülendi! Böylece tüm sorunları başarıyla çözdük :) Serileştirme ve seriden çıkarma konusu basit görünüyor, ancak gördüğünüz gibi dersler uzun oldu. Ve ele almadığımız çok daha fazlası var! Bu arayüzlerin her birini kullanırken hala birçok incelik vardır. Ancak aşırı yeni bilgi yüzünden beyninizi patlatmaktan kaçınmak için, kısaca birkaç önemli nokta daha listeleyeceğim ve size ek okumalar için bağlantılar vereceğim. Peki, başka ne bilmeniz gerekiyor? İlk olarakSerializable , serileştirme sırasında ( veya kullanıp kullanmadığınıza bakılmaksızın Externalizable), değişkenlere dikkat edin static. kullandığınızda Serializable, bu alanlar hiçbir şekilde serileştirilmez (ve buna göre değerleri değişmez, çünkü staticalanlar nesneye değil sınıfa aittir). Ama kullandığınızdaExternalizable, süreci kendiniz kontrol edersiniz, böylece teknik olarak bunları seri hale getirebilirsiniz. Ancak, yapılması pek çok ince hataya yol açabileceğinden bunu önermiyoruz. İkincisi , değiştiricili değişkenlere de dikkat etmelisiniz final. kullandığınızda Serializable, her zamanki gibi serileştirilir ve seriden çıkarılır, ancak kullandığınızda , bir değişkenin Externalizableserisini kaldırmak imkansızdırfinal ! Nedeni basit: finalvarsayılan kurucu çağrıldığında tüm alanlar başlatılır - bundan sonra değerleri değiştirilemez. Bu nedenle, alanları olan nesneleri seri hale getirmek için finaltarafından sağlanan standart serileştirmeyi kullanın Serializable. Üçüncüsü , kalıtımı kullandığınızda, bazılarını miras alan tüm alt sınıflarExternalizablesınıfın ayrıca varsayılan kurucuları olmalıdır. İşte serileştirme mekanizmaları hakkında iyi makalenin bağlantısı: Bir sonrakine kadar! :)
Yorumlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION