Serializable
Мен өз жұмысымды жеңдім, және бүкіл процестің автоматты түрде орындалуы қуанбайды. Біз қарастырған мысалдар да күрделі емес еді. Сонымен, мәміле қандай? Неліктен бірдей тапсырма үшін басқа интерфейс? Өйткені, Serializable
оның бірқатар кемшіліктері бар. Олардың кейбірін тізіп көрейік:
-
Өнімділік. Интерфейстің
Serializable
көптеген артықшылықтары бар, бірақ жоғары өнімділік олардың бірі емес екені анық.
Біріншіден , ішкі механизм Serializable
жұмыс кезінде қызмет көрсету ақпаратының үлкен көлемін және уақытша деректердің әртүрлі түрлерін жасайды.
Екіншіден (қазір бұған кіріп, сізді қызықтыратын болса, бос уақытта оқудың қажеті жоқ), жұмыс Serializable
Reflection API пайдалануға негізделген. Бұл қайшылық сізге Java-да мүмкін емес болып көрінетін нәрселерді жасауға мүмкіндік береді: мысалы, жеке өрістердің мәндерін өзгерту. JavaRush-те Reflection API туралы тамаша мақала бар , ол туралы мына жерден оқи аласыз.
-
Икемділік. пайдаланған кезде сериялау-сериясыздандыру процесін мүлде басқармаймыз
Serializable
.Бір жағынан, бұл өте ыңғайлы, өйткені біз өнімділікке шынымен мән бермесек, codeты жазбау мүмкіндігі ыңғайлы болып көрінеді. Бірақ сериализация логикасына өзіміздің кейбір мүмкіндіктерімізді (олардың біреуінің мысалы төменде болады) қосу керек болса ше?
Негізінде, процесті басқаруымыз керек нәрсе -
transient
кейбір деректерді алып тастау үшін кілт сөз, және бұл. «Құралдар жинағы» сияқты:/ -
Қауіпсіздік. Бұл тармақ алдыңғысынан ішінара шығады.
Біз бұл туралы бұрын көп ойланбадық, бірақ сіздің сыныбыңыздағы кейбір ақпарат «басқалардың құлақтарына» (дәлірек айтқанда, көзге) арналмаған болса ше? Қарапайым мысал - қазіргі әлемде көптеген заңдармен реттелетін пароль немесе басқа жеке пайдаланушы деректері.
пайдалану арқылы
Serializable
біз бұл туралы ештеңе істей алмаймыз. Біз барлығын сол күйінде сериялаймыз.Бірақ, жақсы жағынан, біз мұндай деректерді файлға жазбас бұрын немесе желі арқылы жібермес бұрын шифрлауымыз керек. Бірақ
Serializable
бұл мүмкіндік бермейді.
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;
//...конструктор, геттеры, сеттеры, toString()...
@Override
public void writeExternal(ObjectOutput out) throws IOException {
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
}
}
Көріп отырғаныңыздай, біз айтарлықтай өзгерістер жасадық! Ең бастысы анық: интерфейсті жүзеге асыру кезінде Externalizable
сіз екі міндетті әдісті енгізуіңіз керек - writeExternal()
және readExternal()
. Жоғарыда айтқанымыздай, сериялау және сериядан шығару үшін барлық жауапкершілік бағдарламашыға жүктеледі. Дегенмен, енді сіз бұл процесті бақылаудың жоқтығы мәселесін шеше аласыз! Бүкіл процесті тікелей сіз бағдарламалайды, бұл, әрине, әлдеқайда икемді механизмді жасайды. Сонымен қатар, қауіпсіздік мәселесі де шешілді. Көріп отырғаныңыздай, біздің сыныпта өріс бар: шифрсыз сақтауға болмайтын жеке деректер. Енді біз осы шектеуге сәйкес келетін codeты оңай жаза аламыз. Мысалы, құпия деректерді шифрлау және шифрын шешу үшін біздің сыныпқа екі қарапайым жеке әдісті қосыңыз. Біз оларды файлға жазып, шифрланған түрде файлдан оқимыз. Ал қалған деректерді сол қалпында жазамыз және оқимыз :) Нәтижесінде біздің сынып келесідей болады:
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;
}
}
Біз туралы лекцияда кездестірген бірдей ObjectOutput out
және параметрлерді пайдаланатын екі әдісті іске асырдық . Қажетті уақытта біз қажетті деректерді шифрлаймыз немесе шифрын шешеміз және осы пішінде біз оны нысанымызды сериялау үшін пайдаланамыз. Бұл іс жүзінде қалай көрінетінін көрейік: ObjectInput
Serializable
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("Ivan", "Ivanov", "Ivan Ivanov's passport data");
objectOutputStream.writeObject(userInfo);
objectOutputStream.close();
}
}
encryptString()
және әдістерінде decryptString()
құпия деректердің қандай пішінде жазылатынын және оқылатынын тексеру үшін консольге арнайы шығыс қостық. Жоғарыдағы code консольге келесі жолды шығарады: SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRh Шифрлау сәтті аяқталды! Файлдың толық мазмұны келесідей: ¬н sr UserInfoГ!}ҐџC‚ћ xpt Ivant Ivanovt $SXZhbiBJdmFub3YncyBwYXNzcG9ydCBkYXRhx Енді біз жазған сериядан шығару логикасын қолданып көрейік.
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();
}
}
Мұнда күрделі ештеңе жоқ сияқты, ол жұмыс істеуі керек! Іске кірісейік... "main" ағынындағы ерекше жағдай java.io.InvalidClassException: UserInfo; Жарамды конструктор жоқ Қап :( Бұл соншалықты қарапайым емес болып шықты! Десерализация механизмі ерекше жағдай жасады және бізден әдепкі конструктор жасауды талап етті. Қызық, неге? Serializable
Біз онсыз да үлгердік... :/ Міне, тағы бір маңызды нюансқа келдік. .Айырмашылығы тек бағдарламашы үшін «кеңейтілген» қолжетімділікте және процесті икемді басқару мүмкіндігінде ғана емес, сонымен қатар процестің өзінде.Ең алдымен, сериядан шығару механизмінде ... Қолданылған кезде Serializable
жад жай ғана an object үшін бөлінген, содан кейін оның барлық өрістерін толтыратын ағыннан мәндер оқылады. Егер біз қолдансақ , an object конструкторы шақырылмайды! Барлық жұмыс рефлексия арқылы орындалады (Reflection API, біз оны соңғы бөлімде қысқаша атап өттік. лекция).Жағдайда сериясыздандыру механизмі басқаша болады.Басында әдепкі конструктор шақырылады.Содан кейін ғана an objectінің өрістерін толтыруға жауап беретін құрылған an object әдісіне шақырылады.Яғни . неге интерфейсті жүзеге асыратын кез келген класс әдепкі конструктор болуы керек . Оны сыныпқа қосып , codeты қайта іске қосайық: Externalizable
Serializable
Serializable
Externalizable
UserInfo
readExternal()
Externalizable
UserInfo
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();
}
}
Консоль шығысы: Ivan Ivanовтың төлқұжат деректері UserInfo{firstName='Ivan', lastName='Ivanov', superSecretInformation='Ivan Ivanовтың төлқұжат деректері'} Мүлдем басқа мәселе! Алдымен, құпия деректері бар шифрланған жол консольге шығарылды, содан кейін біздің нысан файлдан жол пішімінде қалпына келтірілді! Осылайша біз барлық мәселелерді сәтті шештік :) Серияландыру және сериядан шығару тақырыбы қарапайым сияқты, бірақ сіз көріп тұрғандай, біздің дәрістеріміз ұзақ болды. Және бұл бәрі емес! Осы интерфейстердің әрқайсысын пайдаланған кезде тағы да көптеген нәзіктіктер бар, бірақ енді сіздің миыңыз жаңа ақпарат көлемінен жарылып кетпеуі үшін мен тағы бірнеше маңызды ойларды қысқаша тізіп, қосымша оқуға сілтемелер беремін. Сонымен, сізге тағы не білу керек? БіріншіденSerializable
, сериялау кезінде ( немесе пайдаланғаныңыз маңызды емес Externalizable
), айнымалыларға назар аударыңыз static
. Пайдаланылған кезде Serializable
бұл өрістер мүлдем серияланбайды (және сәйкесінше олардың мәні өзгермейді, өйткені static
өрістер нысанға емес, сыныпқа жатады). Бірақ оны пайдаланған кезде Externalizable
сіз процесті өзіңіз басқарасыз, сондықтан техникалық түрде мұны жасауға болады. Бірақ бұл ұсынылмайды, өйткені бұл нәзік қателіктерге толы. Екіншіден , модификаторы бар айнымалыларға да назар аудару керек final
. Қолданылған кезде Serializable
олар әдеттегідей серияланады және сериядан шығарылады, бірақ пайдаланған кезде айнымалыны Externalizable
сериядан шығаруfinal
мүмкін емес ! Себебі қарапайым: барлық final
-өрістері әдепкі конструктор шақырылғанда инициализацияланады, содан кейін олардың мәнін өзгерту мүмкін емес. Сондықтан, final
-өрістері бар нысандарды сериялау үшін арқылы стандартты сериялауды пайдаланыңыз Serializable
. Үшіншіден , мұраны пайдаланған кезде, кейбір Externalizable
класстан түсетін барлық мұрагерлік сыныптарда әдепкі конструкторлар болуы керек. Мұнда сериялау механизмдері туралы жақсы мақалаларға сілтемелер берілген:
Кездескенше! :)
GO TO FULL VERSION