CodeGym /జావా బ్లాగ్ /యాదృచ్ఛికంగా /ప్రతిబింబం యొక్క ఉదాహరణలు
John Squirrels
స్థాయి
San Francisco

ప్రతిబింబం యొక్క ఉదాహరణలు

సమూహంలో ప్రచురించబడింది
బహుశా మీరు సాధారణ జీవితంలో "ప్రతిబింబం" అనే భావనను ఎదుర్కొన్నారు. ఈ పదం సాధారణంగా తనను తాను అధ్యయనం చేసే ప్రక్రియను సూచిస్తుంది. ప్రోగ్రామింగ్‌లో, ఇది సారూప్యమైన అర్థాన్ని కలిగి ఉంటుంది - ఇది ప్రోగ్రామ్ రన్ అవుతున్నప్పుడు ప్రోగ్రామ్ గురించి డేటాను విశ్లేషించడానికి మరియు ప్రోగ్రామ్ యొక్క నిర్మాణం మరియు ప్రవర్తనను కూడా మార్చడానికి ఒక మెకానిజం. ప్రతిబింబానికి ఉదాహరణలు - 1 ఇక్కడ ముఖ్యమైనది ఏమిటంటే, మేము దీన్ని రన్‌టైమ్‌లో చేస్తున్నాము, కంపైల్ సమయంలో కాదు. అయితే రన్‌టైమ్‌లో కోడ్‌ను ఎందుకు పరిశీలించాలి? అన్నింటికంటే, మీరు ఇప్పటికే కోడ్‌ను చదవగలరు :/ ప్రతిబింబం యొక్క ఆలోచన వెంటనే స్పష్టంగా తెలియకపోవడానికి ఒక కారణం ఉంది: ఈ సమయం వరకు, మీరు ఏ తరగతులతో పని చేస్తున్నారో మీకు ఎల్లప్పుడూ తెలుసు. ఉదాహరణకు, మీరు ఒక Catతరగతిని వ్రాయవచ్చు:

package learn.codegym;

public class Cat {

   private String name;
   private int age;

   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   public void sayMeow() {

       System.out.println("Meow!");
   }

   public void jump() {

       System.out.println("Jump!");
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       this.age = age;
   }

@Override
public String toString() {
   return "Cat{" +
           "name='" + name + '\'' +
           ", age=" + age +
           '}';
}

}
మీరు దాని గురించి ప్రతిదీ తెలుసు, మరియు మీరు కలిగి ఉన్న ఫీల్డ్‌లు మరియు పద్ధతులను చూడవచ్చు. మీరు అకస్మాత్తుగా ప్రోగ్రామ్‌కు ఇతర జంతు తరగతులను పరిచయం చేయవలసి ఉందని అనుకుందాం. Animalమీరు బహుశా సౌలభ్యం కోసం పేరెంట్ క్లాస్‌తో తరగతి వారసత్వ నిర్మాణాన్ని సృష్టించవచ్చు . ఇంతకుముందు, మేము వెటర్నరీ క్లినిక్‌కి ప్రాతినిధ్యం వహించే తరగతిని కూడా సృష్టించాము, దానికి మేము ఒక Animalవస్తువును (తల్లిదండ్రుల తరగతికి ఉదాహరణ) పాస్ చేయగలము మరియు ప్రోగ్రామ్ కుక్క లేదా పిల్లి అనే దాని ఆధారంగా జంతువుకు తగిన విధంగా చికిత్స చేసింది. ఇవి చాలా సులభమైన పనులు కానప్పటికీ, ప్రోగ్రామ్ కంపైల్ సమయంలో తరగతుల గురించి అవసరమైన మొత్తం సమాచారాన్ని నేర్చుకోగలదు. దీని ప్రకారం, మీరు Catవెటర్నరీ క్లినిక్ క్లాస్ యొక్క పద్ధతులకు ఒక వస్తువును పాస్ చేసినప్పుడుmain()పద్ధతి, ఇది కుక్క కాదు పిల్లి అని ప్రోగ్రామ్‌కు ఇప్పటికే తెలుసు. ఇప్పుడు మనం వేరే పనిని ఎదుర్కొంటున్నామని ఊహించుకుందాం. కోడ్ ఎనలైజర్‌ని రాయడం మా లక్ష్యం. CodeAnalyzerమేము ఒకే పద్ధతితో తరగతిని సృష్టించాలి : void analyzeObject(Object o). ఈ పద్ధతి తప్పక:
  • దానికి పంపబడిన వస్తువు యొక్క తరగతిని నిర్ణయించండి మరియు కన్సోల్‌లో తరగతి పేరును ప్రదర్శించండి;
  • ప్రైవేట్ వాటితో సహా ఉత్తీర్ణులైన తరగతిలోని అన్ని ఫీల్డ్‌ల పేర్లను నిర్ణయించండి మరియు వాటిని కన్సోల్‌లో ప్రదర్శించండి;
  • ప్రైవేట్ వాటితో సహా ఉత్తీర్ణత పొందిన తరగతి యొక్క అన్ని పద్ధతుల పేర్లను నిర్ణయించండి మరియు వాటిని కన్సోల్‌లో ప్రదర్శించండి.
ఇది ఇలా కనిపిస్తుంది:

public class CodeAnalyzer {

   public static void analyzeClass(Object o) {
      
       // Print the name of the class of object o
       // Print the names of all variables of this class
       // Print the names of all methods of this class
   }
  
}
మీరు ఇంతకు ముందు పరిష్కరించిన ఇతర పనుల నుండి ఈ పని ఎలా భిన్నంగా ఉందో ఇప్పుడు మనం స్పష్టంగా చూడవచ్చు. మా ప్రస్తుత లక్ష్యంతో, కష్టం ఏమిటంటే, మనకు లేదా ప్రోగ్రామ్‌కు ఖచ్చితంగా ఏమి పంపబడుతుందో తెలియదుanalyzeClass()పద్ధతి. మీరు అటువంటి ప్రోగ్రామ్‌ను వ్రాస్తే, ఇతర ప్రోగ్రామర్లు దానిని ఉపయోగించడం ప్రారంభిస్తారు మరియు వారు ఈ పద్ధతికి ఏదైనా పాస్ చేయవచ్చు — ఏదైనా ప్రామాణిక జావా తరగతి లేదా వారు వ్రాసే ఏదైనా ఇతర తరగతి. ఉత్తీర్ణత సాధించిన తరగతి ఎన్ని వేరియబుల్స్ మరియు పద్ధతులను కలిగి ఉండవచ్చు. మరో మాటలో చెప్పాలంటే, మేము (మరియు మా ప్రోగ్రామ్) ఏ తరగతులతో పని చేస్తున్నామో మాకు తెలియదు. అయితే, మేము ఈ పనిని పూర్తి చేయాలి. మరియు ఇక్కడే ప్రామాణిక జావా రిఫ్లెక్షన్ API మా సహాయానికి వస్తుంది. రిఫ్లెక్షన్ API అనేది భాష యొక్క శక్తివంతమైన సాధనం. ఒరాకిల్ యొక్క అధికారిక డాక్యుమెంటేషన్ ఈ యంత్రాంగాన్ని వారు ఏమి చేస్తున్నారో తెలిసిన అనుభవజ్ఞులైన ప్రోగ్రామర్లు మాత్రమే ఉపయోగించాలని సిఫార్సు చేస్తున్నారు. మేము ముందస్తుగా ఈ విధమైన హెచ్చరికను ఎందుకు ఇస్తున్నామో మీకు త్వరలో అర్థమవుతుంది :) రిఫ్లెక్షన్ APIతో మీరు చేయగలిగే పనుల జాబితా ఇక్కడ ఉంది:
  1. వస్తువు యొక్క తరగతిని గుర్తించండి/నిశ్చయించండి.
  2. క్లాస్ మాడిఫైయర్‌లు, ఫీల్డ్‌లు, పద్ధతులు, స్థిరాంకాలు, కన్‌స్ట్రక్టర్‌లు మరియు సూపర్‌క్లాస్‌ల గురించి సమాచారాన్ని పొందండి.
  3. అమలు చేయబడిన ఇంటర్‌ఫేస్(లు)కి చెందిన పద్ధతులు ఏవి కనుగొనండి.
  4. ప్రోగ్రామ్ అమలు చేయబడే వరకు తరగతి పేరు తెలియని తరగతి యొక్క ఉదాహరణను సృష్టించండి.
  5. పేరు ద్వారా ఉదాహరణ ఫీల్డ్ విలువను పొందండి మరియు సెట్ చేయండి.
  6. ఒక ఉదాహరణ పద్ధతిని పేరు ద్వారా కాల్ చేయండి.
ఆకట్టుకునే జాబితా, అవునా? :) గమనిక:మేము మా కోడ్ ఎనలైజర్‌కి పంపే వస్తువు రకంతో సంబంధం లేకుండా ప్రతిబింబ మెకానిజం "ఫ్లైలో" ఇవన్నీ చేయగలదు! కొన్ని ఉదాహరణలను చూడటం ద్వారా రిఫ్లెక్షన్ API సామర్థ్యాలను అన్వేషిద్దాం.

వస్తువు యొక్క తరగతిని ఎలా గుర్తించాలి/నిర్ణయించాలి

బేసిక్స్‌తో ప్రారంభిద్దాం. జావా రిఫ్లెక్షన్ ఇంజిన్‌కి ప్రవేశ స్థానం క్లాస్ Class. అవును, ఇది నిజంగా హాస్యాస్పదంగా కనిపిస్తుంది, కానీ ప్రతిబింబం అంటే అదే :) Classతరగతిని ఉపయోగించి, మా పద్ధతికి ఆమోదించబడిన ఏదైనా వస్తువు యొక్క తరగతిని మేము ముందుగా నిర్ణయిస్తాము. దీన్ని చేయడానికి ప్రయత్నిద్దాం:

import learn.codegym.Cat;

public class CodeAnalyzer {

   public static void analyzeClass(Object o) {
       Class clazz = o.getClass();
       System.out.println(clazz);
   }

   public static void main(String[] args) {

       analyzeClass(new Cat("Fluffy", 6));
   }
}
కన్సోల్ అవుట్‌పుట్:

class learn.codegym.Cat
రెండు విషయాలపై శ్రద్ధ వహించండి. మొదట, మేము ఉద్దేశపూర్వకంగా Catతరగతిని ప్రత్యేక ప్యాకేజీలో ఉంచాము learn.codegym. getClass()ఇప్పుడు మీరు ఈ పద్ధతి తరగతి యొక్క పూర్తి పేరును తిరిగి పొందడాన్ని చూడవచ్చు . రెండవది, మేము మా వేరియబుల్ అని పేరు పెట్టాము clazz. అది కొంచెం వింతగా కనిపిస్తుంది. దీనిని "తరగతి" అని పిలవడం అర్ధమే, కానీ "తరగతి" అనేది జావాలో రిజర్వ్ చేయబడిన పదం. కంపైలర్ వేరియబుల్స్‌ని అలా పిలవడానికి అనుమతించదు. మేము దానిని ఎలాగైనా చుట్టుముట్టవలసి వచ్చింది :) ప్రారంభంలో చెడు కాదు! ఆ సామర్థ్యాల జాబితాలో మనకు ఇంకా ఏమి ఉన్నాయి?

క్లాస్ మాడిఫైయర్‌లు, ఫీల్డ్‌లు, పద్ధతులు, స్థిరాంకాలు, కన్‌స్ట్రక్టర్‌లు మరియు సూపర్‌క్లాస్‌ల గురించి సమాచారాన్ని ఎలా పొందాలి.

ఇప్పుడు విషయాలు మరింత ఆసక్తికరంగా మారుతున్నాయి! ప్రస్తుత తరగతిలో, మాకు స్థిరాంకాలు లేదా పేరెంట్ క్లాస్ ఏవీ లేవు. పూర్తి చిత్రాన్ని రూపొందించడానికి వాటిని జోడిద్దాం. సరళమైన Animalపేరెంట్ క్లాస్‌ని సృష్టించండి:

package learn.codegym;
public class Animal {

   private String name;
   private int age;
}
మరియు మేము మా Catతరగతిని వారసత్వంగా పొందుతాము Animalమరియు ఒక స్థిరాంకాన్ని జోడిస్తాము:

package learn.codegym;

public class Cat extends Animal {

   private static final String ANIMAL_FAMILY = "Feline family";

   private String name;
   private int age;

   // ...the rest of the class
}
ఇప్పుడు మనకు పూర్తి చిత్రం ఉంది! ప్రతిబింబం సామర్థ్యం ఏమిటో చూద్దాం :)

import learn.codegym.Cat;

import java.util.Arrays;

public class CodeAnalyzer {

   public static void analyzeClass(Object o) {
       Class clazz = o.getClass();
       System.out.println("Class name: " + clazz);
       System.out.println("Class fields: " + Arrays.toString(clazz.getDeclaredFields()));
       System.out.println("Parent class: " + clazz.getSuperclass());
       System.out.println("Class methods: " + Arrays.toString(clazz.getDeclaredMethods()));
       System.out.println("Class constructors: " + Arrays.toString(clazz.getConstructors()));
   }

   public static void main(String[] args) {

       analyzeClass(new Cat("Fluffy", 6));
   }
}
కన్సోల్‌లో మనం చూసేది ఇక్కడ ఉంది:

Class name:  class learn.codegym.Cat 
Class fields: [private static final java.lang.String learn.codegym.Cat.ANIMAL_FAMILY, private java.lang.String learn.codegym.Cat.name, private int learn.codegym.Cat.age] 
Parent class: class learn.codegym.Animal 
Class methods: [public java.lang.String learn.codegym.Cat.getName(), public void learn.codegym.Cat.setName(java.lang.String), public void learn.codegym.Cat.sayMeow(), public void learn.codegym.Cat.setAge(int), public void learn.codegym.Cat.jump(), public int learn.codegym.Cat.getAge()] 
Class constructors: [public learn.codegym.Cat(java.lang.String, int)]
మేము పొందగలిగిన వివరణాత్మక తరగతి సమాచారాన్ని చూడండి! మరియు పబ్లిక్ సమాచారం మాత్రమే కాదు, ప్రైవేట్ సమాచారం కూడా! గమనిక: privateవేరియబుల్స్ కూడా జాబితాలో ప్రదర్శించబడతాయి. తరగతి యొక్క మా "విశ్లేషణ" తప్పనిసరిగా పూర్తి అయినట్లుగా పరిగణించబడుతుంది: analyzeObject()మేము చేయగలిగిన ప్రతిదాన్ని తెలుసుకోవడానికి మేము ఈ పద్ధతిని ఉపయోగిస్తున్నాము. కానీ ప్రతిబింబంతో మనం చేయగలిగినదంతా ఇది కాదు. మేము సాధారణ పరిశీలనకే పరిమితం కాలేదు — మేము చర్య తీసుకోవడానికి ముందుకు వెళ్తాము! :)

ప్రోగ్రామ్‌ని అమలు చేసే వరకు తరగతి పేరు తెలియని తరగతి యొక్క ఉదాహరణను ఎలా సృష్టించాలి.

డిఫాల్ట్ కన్స్ట్రక్టర్‌తో ప్రారంభిద్దాం. మా Catతరగతికి ఇంకా ఒకటి లేదు, కాబట్టి దీన్ని జోడిద్దాం:

public Cat() {
  
}
Catప్రతిబింబం (పద్ధతి) ఉపయోగించి వస్తువును సృష్టించడానికి ఇక్కడ కోడ్ ఉంది createCat():

import learn.codegym.Cat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

   public static Cat createCat() throws IOException, IllegalAccessException, InstantiationException, ClassNotFoundException {

       BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
       String className = reader.readLine();

       Class clazz = Class.forName(className);
       Cat cat = (Cat) clazz.newInstance();

       return cat;
   }

public static Object createObject() throws Exception {

   BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
   String className = reader.readLine();

   Class clazz = Class.forName(className);
   Object result = clazz.newInstance();

   return result;
}

   public static void main(String[] args) throws IOException, IllegalAccessException, ClassNotFoundException, InstantiationException {
       System.out.println(createCat());
   }
}
కన్సోల్ ఇన్‌పుట్:

learn.codegym.Cat
కన్సోల్ అవుట్‌పుట్:

Cat{name='null', age=0}
ఇది లోపం కాదు: విలువలు nameమరియు ageకన్సోల్‌లో ప్రదర్శించబడతాయి ఎందుకంటే మేము వాటిని toString()క్లాస్ పద్ధతిలో అవుట్‌పుట్ చేయడానికి కోడ్‌ని వ్రాసాము Cat. ఇక్కడ మేము కన్సోల్ నుండి సృష్టించే వస్తువు యొక్క తరగతి పేరును చదువుతాము. ప్రోగ్రామ్ ఆబ్జెక్ట్ సృష్టించబడే తరగతి పేరును గుర్తిస్తుంది. ప్రతిబింబానికి ఉదాహరణలు - 3సంక్షిప్తత కొరకు, మేము సరైన మినహాయింపు నిర్వహణ కోడ్‌ను వదిలివేసాము, ఇది ఉదాహరణ కంటే ఎక్కువ స్థలాన్ని తీసుకుంటుంది. నిజమైన ప్రోగ్రామ్‌లో, వాస్తవానికి, మీరు తప్పుగా నమోదు చేయబడిన పేర్లతో కూడిన పరిస్థితులను నిర్వహించాలి. డిఫాల్ట్ కన్స్ట్రక్టర్ చాలా సులభం, కాబట్టి మీరు చూడగలిగినట్లుగా, తరగతి యొక్క ఉదాహరణను సృష్టించడానికి దీన్ని ఉపయోగించడం సులభం :) పద్ధతిని newInstance()ఉపయోగించడం , మేము ఈ తరగతి యొక్క కొత్త వస్తువును సృష్టిస్తాము. అయితే అది వేరే విషయంCatకన్స్ట్రక్టర్ వాదనలను ఇన్‌పుట్‌గా తీసుకుంటాడు. క్లాస్ డిఫాల్ట్ కన్‌స్ట్రక్టర్‌ని తీసివేసి, మన కోడ్‌ని మళ్లీ అమలు చేయడానికి ప్రయత్నిద్దాం.

null
java.lang.InstantiationException: learn.codegym.Cat 
at java.lang.Class.newInstance(Class.java:427)
ఎక్కడో తేడ జరిగింది! మేము డిఫాల్ట్ కన్‌స్ట్రక్టర్‌ని ఉపయోగించి ఆబ్జెక్ట్‌ని సృష్టించే పద్ధతిని పిలిచినందున మాకు లోపం వచ్చింది. కానీ ఇప్పుడు మన దగ్గర అలాంటి కన్స్ట్రక్టర్ లేదు. కాబట్టి newInstance()పద్ధతి అమలులో ఉన్నప్పుడు, ప్రతిబింబ విధానం రెండు పారామితులతో మా పాత కన్స్ట్రక్టర్‌ను ఉపయోగిస్తుంది:

public Cat(String name, int age) {
   this.name = name;
   this.age = age;
}
కానీ మేము వాటి గురించి పూర్తిగా మరచిపోయినట్లుగా, మేము పారామితులతో ఏమీ చేయలేదు! కన్స్ట్రక్టర్‌కు ఆర్గ్యుమెంట్‌లను పంపడానికి ప్రతిబింబాన్ని ఉపయోగించడం కొంచెం "సృజనాత్మకత" అవసరం:

import learn.codegym.Cat;

import java.lang.reflect.InvocationTargetException;

public class Main {

   public static Cat createCat()  {

       Class clazz = null;
       Cat cat = null;

       try {
           clazz = Class.forName("learn.codegym.Cat");
           Class[] catClassParams = {String.class, int.class};
           cat = (Cat) clazz.getConstructor(catClassParams).newInstance("Fluffy", 6);
       } catch (ClassNotFoundException e) {
           e.printStackTrace();
       } catch (InstantiationException e) {
           e.printStackTrace();
       } catch (IllegalAccessException e) {
           e.printStackTrace();
       } catch (NoSuchMethodException e) {
           e.printStackTrace();
       } catch (InvocationTargetException e) {
           e.printStackTrace();
       }

       return cat;
   }

   public static void main(String[] args) {
       System.out.println(createCat());
   }
}
కన్సోల్ అవుట్‌పుట్:

Cat{name='Fluffy', age=6}
మా ప్రోగ్రామ్‌లో ఏమి జరుగుతుందో నిశితంగా పరిశీలిద్దాం. మేము వస్తువుల శ్రేణిని సృష్టించాము Class.

Class[] catClassParams = {String.class, int.class};
అవి మా కన్స్ట్రక్టర్ యొక్క పారామితులకు అనుగుణంగా ఉంటాయి (ఇది కేవలం Stringమరియు intపారామితులను కలిగి ఉంటుంది). మేము వాటిని పద్ధతికి పాస్ చేస్తాము clazz.getConstructor()మరియు కావలసిన కన్స్ట్రక్టర్‌కు ప్రాప్యతను పొందుతాము. ఆ తర్వాత, మేము చేయవలసిందల్లా newInstance()అవసరమైన వాదనలతో పద్ధతిని కాల్ చేయండి మరియు వస్తువును కావలసిన రకానికి స్పష్టంగా ప్రసారం చేయడం మర్చిపోవద్దు: Cat.

cat = (Cat) clazz.getConstructor(catClassParams).newInstance("Fluffy", 6);
ఇప్పుడు మా వస్తువు విజయవంతంగా సృష్టించబడింది! కన్సోల్ అవుట్‌పుట్:

Cat{name='Fluffy', age=6}
కుడివైపు కదులుతూ :)

ఒక ఉదాహరణ ఫీల్డ్ యొక్క విలువను పేరు ద్వారా పొందడం మరియు సెట్ చేయడం ఎలా.

మీరు మరొక ప్రోగ్రామర్ వ్రాసిన తరగతిని ఉపయోగిస్తున్నారని ఊహించండి. అదనంగా, మీరు దీన్ని సవరించగల సామర్థ్యాన్ని కలిగి లేరు. ఉదాహరణకు, JARలో ప్యాక్ చేయబడిన రెడీమేడ్ క్లాస్ లైబ్రరీ. మీరు తరగతుల కోడ్‌ను చదవగలరు, కానీ మీరు దానిని మార్చలేరు. ఈ లైబ్రరీలోని క్లాస్‌లలో ఒకదాన్ని సృష్టించిన ప్రోగ్రామర్ (అది మన పాత Catతరగతిగా ఉండనివ్వండి), డిజైన్‌ను ఖరారు చేసే ముందు రాత్రి తగినంత నిద్రపోవడంలో విఫలమై, ఫీల్డ్‌కు గెట్టర్ మరియు సెట్టర్‌ను తీసివేసినట్లు అనుకుందాం age. ఇప్పుడు ఈ క్లాస్ మీ ముందుకు వచ్చింది. ఇది మీ అన్ని అవసరాలను తీరుస్తుంది, ఎందుకంటే మీకు Catమీ ప్రోగ్రామ్‌లో వస్తువులు మాత్రమే అవసరం. కానీ మీరు వారికి ఫీల్డ్ కలిగి ఉండాలి age! ఇది ఒక సమస్య: మేము ఫీల్డ్‌ని చేరుకోలేము, ఎందుకంటే అది కలిగి ఉందిprivateమాడిఫైయర్, మరియు గెట్టర్ మరియు సెట్టర్‌లను క్లాస్‌ని సృష్టించిన నిద్ర లేమి డెవలపర్ తొలగించారు :/ ఈ పరిస్థితిలో ప్రతిబింబం మాకు సహాయపడుతుంది! మేము తరగతి కోసం కోడ్‌కి ప్రాప్యతను కలిగి ఉన్నాము Cat, కాబట్టి మేము కనీసం ఏ ఫీల్డ్‌లను కలిగి ఉన్నాయో మరియు వాటిని ఏమని పిలుస్తామో కనుగొనవచ్చు. ఈ సమాచారంతో మేము మా సమస్యను పరిష్కరించగలము:

import learn.codegym.Cat;

import java.lang.reflect.Field;

public class Main {

   public static Cat createCat()  {

       Class clazz = null;
       Cat cat = null;
       try {
           clazz = Class.forName("learn.codegym.Cat");
           cat = (Cat) clazz.newInstance();

           // We got lucky with the name field, since it has a setter
           cat.setName("Fluffy");

           Field age = clazz.getDeclaredField("age");
          
           age.setAccessible(true);

           age.set(cat, 6);

       } catch (IllegalAccessException e) {
           e.printStackTrace();
       } catch (InstantiationException e) {
           e.printStackTrace();
       } catch (ClassNotFoundException e) {
           e.printStackTrace();
       } catch (NoSuchFieldException e) {
           e.printStackTrace();
       }

       return cat;
   }

   public static void main(String[] args) {
       System.out.println(createCat());
   }
}
వ్యాఖ్యలలో పేర్కొన్నట్లుగా, nameక్లాస్ డెవలపర్‌లు సెట్టర్‌ను అందించినందున ఫీల్డ్‌తో ప్రతిదీ సూటిగా ఉంటుంది. డిఫాల్ట్ కన్స్ట్రక్టర్ల నుండి వస్తువులను ఎలా సృష్టించాలో మీకు ఇప్పటికే తెలుసు: newInstance()దీని కోసం మా వద్ద ఉంది. కానీ మేము రెండవ ఫీల్డ్‌తో కొన్ని టింకరింగ్ చేయవలసి ఉంటుంది. ఇక్కడ ఏమి జరుగుతుందో తెలుసుకుందాం :)

Field age = clazz.getDeclaredField("age");
ఇక్కడ, మా Class clazzవస్తువును ఉపయోగించి, మేము పద్ధతి ageద్వారా ఫీల్డ్‌ని యాక్సెస్ చేస్తాము getDeclaredField(). ఇది వయస్సు ఫీల్డ్‌ను వస్తువుగా పొందేలా చేస్తుంది Field age. కానీ ఇది సరిపోదు, ఎందుకంటే మనం privateఫీల్డ్‌లకు విలువలను కేటాయించలేము. దీన్ని చేయడానికి, మేము ఈ పద్ధతిని ఉపయోగించి ఫీల్డ్‌ని యాక్సెస్ చేయగలగాలి setAccessible():

age.setAccessible(true);
మేము దీన్ని ఫీల్డ్‌కి చేసిన తర్వాత, మనం విలువను కేటాయించవచ్చు:

age.set(cat, 6);
మీరు చూడగలిగినట్లుగా, మా Field ageఆబ్జెక్ట్‌లో ఒక రకమైన ఇన్‌సైడ్-అవుట్ సెట్టర్ ఉంది, దానికి మనం పూర్ణాంక విలువను మరియు ఫీల్డ్ కేటాయించాల్సిన వస్తువును పాస్ చేస్తాము. మేము మా main()పద్ధతిని అమలు చేస్తాము మరియు చూడండి:

Cat{name='Fluffy', age=6}
అద్భుతమైన! మేము చేసాము! :) మనం ఇంకా ఏమి చేయగలమో చూద్దాం...

ఉదాహరణ పద్ధతిని పేరుతో ఎలా పిలవాలి.

మునుపటి ఉదాహరణలో పరిస్థితిని కొద్దిగా మారుద్దాం. Catక్లాస్ డెవలపర్ గెటర్స్ మరియు సెటైర్‌లతో తప్పు చేయలేదని చెప్పండి . ఆ విషయంలో అంతా ఓకే. ఇప్పుడు సమస్య భిన్నంగా ఉంది: మనకు ఖచ్చితంగా అవసరమైన ఒక పద్ధతి ఉంది, కానీ డెవలపర్ దానిని ప్రైవేట్‌గా చేసారు:

private void sayMeow() {

   System.out.println("Meow!");
}
అంటే మనం మన ప్రోగ్రామ్‌లో ఆబ్జెక్ట్‌లను క్రియేట్ చేస్తే , వాటిపై ఉన్న మెథడ్‌ని Catకాల్ చేయలేరు . sayMeow()మియావ్ చేయని పిల్లులు మనకు ఉంటాయా? ఇది విచిత్రం :/ మేము దీన్ని ఎలా పరిష్కరిస్తాము? మరోసారి, ప్రతిబింబం API మాకు సహాయం చేస్తుంది! మనకు అవసరమైన పద్ధతి పేరు మనకు తెలుసు. మిగతావన్నీ సాంకేతికత:

import learn.codegym.Cat;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main {

   public static void invokeSayMeowMethod()  {

       Class clazz = null;
       Cat cat = null;
       try {

           cat = new Cat("Fluffy", 6);
          
           clazz = Class.forName(Cat.class.getName());
          
           Method sayMeow = clazz.getDeclaredMethod("sayMeow");
          
           sayMeow.setAccessible(true);
          
           sayMeow.invoke(cat);
          
       } catch (ClassNotFoundException e) {
           e.printStackTrace();
       } catch (NoSuchMethodException e) {
           e.printStackTrace();
       } catch (IllegalAccessException e) {
           e.printStackTrace();
       } catch (InvocationTargetException e) {
           e.printStackTrace();
       }
   }

   public static void main(String[] args) {
       invokeSayMeowMethod();
   }
}
ప్రైవేట్ ఫీల్డ్‌ని యాక్సెస్ చేసేటప్పుడు మనం చేసిన పనినే ఇక్కడ కూడా చేస్తాము. మొదట, మనకు అవసరమైన పద్ధతిని మేము పొందుతాము. ఇది ఒక Methodవస్తువులో సంగ్రహించబడింది:

Method sayMeow = clazz.getDeclaredMethod("sayMeow");
getDeclaredMethod()పద్ధతి ప్రైవేట్ పద్ధతులకు వెళ్లేలా చేస్తుంది. తరువాత, మేము కాల్ చేయదగిన పద్ధతిని చేస్తాము:

sayMeow.setAccessible(true);
చివరకు, మేము కావలసిన వస్తువుపై పద్ధతిని పిలుస్తాము:

sayMeow.invoke(cat);
ఇక్కడ, మా పద్ధతి కాల్ "కాల్‌బ్యాక్" లాగా కనిపిస్తుంది: మేము ఒక వస్తువును కావలసిన పద్ధతి ( cat.sayMeow()) వద్ద సూచించడానికి వ్యవధిని ఉపయోగించడం అలవాటు చేసుకున్నాము, కానీ ప్రతిబింబంతో పని చేస్తున్నప్పుడు, మనం కాల్ చేయాలనుకుంటున్న ఆబ్జెక్ట్‌ని పద్ధతికి పంపుతాము ఆ పద్ధతి. మా కన్సోల్‌లో ఏముంది?

Meow!
ప్రతిదీ పని చేసింది! :) ఇప్పుడు మీరు జావా యొక్క ప్రతిబింబ మెకానిజం మనకు అందించే విస్తారమైన అవకాశాలను చూడవచ్చు. కష్టమైన మరియు ఊహించని పరిస్థితుల్లో (క్లోజ్డ్ లైబ్రరీ నుండి క్లాస్‌తో మా ఉదాహరణలు వంటివి), ఇది నిజంగా మాకు చాలా సహాయపడుతుంది. కానీ, ఏ గొప్ప శక్తితోనూ, అది గొప్ప బాధ్యతను తెస్తుంది. ప్రతిబింబం యొక్క ప్రతికూలతలు ఒరాకిల్ వెబ్‌సైట్‌లోని ప్రత్యేక విభాగంలో వివరించబడ్డాయి . మూడు ప్రధాన ప్రతికూలతలు ఉన్నాయి:
  1. పనితీరు అధ్వాన్నంగా ఉంది. ప్రతిబింబాన్ని ఉపయోగించడం అనే పద్ధతులు సాధారణ పద్ధతిలో పిలిచే పద్ధతుల కంటే అధ్వాన్నమైన పనితీరును కలిగి ఉంటాయి.

  2. భద్రతా పరిమితులు ఉన్నాయి. రిఫ్లెక్షన్ మెకానిజం రన్‌టైమ్‌లో ప్రోగ్రామ్ ప్రవర్తనను మార్చడానికి అనుమతిస్తుంది. కానీ మీ కార్యాలయంలో, నిజమైన ప్రాజెక్ట్‌లో పని చేస్తున్నప్పుడు, మీరు దీన్ని అనుమతించని పరిమితులను ఎదుర్కోవచ్చు.

  3. అంతర్గత సమాచారం బహిర్గతమయ్యే ప్రమాదం. ప్రతిబింబం అనేది ఎన్‌క్యాప్సులేషన్ సూత్రం యొక్క ప్రత్యక్ష ఉల్లంఘన అని అర్థం చేసుకోవడం చాలా ముఖ్యం: ఇది ప్రైవేట్ ఫీల్డ్‌లు, పద్ధతులు మొదలైనవాటిని యాక్సెస్ చేయడానికి అనుమతిస్తుంది. OOP సూత్రాల యొక్క ప్రత్యక్ష మరియు స్పష్టమైన ఉల్లంఘనను ఆశ్రయించాలని నేను చెప్పనవసరం లేదు. మీ నియంత్రణకు మించిన కారణాల వల్ల సమస్యను పరిష్కరించడానికి ఇతర మార్గాలు లేనప్పుడు అత్యంత తీవ్రమైన సందర్భాల్లో మాత్రమే.

ప్రతిబింబాన్ని తెలివిగా మరియు నివారించలేని సందర్భాల్లో మాత్రమే ఉపయోగించండి మరియు దాని లోపాల గురించి మర్చిపోకండి. దీంతో మా పాఠం ముగిసింది. ఇది చాలా పొడవుగా ఉంది, కానీ మీరు ఈ రోజు చాలా నేర్చుకున్నారు :)
వ్యాఖ్యలు
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION