CodeGym /జావా బ్లాగ్ /యాదృచ్ఛికంగా /ప్రతిబింబం API: ప్రతిబింబం. జావా యొక్క చీకటి వైపు
John Squirrels
స్థాయి
San Francisco

ప్రతిబింబం API: ప్రతిబింబం. జావా యొక్క చీకటి వైపు

సమూహంలో ప్రచురించబడింది
నమస్కారం, యువ పడవాన్. ఈ ఆర్టికల్‌లో, జావా ప్రోగ్రామర్లు అసాధ్యమైన పరిస్థితుల్లో మాత్రమే ఉపయోగించే ఫోర్స్ గురించి నేను మీకు చెప్తాను. జావా యొక్క చీకటి వైపు ప్రతిబింబం API. జావాలో, జావా రిఫ్లెక్షన్ API ఉపయోగించి ప్రతిబింబం అమలు చేయబడుతుంది.

జావా ప్రతిబింబం అంటే ఏమిటి?

ఇంటర్నెట్‌లో చిన్న, ఖచ్చితమైన మరియు ప్రసిద్ధ నిర్వచనం ఉంది. ప్రతిబింబం ( చివరి లాటిన్ రిఫ్లెక్సియో నుండి - వెనుకకు తిరగడానికి ) అనేది ప్రోగ్రామ్ నడుస్తున్నప్పుడు దాని గురించిన డేటాను అన్వేషించడానికి ఒక మెకానిజం. ఫీల్డ్‌లు, పద్ధతులు మరియు క్లాస్ కన్‌స్ట్రక్టర్‌ల గురించి సమాచారాన్ని అన్వేషించడానికి ప్రతిబింబం మిమ్మల్ని అనుమతిస్తుంది. కంపైల్ సమయంలో లేని రకాలతో పని చేయడానికి ప్రతిబింబం మిమ్మల్ని అనుమతిస్తుంది, కానీ అవి అమలు సమయంలో అందుబాటులోకి వచ్చాయి. ప్రతిబింబం మరియు లోపం సమాచారాన్ని జారీ చేయడానికి తార్కికంగా స్థిరమైన నమూనా సరైన డైనమిక్ కోడ్‌ను సృష్టించడం సాధ్యం చేస్తుంది. మరో మాటలో చెప్పాలంటే, జావాలో ప్రతిబింబం ఎలా పనిచేస్తుందో అర్థం చేసుకోవడం మీ కోసం అనేక అద్భుతమైన అవకాశాలను తెరుస్తుంది. మీరు అక్షరాలా తరగతులు మరియు వాటి భాగాలను మోసగించవచ్చు. ప్రతిబింబం అనుమతించే ప్రాథమిక జాబితా ఇక్కడ ఉంది:
  • ఒక వస్తువు యొక్క తరగతిని నేర్చుకోండి/నిర్ణయించండి;
  • తరగతి మాడిఫైయర్‌లు, ఫీల్డ్‌లు, పద్ధతులు, స్థిరాంకాలు, కన్‌స్ట్రక్టర్‌లు మరియు సూపర్‌క్లాస్‌ల గురించి సమాచారాన్ని పొందండి;
  • అమలు చేయబడిన ఇంటర్‌ఫేస్(ల)కి చెందిన పద్ధతులు ఏవి ఉన్నాయో తెలుసుకోండి;
  • రన్ టైమ్ వరకు క్లాస్ పేరు తెలియని క్లాస్ యొక్క ఉదాహరణను సృష్టించండి;
  • వస్తువు యొక్క ఫీల్డ్‌ల విలువలను పేరుతో పొందండి మరియు సెట్ చేయండి;
  • వస్తువు యొక్క పద్ధతిని పేరుతో పిలవండి.
దాదాపు అన్ని ఆధునిక జావా సాంకేతికతలలో ప్రతిబింబం ఉపయోగించబడుతుంది. జావా, ఒక ప్లాట్‌ఫారమ్‌గా, ప్రతిబింబం లేకుండా ఇంత విస్తృతమైన స్వీకరణను సాధించగలదని ఊహించడం కష్టం. చాలా మటుకు, అది ఉండదు. ఇప్పుడు మీరు సాధారణంగా ప్రతిబింబాన్ని సైద్ధాంతిక భావనగా పరిచయం చేసుకున్నారు, దాని ఆచరణాత్మక అనువర్తనానికి వెళ్దాం! మేము రిఫ్లెక్షన్ API యొక్క అన్ని పద్ధతులను నేర్చుకోము—మీరు ఆచరణలో ఎదుర్కొనే వాటిని మాత్రమే. ప్రతిబింబం అనేది తరగతులతో పని చేయడాన్ని కలిగి ఉంటుంది కాబట్టి, మేము అనే సాధారణ తరగతితో ప్రారంభిస్తాము MyClass:

public class MyClass {
   private int number;
   private String name = "default";
//    public MyClass(int number, String name) {
//        this.number = number;
//        this.name = name;
//    }
   public int getNumber() {
       return number;
   }
   public void setNumber(int number) {
       this.number = number;
   }
   public void setName(String name) {
       this.name = name;
   }
   private void printData(){
       System.out.println(number + name);
   }
}
మీరు గమనిస్తే, ఇది చాలా ప్రాథమిక తరగతి. పారామితులతో కూడిన కన్స్ట్రక్టర్ ఉద్దేశపూర్వకంగా వ్యాఖ్యానించబడింది. మేము దాని తర్వాత తిరిగి వస్తాము. మీరు తరగతిలోని కంటెంట్‌లను జాగ్రత్తగా పరిశీలిస్తే, పేరు ఫీల్డ్‌కు పొందే వ్యక్తి లేకపోవడాన్ని మీరు గమనించవచ్చు . పేరు ఫీల్డ్ ప్రైవేట్ యాక్సెస్ మాడిఫైయర్‌తో గుర్తించబడింది : మేము దానిని క్లాస్ వెలుపల యాక్సెస్ చేయలేము అంటే దాని విలువను మనం తిరిగి పొందలేము . " ఐతే సమస్య ఏమిటి ?" మీరు చెప్పే. " గెటర్‌ను జోడించండి లేదా యాక్సెస్ మాడిఫైయర్‌ని మార్చండి". మరియు మీరు తప్ప, సరిగ్గా ఉంటారుMyClassసంకలనం చేయబడిన AAR లైబ్రరీలో లేదా మార్పులు చేయగల సామర్థ్యం లేని మరొక ప్రైవేట్ మాడ్యూల్‌లో ఉంది. ఆచరణలో, ఇది అన్ని సమయాలలో జరుగుతుంది. మరియు కొంతమంది అజాగ్రత్త ప్రోగ్రామర్లు గెట్టర్ రాయడం మర్చిపోయారు . ప్రతిబింబాన్ని గుర్తుంచుకోవలసిన సమయం ఇదే! తరగతి యొక్క ప్రైవేట్ పేరు ఫీల్డ్‌ని పొందడానికి ప్రయత్నిద్దాం MyClass:

public static void main(String[] args) {
   MyClass myClass = new MyClass();
   int number = myClass.getNumber();
   String name = null; // No getter =(
   System.out.println(number + name); // Output: 0null
   try {
       Field field = myClass.getClass().getDeclaredField("name");
       field.setAccessible(true);
       name = (String) field.get(myClass);
   } catch (NoSuchFieldException | IllegalAccessException e) {
       e.printStackTrace();
   }
   System.out.println(number + name); // Output: 0default
}
ఇప్పుడేం జరిగిందో విశ్లేషిద్దాం. జావాలో, అనే అద్భుతమైన తరగతి ఉంది Class. ఇది ఎక్జిక్యూటబుల్ జావా అప్లికేషన్‌లో తరగతులు మరియు ఇంటర్‌ఫేస్‌లను సూచిస్తుంది. Classమరియు మధ్య సంబంధాన్ని మేము కవర్ చేయము ClassLoader, ఎందుకంటే అది ఈ కథనం యొక్క అంశం కాదు. తర్వాత, ఈ తరగతి ఫీల్డ్‌లను తిరిగి పొందడానికి, మీరు getFields()పద్ధతికి కాల్ చేయాలి. ఈ పద్ధతి ఈ తరగతి యాక్సెస్ చేయగల ఫీల్డ్‌లన్నింటినీ అందిస్తుంది. ఇది మాకు పని చేయదు, ఎందుకంటే మా ఫీల్డ్ ప్రైవేట్‌గా ఉంది , కాబట్టి మేము getDeclaredFields()పద్ధతిని ఉపయోగిస్తాము. ఈ పద్ధతి క్లాస్ ఫీల్డ్‌ల శ్రేణిని కూడా అందిస్తుంది, కానీ ఇప్పుడు ఇది ప్రైవేట్ మరియు రక్షిత ఫీల్డ్‌లను కలిగి ఉంటుంది. ఈ సందర్భంలో, మనకు ఆసక్తి ఉన్న ఫీల్డ్ పేరు మాకు తెలుసు, కాబట్టి మేము getDeclaredField(String)ఎక్కడ పద్ధతిని ఉపయోగించవచ్చుStringకావలసిన ఫీల్డ్ పేరు. గమనిక: getFields()మరియు getDeclaredFields()పేరెంట్ క్లాస్ ఫీల్డ్‌లను తిరిగి ఇవ్వవద్దు! గొప్ప. Fieldమా పేరును సూచించే వస్తువు వచ్చింది . ఫీల్డ్ పబ్లిక్ కాదు కాబట్టి , మేము దానితో పని చేయడానికి తప్పనిసరిగా యాక్సెస్‌ని మంజూరు చేయాలి. పద్ధతి setAccessible(true)మరింత ముందుకు సాగడానికి అనుమతిస్తుంది. ఇప్పుడు పేరు ఫీల్డ్ మా పూర్తి నియంత్రణలో ఉంది! Fieldమీరు ఆబ్జెక్ట్ యొక్క పద్ధతిని కాల్ చేయడం ద్వారా దాని విలువను తిరిగి పొందవచ్చు get(Object), ఇక్కడ Objectమా తరగతికి సంబంధించిన ఉదాహరణ ఉంది MyClass. మేము రకాన్ని మార్చాము మరియు మా పేరుString వేరియబుల్‌కు విలువను కేటాయిస్తాము . పేరు ఫీల్డ్‌కు కొత్త విలువను సెట్ చేయడానికి మేము సెట్టర్‌ను కనుగొనలేకపోతే , మీరు సెట్ పద్ధతిని ఉపయోగించవచ్చు :

field.set(myClass, (String) "new value");
అభినందనలు! మీరు ఇప్పుడే ప్రతిబింబం యొక్క ప్రాథమికాలను స్వాధీనం చేసుకున్నారు మరియు ప్రైవేట్ ఫీల్డ్‌ని యాక్సెస్ చేసారు! try/catchబ్లాక్ మరియు నిర్వహించబడుతున్న మినహాయింపుల రకాలపై శ్రద్ధ వహించండి . IDE వారి ఉనికిని దానంతటదే మీకు తెలియజేస్తుంది, కానీ వారు ఇక్కడ ఎందుకు ఉన్నారో వారి పేర్లతో మీరు స్పష్టంగా చెప్పగలరు. వెళ్ళేముందు! మీరు గమనించినట్లుగా, MyClassతరగతి డేటా గురించి సమాచారాన్ని ప్రదర్శించడానికి మా తరగతికి ఇప్పటికే ఒక పద్ధతి ఉంది:

private void printData(){
       System.out.println(number + name);
   }
కానీ ఈ ప్రోగ్రామర్ తన వేలిముద్రలను ఇక్కడ కూడా వదిలేశాడు. పద్ధతికి ప్రైవేట్ యాక్సెస్ మాడిఫైయర్ ఉంది మరియు ప్రతిసారీ డేటాను ప్రదర్శించడానికి మేము మా స్వంత కోడ్‌ను వ్రాయాలి. ఏమిటీ గొడవ. మన ప్రతిబింబం ఎక్కడికి వెళ్ళింది? కింది విధిని వ్రాయండి:

public static void printData(Object myClass){
   try {
       Method method = myClass.getClass().getDeclaredMethod("printData");
       method.setAccessible(true);
       method.invoke(myClass);
   } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
       e.printStackTrace();
   }
}
ఫీల్డ్‌ని తిరిగి పొందడానికి ఉపయోగించే విధానం ఇక్కడ కూడా ఉంటుంది. మేము పేరు ద్వారా కావలసిన పద్ధతిని యాక్సెస్ చేస్తాము మరియు దానికి ప్రాప్యతను మంజూరు చేస్తాము. మరియు వస్తువుపై Methodమేము invoke(Object, Args)పద్ధతి అని పిలుస్తాము, ఇక్కడ తరగతి Objectయొక్క ఉదాహరణ కూడా MyClass. Argsఅనేది పద్ధతి యొక్క వాదనలు, మాది ఏదీ లేనప్పటికీ. ఇప్పుడు మేము printDataసమాచారాన్ని ప్రదర్శించడానికి ఫంక్షన్‌ని ఉపయోగిస్తాము:

public static void main(String[] args) {
   MyClass myClass = new MyClass();
   int number = myClass.getNumber();
   String name = null; //?
   printData(myClass); // Output: 0default
   try {
       Field field = myClass.getClass().getDeclaredField("name");
       field.setAccessible(true);
       field.set(myClass, (String) "new value");
       name = (String) field.get(myClass);
   } catch (NoSuchFieldException | IllegalAccessException e) {
       e.printStackTrace();
   }
   printData(myClass);// Output: 0new value
}
హుర్రే! ఇప్పుడు మేము తరగతి యొక్క ప్రైవేట్ పద్ధతికి ప్రాప్యతను కలిగి ఉన్నాము. కానీ పద్ధతికి వాదనలు ఉంటే ఏమి చేయాలి మరియు కన్స్ట్రక్టర్ ఎందుకు వ్యాఖ్యానించబడ్డాడు? ప్రతిదీ దాని స్వంత సమయంలో. రన్ టైమ్‌లో (ప్రోగ్రామ్ రన్ అవుతున్నప్పుడు) క్లాస్ ఇన్‌స్టాన్స్‌లను సృష్టించడానికి ప్రతిబింబం మిమ్మల్ని అనుమతిస్తుంది అని ప్రారంభంలో ఉన్న నిర్వచనం నుండి స్పష్టంగా తెలుస్తుంది ! మేము తరగతి పూర్తి పేరును ఉపయోగించి ఒక వస్తువును సృష్టించవచ్చు. తరగతి యొక్క పూర్తి పేరు దాని ప్యాకేజీ యొక్క మార్గంతో సహా తరగతి పేరు .
ప్రతిబింబం API: ప్రతిబింబం.  జావా యొక్క చీకటి వైపు - 2
నా ప్యాకేజీ సోపానక్రమంలో, MyClass యొక్క పూర్తి పేరు "reflection.MyClass". తరగతి పేరును తెలుసుకోవడానికి ఒక సులభమైన మార్గం కూడా ఉంది (తరగతి పేరును స్ట్రింగ్‌గా తిరిగి ఇవ్వండి):

MyClass.class.getName()
తరగతి యొక్క ఉదాహరణను సృష్టించడానికి జావా ప్రతిబింబాన్ని ఉపయోగిస్తాము:

public static void main(String[] args) {
   MyClass myClass = null;
   try {
       Class clazz = Class.forName(MyClass.class.getName());
       myClass = (MyClass) clazz.newInstance();
   } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
       e.printStackTrace();
   }
   System.out.println(myClass); // Output: created object reflection.MyClass@60e53b93
}
జావా అప్లికేషన్ ప్రారంభమైనప్పుడు, అన్ని తరగతులు JVMలోకి లోడ్ చేయబడవు. మీ కోడ్ తరగతిని సూచించకపోతే MyClass, ClassLoaderJVMలో తరగతులను లోడ్ చేయడానికి బాధ్యత వహించే , తరగతిని ఎప్పటికీ లోడ్ చేయదు. అంటే మీరు ClassLoaderదానిని లోడ్ చేయమని బలవంతం చేయాలి మరియు వేరియబుల్ రూపంలో తరగతి వివరణను పొందాలి Class. అందుకే మనకు forName(String)పద్ధతి ఉంది, Stringమనకు అవసరమైన తరగతి పేరు ఎక్కడ ఉంది. ఆబ్జెక్ట్‌ని పొందిన తర్వాత Сlass, పద్ధతికి కాల్ చేయడం వలన ఆ వివరణను ఉపయోగించి సృష్టించబడిన వస్తువు newInstance()తిరిగి వస్తుంది . Objectఈ వస్తువును మనకు సరఫరా చేయడమే మిగిలి ఉందిMyClassతరగతి. కూల్! ఇది కష్టం, కానీ అర్థమయ్యేలా ఉంది, నేను ఆశిస్తున్నాను. ఇప్పుడు మనం క్లాస్ యొక్క ఉదాహరణను అక్షరాలా ఒక లైన్‌లో సృష్టించవచ్చు! దురదృష్టవశాత్తూ, వివరించిన విధానం డిఫాల్ట్ కన్స్ట్రక్టర్‌తో మాత్రమే పని చేస్తుంది (పారామితులు లేకుండా). మీరు పారామితులతో పద్ధతులు మరియు కన్స్ట్రక్టర్‌లను ఎలా పిలుస్తారు? మా కన్స్ట్రక్టర్‌ను అన్‌కమెంట్ చేయడానికి ఇది సమయం. ఊహించినట్లుగా, newInstance()డిఫాల్ట్ కన్స్ట్రక్టర్‌ని కనుగొనలేకపోయాము మరియు ఇకపై పని చేయదు. క్లాస్ ఇన్‌స్టాంటియేషన్‌ని మళ్లీ వ్రాద్దాం:

public static void main(String[] args) {
   MyClass myClass = null;
   try {
       Class clazz = Class.forName(MyClass.class.getName());
       Class[] params = {int.class, String.class};
       myClass = (MyClass) clazz.getConstructor(params).newInstance(1, "default2");
   } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
       e.printStackTrace();
   }
   System.out.println(myClass);// Output: created object reflection.MyClass@60e53b93
}
క్లాస్ కన్‌స్ట్రక్టర్‌లను పొందేందుకు క్లాస్ డెఫినిషన్‌పై పద్ధతిని getConstructors()పిలవాలి, ఆపై getParameterTypes()కన్స్ట్రక్టర్ యొక్క పారామితులను పొందడానికి పిలవాలి:

Constructor[] constructors = clazz.getConstructors();
for (Constructor constructor : constructors) {
   Class[] paramTypes = constructor.getParameterTypes();
   for (Class paramType : paramTypes) {
       System.out.print(paramType.getName() + " ");
   }
   System.out.println();
}
అది మనందరికీ కన్స్ట్రక్టర్‌లు మరియు వాటి పారామితులను అందజేస్తుంది. నా ఉదాహరణలో, నేను నిర్దిష్ట, గతంలో తెలిసిన పారామితులతో నిర్దిష్ట కన్స్ట్రక్టర్‌ని సూచిస్తాను. మరియు ఈ కన్స్ట్రక్టర్‌ను కాల్ చేయడానికి, మేము newInstanceఈ పారామితుల విలువలను పాస్ చేసే పద్ధతిని ఉపయోగిస్తాము. invokeకాల్ పద్ధతులను ఉపయోగిస్తున్నప్పుడు కూడా అదే విధంగా ఉంటుంది . ఇది ప్రశ్న వేస్తుంది: ప్రతిబింబం ద్వారా కన్స్ట్రక్టర్‌లను పిలవడం ఎప్పుడు ఉపయోగపడుతుంది? ఇప్పటికే ప్రారంభంలో పేర్కొన్నట్లుగా, ఆధునిక జావా సాంకేతికతలు జావా రిఫ్లెక్షన్ API లేకుండా పొందలేవు. ఉదాహరణకు, డిపెండెన్సీ ఇంజెక్షన్ (DI), ఇది పద్ధతులు మరియు కన్స్ట్రక్టర్‌ల ప్రతిబింబంతో ఉల్లేఖనాలను మిళితం చేసి జనాదరణ పొందిన డేరర్‌ను ఏర్పరుస్తుందిAndroid అభివృద్ధి కోసం లైబ్రరీ. ఈ కథనాన్ని చదివిన తర్వాత, మీరు జావా రిఫ్లెక్షన్ API యొక్క మార్గాల్లో విద్యావంతులని నమ్మకంగా పరిగణించవచ్చు. వారు ప్రతిబింబాన్ని జావా యొక్క చీకటి వైపు ఏమీ అనరు. ఇది OOP నమూనాను పూర్తిగా విచ్ఛిన్నం చేస్తుంది. జావాలో, ఎన్‌క్యాప్సులేషన్ కొన్ని ప్రోగ్రామ్ భాగాలకు ఇతరుల యాక్సెస్‌ను దాచిపెడుతుంది మరియు పరిమితం చేస్తుంది. మేము ప్రైవేట్ మాడిఫైయర్‌ని ఉపయోగించినప్పుడు, ఆ ఫీల్డ్ ఉన్న తరగతి నుండి మాత్రమే యాక్సెస్ చేయాలని మేము భావిస్తున్నాము. మరియు మేము ఈ సూత్రం ఆధారంగా ప్రోగ్రామ్ యొక్క తదుపరి నిర్మాణాన్ని నిర్మిస్తాము. ఈ కథనంలో, మీరు ఎక్కడైనా మీ దారిని బలవంతం చేయడానికి ప్రతిబింబాన్ని ఎలా ఉపయోగించవచ్చో మేము చూశాము. క్రియేషనల్ డిజైన్ నమూనా సింగిల్టన్నిర్మాణ పరిష్కారంగా దీనికి మంచి ఉదాహరణ. ప్రాథమిక ఆలోచన ఏమిటంటే, ఈ నమూనాను అమలు చేసే తరగతి మొత్తం ప్రోగ్రామ్‌ను అమలు చేసే సమయంలో ఒక ఉదాహరణ మాత్రమే ఉంటుంది. డిఫాల్ట్ కన్స్ట్రక్టర్‌కు ప్రైవేట్ యాక్సెస్ మాడిఫైయర్‌ని జోడించడం ద్వారా ఇది సాధించబడుతుంది. మరియు ఒక ప్రోగ్రామర్ అటువంటి తరగతులకు సంబంధించిన మరిన్ని ఉదాహరణలను సృష్టించడానికి ప్రతిబింబాన్ని ఉపయోగించినట్లయితే అది చాలా చెడ్డది. మార్గం ద్వారా, నేను ఇటీవల ఒక సహోద్యోగి చాలా ఆసక్తికరమైన ప్రశ్న అడగడం విన్నాను: సింగిల్టన్ నమూనాను అమలు చేసే తరగతి వారసత్వంగా పొందవచ్చా? ఈ సందర్భంలో, ప్రతిబింబం కూడా శక్తిలేనిది కావచ్చు? వ్యాసం గురించి మీ అభిప్రాయాన్ని మరియు దిగువ వ్యాఖ్యలలో మీ సమాధానాన్ని తెలియజేయండి మరియు అక్కడ మీ స్వంత ప్రశ్నలను అడగండి!
వ్యాఖ్యలు
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION