Serializable
దాని పని చేసింది, మరియు మొత్తం ప్రక్రియ యొక్క స్వయంచాలక అమలులో ఏది ఇష్టపడదు? మరియు మేము చూసిన ఉదాహరణలు కూడా సంక్లిష్టంగా లేవు. కాబట్టి సమస్య ఏమిటి? అదే పనుల కోసం మనకు మరొక ఇంటర్ఫేస్ ఎందుకు అవసరం? వాస్తవం ఏమిటంటే Serializable
అనేక లోపాలు ఉన్నాయి. మేము వాటిలో కొన్నింటిని జాబితా చేస్తాము:
-
ప్రదర్శన. ఇంటర్ఫేస్
Serializable
అనేక ప్రయోజనాలను కలిగి ఉంది, కానీ అధిక పనితీరు స్పష్టంగా వాటిలో ఒకటి కాదు.మొదటిది,
Serializable
యొక్క అంతర్గత అమలు పెద్ద మొత్తంలో సేవా సమాచారాన్ని మరియు అన్ని రకాల తాత్కాలిక డేటాను ఉత్పత్తి చేస్తుంది.రెండవది,
Serializable
రిఫ్లెక్షన్ APIపై ఆధారపడుతుంది (ప్రస్తుతం మీరు దీని గురించి లోతుగా డైవ్ చేయనవసరం లేదు; మీకు ఆసక్తి ఉంటే మీ తీరిక సమయంలో మీరు మరింత చదవవచ్చు). ఈ విషయం జావాలో అసాధ్యంగా అనిపించే పనులను చేయడానికి మిమ్మల్ని అనుమతిస్తుంది: ఉదాహరణకు, ప్రైవేట్ ఫీల్డ్ల విలువలను మార్చండి. కోడ్జిమ్లో రిఫ్లెక్షన్ API గురించి అద్భుతమైన కథనం ఉంది . మీరు దాని గురించి అక్కడ చదువుకోవచ్చు. -
వశ్యత. మేము ఇంటర్ఫేస్ను ఉపయోగించినప్పుడు సీరియలైజేషన్-డీరియలైజేషన్ ప్రక్రియను నియంత్రించము
Serializable
.ఒక వైపు, ఇది చాలా సౌకర్యవంతంగా ఉంటుంది, ఎందుకంటే మేము పనితీరు గురించి ప్రత్యేకంగా ఆందోళన చెందకపోతే, కోడ్ వ్రాయనవసరం లేదు. అయితే మనం నిజంగా మన స్వంత ఫీచర్లలో కొన్నింటిని (మేము దిగువ ఉదాహరణను అందిస్తాము) సీరియలైజేషన్ లాజిక్కు జోడించాల్సిన అవసరం ఉంటే?
ప్రాథమికంగా, మేము ప్రక్రియను నియంత్రించాల్సింది
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;
// ...constructor, getters, setters, toString()...
@Override
public void writeExternal(ObjectOutput out) throws IOException {
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
}
}
మీరు గమనిస్తే, మాకు ముఖ్యమైన మార్పులు ఉన్నాయి! ప్రధానమైనది స్పష్టంగా ఉంది: Externalizable
ఇంటర్ఫేస్ను అమలు చేస్తున్నప్పుడు, మీరు తప్పనిసరిగా రెండు అవసరమైన పద్ధతులను అమలు చేయాలి: writeExternal()
మరియుreadExternal()
. మేము ముందే చెప్పినట్లు, సీరియలైజేషన్ మరియు డీరియలైజేషన్ బాధ్యత ప్రోగ్రామర్పై ఉంటుంది. కానీ ఇప్పుడు మీరు ప్రక్రియపై నియంత్రణ లేని సమస్యను పరిష్కరించవచ్చు! మొత్తం ప్రక్రియ మీచే నేరుగా ప్రోగ్రామ్ చేయబడుతుంది. సహజంగానే, ఇది మరింత సౌకర్యవంతమైన యంత్రాంగాన్ని అనుమతిస్తుంది. అదనంగా, భద్రతతో సమస్య పరిష్కరించబడుతుంది. మీరు చూడగలిగినట్లుగా, మా తరగతికి వ్యక్తిగత డేటా ఫీల్డ్ ఉంది, అది గుప్తీకరించబడదు. ఇప్పుడు మనం ఈ పరిమితిని సంతృప్తిపరిచే కోడ్ని సులభంగా వ్రాయవచ్చు. ఉదాహరణకు, సున్నితమైన డేటాను గుప్తీకరించడానికి మరియు డీక్రిప్ట్ చేయడానికి మేము మా తరగతికి రెండు సాధారణ ప్రైవేట్ పద్ధతులను జోడించవచ్చు. మేము ఫైల్కు డేటాను వ్రాస్తాము మరియు ఫైల్ నుండి ఎన్క్రిప్టెడ్ రూపంలో చదువుతాము. మిగిలిన డేటా అలాగే వ్రాయబడుతుంది మరియు చదవబడుతుంది :) ఫలితంగా, మా తరగతి ఇలా కనిపిస్తుంది:
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
మరియు పారామితులను ఉపయోగించే రెండు పద్ధతులను మేము అమలు చేసాము . సరైన సమయంలో, మేము అవసరమైన డేటాను ఎన్క్రిప్ట్ చేస్తాము లేదా డీక్రిప్ట్ చేస్తాము మరియు మా ఆబ్జెక్ట్ని సీరియల్ చేయడానికి గుప్తీకరించిన డేటాను ఉపయోగిస్తాము. ఇది ఆచరణలో ఎలా కనిపిస్తుందో చూద్దాం: 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("Paul", "Piper", "Paul Piper's passport data");
objectOutputStream.writeObject(userInfo);
objectOutputStream.close();
}
}
encryptString()
మరియు పద్ధతులలో decryptString()
, రహస్య డేటా వ్రాయబడే మరియు చదవబడే ఫారమ్ను ధృవీకరించడానికి మేము ప్రత్యేకంగా కన్సోల్ అవుట్పుట్ని జోడించాము. ఎగువ కోడ్ కింది పంక్తిని ప్రదర్శించింది: 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();
}
}
బాగా, ఇక్కడ ఏమీ సంక్లిష్టంగా అనిపించదు. ఇది పని చేయాలి! మేము దీన్ని అమలు చేసి పొందుతాము... థ్రెడ్ "ప్రధాన" java.io.InvalidClassExceptionలో మినహాయింపు: UserInfo; చెల్లుబాటు అయ్యే కన్స్ట్రక్టర్ లేదు 
Serializable
మేము ఒకటి లేకుండానే పొందాము... :/ ఇక్కడ మేము మరొక ముఖ్యమైన సూక్ష్మభేదాన్ని ఎదుర్కొన్నాము. మధ్య Serializable
మరియు Externalizable
వ్యత్యాసం ప్రోగ్రామర్ యొక్క 'విస్తరించిన' యాక్సెస్ మరియు ప్రక్రియను మరింత సరళంగా నియంత్రించే సామర్థ్యంలో మాత్రమే కాకుండా, ప్రక్రియలో కూడా ఉంటుంది. అన్నింటికంటే, డీరియలైజేషన్ మెకానిజంలో . ఉపయోగిస్తున్నప్పుడుSerializable
, మెమరీ కేవలం వస్తువు కోసం కేటాయించబడుతుంది, ఆపై విలువలు స్ట్రీమ్ నుండి చదవబడతాయి మరియు వస్తువు యొక్క ఫీల్డ్లను సెట్ చేయడానికి ఉపయోగించబడతాయి. మేము ఉపయోగిస్తే Serializable
, ఆబ్జెక్ట్ యొక్క కన్స్ట్రక్టర్ పిలవబడదు! అన్ని పని ప్రతిబింబం ద్వారా జరుగుతుంది (రిఫ్లెక్షన్ API, మేము చివరి పాఠంలో క్లుప్తంగా పేర్కొన్నాము). తో 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();
}
}
కన్సోల్ అవుట్పుట్: పాల్ పైపర్ పాస్పోర్ట్ డేటా UserInfo \ firstName = 'Paul', lastName = 'Piper', superSecretInformation = 'Paul Piper's passport data' } ఇప్పుడు అది పూర్తిగా భిన్నమైనది! ముందుగా, రహస్య సమాచారంతో డీక్రిప్ట్ చేయబడిన స్ట్రింగ్ కన్సోల్లో ప్రదర్శించబడుతుంది. అప్పుడు ఫైల్ నుండి మనం కోలుకున్న వస్తువు స్ట్రింగ్గా ప్రదర్శించబడుతుంది! కాబట్టి మేము అన్ని సమస్యలను విజయవంతంగా పరిష్కరించాము :) సీరియలైజేషన్ మరియు డీరియలైజేషన్ యొక్క అంశం చాలా సరళంగా అనిపిస్తుంది, కానీ, మీరు చూడగలిగినట్లుగా, పాఠాలు చాలా పొడవుగా ఉన్నాయి. ఇంకా మనం కవర్ చేయనివి చాలా ఉన్నాయి! ఈ ప్రతి ఇంటర్ఫేస్లను ఉపయోగిస్తున్నప్పుడు ఇంకా అనేక సూక్ష్మబేధాలు ఉన్నాయి. కానీ మితిమీరిన కొత్త సమాచారం నుండి మీ మెదడు పేలకుండా ఉండటానికి, నేను మరికొన్ని ముఖ్యమైన అంశాలను క్లుప్తంగా జాబితా చేస్తాను మరియు అదనపు పఠనానికి మీకు లింక్లను ఇస్తాను. కాబట్టి, మీరు ఇంకా ఏమి తెలుసుకోవాలి? ముందుగా , సీరియలైజేషన్ సమయంలో (మీరు ఉపయోగిస్తున్నారా Serializable
లేదా అనే దానితో సంబంధం లేకుండా), వేరియబుల్స్పై Externalizable
శ్రద్ధ వహించండి . static
మీరు ఉపయోగించినప్పుడు Serializable
, ఈ ఫీల్డ్లు అస్సలు క్రమీకరించబడవు (మరియు, తదనుగుణంగా, వాటి విలువలు మారవు, ఎందుకంటే static
ఫీల్డ్లు తరగతికి చెందినవి, వస్తువు కాదు). కానీ మీరు ఉపయోగించినప్పుడుExternalizable
, మీరు ప్రక్రియను మీరే నియంత్రిస్తారు, కాబట్టి సాంకేతికంగా మీరు వాటిని సీరియల్ చేయవచ్చు. కానీ, మేము దీన్ని సిఫార్సు చేయము, ఎందుకంటే చేయడం వలన చాలా సూక్ష్మ బగ్లు ఏర్పడే అవకాశం ఉంది. రెండవది , మీరు మాడిఫైయర్తో వేరియబుల్స్పై కూడా శ్రద్ధ వహించాలి final
. మీరు ఉపయోగించినప్పుడు Serializable
, అవి యధావిధిగా ధారావాహిక మరియు డీరియలైజ్ చేయబడతాయి, కానీ మీరు ఉపయోగించినప్పుడు , వేరియబుల్ను Externalizable
డీరియలైజ్ చేయడం అసాధ్యంfinal
! కారణం చాలా సులభం: final
డిఫాల్ట్ కన్స్ట్రక్టర్ని పిలిచినప్పుడు అన్ని ఫీల్డ్లు ప్రారంభించబడతాయి - ఆ తర్వాత, వాటి విలువ మార్చబడదు. అందువల్ల, ఫీల్డ్లను కలిగి ఉన్న వస్తువులను సీరియలైజ్ చేయడానికి final
, అందించిన ప్రామాణిక సీరియలైజేషన్ను ఉపయోగించండి Serializable
. మూడవది , మీరు వారసత్వాన్ని ఉపయోగించినప్పుడు, కొన్ని వారసత్వంగా వచ్చే అన్ని వారసుల తరగతులుExternalizable
తరగతి తప్పనిసరిగా డిఫాల్ట్ కన్స్ట్రక్టర్లను కూడా కలిగి ఉండాలి. సీరియలైజేషన్ మెకానిజమ్స్ గురించి మంచి కథనానికి ఇక్కడ లింక్ ఉంది:
మరల సారి వరకు! :)
GO TO FULL VERSION