Салом, Падаван ҷавон. Дар ин мақола ман ба шумо дар бораи Қуввае нақл мекунам, ки қудрати онро барномасозони java танҳо дар вазъияти ба назар ноумедкунанда истифода мебаранд. Ҳамин тавр, паҳлӯи торикии Java ин аст -
Мулоҳиза дар Java бо истифода аз Java Reflection API анҷом дода мешавад. Ин инъикос чист? Таърифи кӯтоҳ ва дақиқ вуҷуд дорад, ки дар Интернет низ маъмул аст. Рефлексия (аз лотинии Reflexio - бозгашт) механизми омӯзиши маълумот дар бораи барнома ҳангоми иҷрои он мебошад. Мулоҳиза ба шумо имкон медиҳад, ки маълумотро дар бораи майдонҳо, усулҳо ва конструкторҳои синф тафтиш кунед. Худи механизми инъикос ба шумо имкон медиҳад, ки намудҳоеро коркард кунед, ки дар вақти тартибдиҳӣ гум мешаванд, вале ҳангоми иҷрои барнома пайдо мешаванд. Мулоҳиза ва мавҷудияти модели мантиқии мувофиқ барои гузориши хатогиҳо имкон медиҳад, ки рамзи дурусти динамикӣ эҷод карда шавад. Ба ибораи дигар, фаҳмидани он ки инъикос дар Java чӣ гуна кор мекунад, барои шумо як қатор имкониятҳои аҷибро мекушояд. Шумо метавонед айнан дарсҳо ва ҷузъҳои онҳоро ҳал кунед.
Дар ин ҷо як рӯйхати асосии он аст, ки инъикос чӣ имкон медиҳад:
Дар иерархияи ман
Reflection API
- Муайян кардани синфи an object;
- Дар бораи тағирдиҳандаҳои синфҳо, майдонҳо, усулҳо, константаҳо, конструкторҳо ва суперсинфҳо маълумот гиред;
- Бифаҳмед, ки кадом усулҳо ба интерфейс/интерфейсҳои амалӣ тааллуқ доранд;
- Намунаи синфро эҷод кунед ва номи синф то иҷро шудани барнома номаълум аст;
- Гирифтан ва муқаррар кардани арзиши майдони an object аз рӯи ном;
- Усули an objectро бо ном даъват кунед.
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
.
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 сӯҳбат хоҳем кард. Ба диққататон ташаккур!
GO TO FULL VERSION