JavaRush /Блоги Java /Random-TG /API Reflection. Мулоҳиза. Ҷониби торикии Java
Oleksandr Klymenko
Сатҳи
Харків

API Reflection. Мулоҳиза. Ҷониби торикии Java

Дар гурӯҳ нашр шудааст
Салом, Падаван ҷавон. Дар ин мақола ман ба шумо дар бораи Қуввае нақл мекунам, ки қудрати онро барномасозони java танҳо дар вазъияти ба назар ноумедкунанда истифода мебаранд. Ҳамин тавр, паҳлӯи торикии Java ин аст -Reflection API
API Reflection.  Мулоҳиза.  Ҷониби торикии Java - 1
Мулоҳиза дар Java бо истифода аз Java Reflection API анҷом дода мешавад. Ин инъикос чист? Таърифи кӯтоҳ ва дақиқ вуҷуд дорад, ки дар Интернет низ маъмул аст. Рефлексия (аз лотинии Reflexio - бозгашт) механизми омӯзиши маълумот дар бораи барнома ҳангоми иҷрои он мебошад. Мулоҳиза ба шумо имкон медиҳад, ки маълумотро дар бораи майдонҳо, усулҳо ва конструкторҳои синф тафтиш кунед. Худи механизми инъикос ба шумо имкон медиҳад, ки намудҳоеро коркард кунед, ки дар вақти тартибдиҳӣ гум мешаванд, вале ҳангоми иҷрои барнома пайдо мешаванд. Мулоҳиза ва мавҷудияти модели мантиқии мувофиқ барои гузориши хатогиҳо имкон медиҳад, ки рамзи дурусти динамикӣ эҷод карда шавад. Ба ибораи дигар, фаҳмидани он ки инъикос дар Java чӣ гуна кор мекунад, барои шумо як қатор имкониятҳои аҷибро мекушояд. Шумо метавонед айнан дарсҳо ва ҷузъҳои онҳоро ҳал кунед.
API Reflection.  Мулоҳиза.  Ҷониби торикии Java - 2
Дар ин ҷо як рӯйхати асосии он аст, ки инъикос чӣ имкон медиҳад:
  • Муайян кардани синфи an object;
  • Дар бораи тағирдиҳандаҳои синфҳо, майдонҳо, усулҳо, константаҳо, конструкторҳо ва суперсинфҳо маълумот гиред;
  • Бифаҳмед, ки кадом усулҳо ба интерфейс/интерфейсҳои амалӣ тааллуқ доранд;
  • Намунаи синфро эҷод кунед ва номи синф то иҷро шудани барнома номаълум аст;
  • Гирифтан ва муқаррар кардани арзиши майдони an object аз рӯи ном;
  • Усули an objectро бо ном даъват кунед.
Рефлексия тақрибан дар ҳама технологияҳои муосири Java истифода мешавад. Тасаввур кардан душвор аст, ки оё Java ҳамчун платформа метавонист бидуни мулоҳиза ба чунин қабули азим ноил шавад. Эҳтимол, ман натавонистам. Шумо бо идеяи умумии назариявии инъикос шинос шудаед, акнун биёед ба татбиқи амалии он сар кунем! Мо на ҳама усулҳои Reflection 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);
   }
}
Тавре ки мо мебинем, ин синфи маъмултарин аст. Конструктор бо параметрҳо бо ягон сабаб шарҳ дода мешавад, мо ба ин баъдтар бармегардем. Агар шумо ба мундариҷаи синф бодиққат назар андозед, шумо эҳтимол набудани getter'a for the name. Худи майдон nameбо тағирдиҳандаи дастрасӣ ишора шудааст private; мо наметавонем ба он берун аз худи синф дастрасӣ пайдо кунем; =>мо арзиши онро гирифта наметавонем. "Пас мушкил дар чист? — мегуед. " getterТағйирдиҳандаи дастрасӣ илова кунед ё тағир диҳед." Ва шумо дуруст мегӯед, аммо чӣ мешавад, агар MyClassон дар китобхонаи тартибдодашудаи aar ё дар дигар модули пӯшида бидуни дастрасии таҳрир бошад ва дар амал ин хеле зуд-зуд рух медиҳад. Ва баъзе барномасозони беэътино танҳо навиштанро фаромӯш кардаанд getter. Вақти он расидааст, ки дар бораи инъикос ба ёд оред! Биёед кӯшиш кунем, ки ба privateмайдони nameсинф бирасем 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
}
Биёед бифаҳмем, ки ҳоло дар ин ҷо чӣ рӯй дод. Дар java синфи олиҷаноб вуҷуд дорад Class. Он синфҳо ва интерфейсҳоро дар барномаи иҷрошавандаи Java муаррифӣ мекунад. Мо ба робитаи байни Classва ClassLoader. ин мавзӯи мақола нест. Минбаъд, барои ба даст овардани майдонҳои ин синф, шумо бояд методро даъват кунед getFields(), ин усул ҳамаи майдонҳои мавҷудаи синфро ба мо бармегардонад. Ин барои мо мувофиқ нест, зеро майдони мо аст private, бинобар ин мо усули ро истифода мебарем.Ин getDeclaredFields()усул инчунин массиви майдонҳои синфро бармегардонад, аммо ҳоло ҳам privateва ҳам protected. Дар вазъияти мо, мо номи соҳаеро медонем, ки ба мо таваҷҷӯҳ дорад ва мо метавонем усулро истифода барем getDeclaredField(String), ки Stringноми майдони дилхоҳ дар куҷост. Шарҳ: getFields()ва getDeclaredFields()майдонҳои синфи волидайнро барнагардонед! Аҷоиб, мо an objectеро гирифтем Field , ки бо истиноди name. Зеро майдон набуд публичным(оммавӣ), барои кор бо он дастрасӣ додан лозим аст. Усул setAccessible(true)ба мо имкон медихад, ки корро давом дихем. Холо киштзор nameкомилан дар ихтиёри мост! Шумо метавонед арзиши онро тавассути занг задан get(Object)ба an object Field, ки Objectнамунаи синфи мост, пайдо кунед MyClass. Мо онро мепартоем Stringва онро ба тағирёбандаи худ таъин мекунем name. Агар мо ногаҳон 'a надошта бошем setter, мо метавонем ин усулро барои таъин кардани арзиши нав барои майдони ном истифода барем set:
field.set(myClass, (String) "new value");
Табрик мекунем! Шумо наваHow механизми асосии инъикосро азхуд кардаед ва тавонистаед ба privateмайдон дастрасӣ пайдо кунед! Ба блок try/catchва намудҳои истисноҳои коркардшуда диққат диҳед. Худи IDE ҳузури ҳатмии онҳоро нишон медиҳад, аммо номи онҳо равшан мекунад, ки чаро онҳо дар ин ҷо ҳастанд. Ба пеш! Тавре ки шумо пайхас кардаед, дар мо MyClassаллакай усули намоиши маълумот дар бораи маълумоти синф мавҷуд аст:
private void printData(){
       System.out.println(number + name);
   }
Аммо ин барномасоз дар ин ҷо низ мерос гузоштааст. Ин усул дар зери тағирдиҳандаи дастрасӣ аст privateва мо бояд ҳар дафъа рамзи баромадро худамон нависем. Ин тартиб нест, инъикоси мо куҷост?... Биёед вазифаи зеринро нависед:
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();
   }
}
Дар ин ҷо тартиб тақрибан ба гирифтани майдон монанд аст - мо усули дилхоҳро бо ном мегирем ва ба он дастрасӣ медиҳем. Ва барои даъват кардани an objectе, ки Methodмо истифода мебарем invoke(Оbject, Args), дар он ҷо Оbjectниз намунаи синф аст MyClass. Args- далелҳои методӣ - мо ҳеҷ чиз надоранд. Ҳоло мо функсияро барои намоиш додани маълумот истифода мебарем printData:
public static void main(String[] args) {
   MyClass myClass = new MyClass();
   int number = myClass.getNumber();
   String name = null; //?
   printData(myClass); // outout 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
}
Хуб, ҳоло мо ба усули хусусии синф дастрасӣ дорем. Аммо чӣ мешавад, агар усул то ҳол далелҳо дошта бошад ва чаро конструктори шарҳ додашуда вуҷуд дорад? Ҳама чиз вақти худро дорад. Аз таърифи аввал маълум аст, ки инъикос ба шумо имкон медиҳад, ки мисолҳои синфро дар реҷа эҷод кунед runtime(ҳангоми кор кардани барнома)! Мо метавонем an objectи синфро бо номи пурраи он синф созем. Номи синфи пурраи тахассусӣ номи синф аст, бо назардошти роҳ ба он дар package.
API Reflection.  Мулоҳиза.  Ҷониби торикии Java - 3
Дар иерархияи ман packageноми пурраи 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
}
Вақте ки барномаи java оғоз меёбад, на ҳама синфҳо ба JVM бор карда мешаванд. Агар рамзи шумо ба синф ишора накунад MyClass, шахсе, ки барои боркунии синфҳо ба JVM масъул аст, яъне ClassLoader, ҳеҷ гоҳ онро дар он ҷо бор намекунад. Аз ин рӯ, мо бояд ClassLoaderонро маҷбур кунем, ки тавсифи синфи моро дар шакли тағирёбандаи навъи Class. Барои ин вазифа методе мавҷуд аст forName(String), ки дар куҷо Stringноми синфе, ки тавсифи онро талаб мекунем. Пас аз гирифтани Сlass, занги методӣ newInstance()бармегардад Object, ки мувофиқи ҳамон тавсиф сохта мешавад. Барои ба синфи мо овардани ин an 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Барои усулҳои занг низ ҳамин тавр мешавад . Саволе ба миён меояд: даъвати инъикоскунандаи конструкторҳо дар куҷо муфид буда метавонад? Технологияҳои муосири java, тавре ки дар аввал гуфта шуд, бе API Reflection кор карда наметавонанд. Масалан, DI (Dependency Injection), ки дар он эзоҳҳо дар якҷоягӣ бо инъикоси усулҳо ва конструкторҳо китобхонаи Dagger-ро ташкил медиҳанд, ки дар таҳияи Android маъмул аст. Пас аз хондани ин мақола, шумо метавонед худро дар механизмҳои Reflection API мунаввар ҳисоб кунед. Бесабаб нест, ки инъикосро тарафи торикии Java меноманд. Он парадигмаи OOP-ро комилан вайрон мекунад. Дар Java, инкапсуляция барои пинҳон кардан ва маҳдуд кардани дастрасии баъзе ҷузъҳои барнома ба дигарон хидмат мекунад. Бо истифода аз тағирдиҳандаи хусусӣ мо дар назар дорем, ки дастрасӣ ба ин майдон танҳо дар дохor синфе хоҳад буд, ки ин майдон вуҷуд дорад ва дар асоси ин мо меъмории минбаъдаи барномаро месозем. Дар ин мақола мо дидем, ки чӣ гуна шумо метавонед инъикосро барои ба ҳама ҷо расидан истифода баред. Намунаи хуб дар шакли ҳалли меъморӣ намунаи тарроҳии тавлидкунанда мебошад - Singleton. Идеяи асосии он аз он иборат аст, ки дар давоми тамоми кори барнома синфе, ки ин қолабро амалӣ мекунад, бояд танҳо як нусха дошта бошад. Ин бо гузоштани тағирдиҳандаи дастрасии пешфарз ба хусусӣ барои созанда анҷом дода мешавад. Ва хеле бад мешавад, агар ягон барномасоз бо инъикоси худ чунин синфҳоро эҷод кунад. Воқеан, як саволи хеле ҷолибе ҳаст, ки ба наздикӣ аз кормандам шунидам: оё синфе, ки шаблонро амалӣ мекунад, Singletonворисон дошта метавонад? Оё мумкин аст, ки ҳатто инъикос дар ин ҳолат беқувват бошад? Фикру мулоҳизаҳои худро дар бораи мақола ва ҷавоб дар шарҳҳо нависед ва инчунин саволҳои худро диҳед! Қувваи воқеии Reflection API дар якҷоягӣ бо Runtime Annotations меояд, ки мо эҳтимол дар мақолаи оянда дар бораи паҳлӯҳои торикии Java сӯҳбат хоҳем кард. Ба диққататон ташаккур!
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION