Class.newInstance() orqali obyekt yaratish namunasi
O'ylab ko'r: sen oldinda turgan vazifa - refleksiya orqali obyekt yaratish kerak. Boshlasakmi?
Biz olmoqchi bo'lgan boshlang'ich klassdan boshlaymiz:
public class Employee {
private String name;
private String surname;
private int age;
{
age = -1;
name = "Ivan";
surname = "Ivanov";
}
public Employee(String name, String surname, int age) {
this.name = name;
this.surname = surname;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", surname='" + surname + '\'' +
", age=" + age +
'}';
}
}
Bu bizning klass bo'ladi, unda bir nechta maydon, parametr bilan konstruktor, getter va setterlar, toString() metodi va iniciatsiya bloki bor. Endi obyektni refleksiya orqali yaratishga o'tamiz. Birinchi usul Class.newInstance() orqali amalga oshiriladi.
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
Employee employee = Employee.class.newInstance();
System.out.println("age is - " + employee.getAge());
}
}
Ajoyib, kodni ishga tushiramiz va initsializator orqali yoshni chiqishini kutamiz. Lekin, sukut bo'yicha konstruktor yo'qligi haqida xato olamiz. Bu usul orqali biz faqat sukut bo'yicha konstruktor bilan yaratilgan obyektni olamiz. Klassimiz uchun sukut bo'yicha konstruktor qo'shib, kodni yana bir bor sinab ko'raylik.
Xato haqida xabar:
Yangi konstruktor kodi:
public Employee() { }
Konstruktor qo'shilgandan so'ng dastur natijasi:
Ajoyib, biz bu metod qanday ishlashini tushundik. Endi uning ichki qismini ko'rib chiqamiz. Dokumentatsiyani ochamiz va bizning metod deprecate (inglizcha - eskirgan) ekanligini ko'ramiz:
Yana bir narsa - InstantiationException, IllegalAccessException istisnolarni chiqarishi mumkin. Shuning uchun dokumentatsiyada obyekt yaratishning ikkinchi usulini, ya'ni Constructor.newInstance() dan foydalanishni tavsiya qilamiz. Constructor klassining ishlashini ko'rib chiqaylik va u haqida batafsil gaplashaylik.
getConstructors va getDeclaredConstructors metodlari
Constructor klassi bilan ishlash uchun, avval uni olishimiz kerak. Buning uchun bizda ikkita metod bor: getConstructors va getDeclaredConstructors.
Birinchi metod ochiq konstruktlarning ro'yxatini massiv shaklida qaytaradi, ikkinchisi esa klassdagi barcha konstruktlarni massiv shaklida qaytaradi.
Klassimizga biroz maxfiylik qo'shamiz, ya'ni metodlarimizning ishlashini ko'rsatish uchun bir nechta privet konstruktlar qo'shamiz.
Biroz privet konstruktlar qo'shamiz:
private Employee(String name, String surname) {
this.name = name;
this.surname = surname;
}
Klass strukturasida bizning bir konstruktorimiz privet ekanligini aniq ko'rish mumkin:
Bizning metodlarimizning ishini sinab ko'ramiz:
public class Main {
public static void main(String[] args) {
Class employeeClass = Employee.class;
System.out.println("getConstructors:");
printAllConstructors(employeeClass);
System.out.println("\n" +"getDeclaredConstructors:");
printDeclaredConstructors(employeeClass);
}
static void printDeclaredConstructors(Class<?> c){
for (Constructor<?> constructor : c.getDeclaredConstructors() ) {
System.out.println(constructor);
}
}
static void printAllConstructors(Class<?> c){
for (Constructor<?> constructor : c.getConstructors()) {
System.out.println(constructor);
}
}
}
Va biz quyidagi natijani olamiz:
public ru.javarush.Employee(java.lang.String,java.lang.String,int)
public.ru.javarush.Employee()
getDeclaredConstructors:
private ru.javarush.Employee(java.lang.String,java.lang.String)
public ru.javarush.Employee(java.lang.String,java.lang.String,int)
public ru.javarush.Employee()
Ajoyib, shu tarzda biz Constructor klassiga kirish imkoniyatini olamiz. Endi uning imkoniyatlari haqida gaplashishimiz mumkin.
java.lang.reflect.Constructor klassi, uning asosiy metodlari
Asosiy metodlarga va ularning qanday ishlashiga bir ko'z tashlaylik:
| Metod | Ta'rif |
|---|---|
| getName() | Ushbu konstruktorning nomini string shaklida qaytaradi. |
| getModifiers() | Java tili modifikatorlarini raqam shaklida qaytaradi. |
| getExceptionTypes() | Konstruktor tomonidan e'lon qilingan istisno turlarini ifodalovchi ob'ektlar massivi qaytaradi. |
| getParameters() | Ob'ekt parametrlari ifodalovchi ob'ektlar massivini qaytaradi. Agar konstruktor parametrga ega bo'lmasa, uzunligi 0 bo'lgan massiv qaytaradi. |
| getParameterTypes() | E'lon qilingan tartibdagi parametrlarning formal turlarini ifodalovchi ob'ektlar massivini qaytaradi. |
| getGenericParameterTypes() | E'lon qilingan tartibdagi parametrlarning formal turlarini ifodalovchi tip ob'ektlar massivini qaytaradi. |
getName() & getModifiers()
Bizning massivimizni List ichiga olishimiz uchun qulay ishlashimiz uchun metodi yozamiz: getName va getModifiers:
static List<Constructor<?>> getAllConstructors(Class<?> c) {
return new ArrayList<>(Arrays.asList(c.getDeclaredConstructors()));
}
static List<String> getConstructorNames(List<Constructor<?>> constructors) {
List<String> result = new ArrayList<>();
for (Constructor<?> constructor : constructors) {
result.add(constructor.toString());
}
return result;
}
static List<String> getConstructorModifiers(List<Constructor<?>> constructors) {
List<String> result = new ArrayList<>();
for (Constructor<?> constructor : constructors) {
result.add(Modifier.toString(constructor.getModifiers()));
}
return result;
}
Bizning main metodimiz, bizda hammasini chaqirish mumkin bo'lgan joyda:
public static void main(String[] args) {
Class employeeClass = Employee.class;
var constructors = getAllConstructors(employeeClass);
var constructorNames = getConstructorNames(constructors);
var constructorModifiers = getConstructorModifiers(constructors);
System.out.println("Klass Employee:");
System.out.println("Konstruktorlar :");
System.out.println(constructorNames);
System.out.println("Modifikatorlar :");
System.out.println(constructorModifiers);
}
Natijada bizga kerakli barcha ma'lumotlarni ko'ramiz:
Konstruktorlar :
[private ru.javarush.Employee(java.lang.String), public
ru.javarush.Employee(java.lang.String,java.lang.String,int), public ru.javarush.Employee()]
Modifikatorlar :
[private, public, public]
getExceptionTypes()
Ushbu metod bizning konstruktorimiz tabiiy chiqarishi mumkin bo'lgan istisnolar massivini olish imkonini beradi. Bizning mavjud konstruktorimizni biroz o'zgartirib, yangi metod yozaylik.
Bu yerda bizning hozirgi privet konstruktorimiz biroz o'zgartirildi:
private Employee(String name, String surname) throws Exception {
this.name = name;
this.surname = surname;
}
Bu yerda bizda istisno turlarini olish va uni main ga qo'shish metodi:
static List<Class<?>> getConstructorExceptionTypes(Constructor<?> c) {
return new ArrayList<>(Arrays.asList(c.getExceptionTypes()));
}
var constructorExceptionTypes = getConstructorExceptionTypes(constructors.get(0));
System.out.println("Istisno turlari :");
System.out.println(constructorExceptionTypes);
Yuqorida, biz ro'yxatdagi birinchi konstruktor bilan ish tutdik. Ma'lum bir konstruktorni qanday olishni keyinroq muhokama qilamiz.
Va throws Exception qo'shishdan keyin natijaga qaraylik:
[class java.lang.Exception]
Va istisno qo'shishdan oldin:
[]
Hammasi ajoyib, lekin konstruktorlarimiz uchun qanday parametrlar kerakligini qanday ko'rish mumkin? Bu qismni ham ko'rib chiqaylik.
getParameters() & getParameterTypes() & getGenericParameterTypes()
Bizning privet konstruktorimizni yana biroz tuzatish bilan boshlaymiz. Endi u quyidagi ko'rinishda bo'ladi:
private Employee(String name, String surname, List<String> list) {
this.name = name;
this.surname = surname;
}
Va bizda uchta qo'shimcha metodlar paydo bo'ladi: getParameters parametrlar va ularning turlarini olish, getParameterTypes parametr turlarini olish va getGenericParameterTypes bilan generik typelarga o'ralgan turlarni olish uchun.
static List<Parameter> getConstructorParameters(Constructor<?> c) {
return new ArrayList<>(Arrays.asList(c.getParameters()));
}
static List<Class<?>> getConstructorParameterTypes(Constructor<?> c) {
return new ArrayList<>(Arrays.asList(c.getParameterTypes()));
}
static List<Type> getConstructorParametersGenerics(Constructor<?> c) {
return new ArrayList<>(Arrays.asList(c.getGenericParameterTypes()));
}
Va bizning hali kichik bo'lmagan main ga yana biroz ma'lumot qo'shamiz:
var constructorParameterTypes = getConstructorParameterTypes(constructors.get(0));
var constructorParameters = getConstructorParameters(constructors.get(0));
var constructorParametersGenerics = getConstructorParametersGenerics(constructors.get(0));
System.out.println("Konstruktor parametrlarini :");
System.out.println(constructorParameters);
System.out.println("Parametrlar turlari:");
System.out.println(constructorParameterTypes);
System.out.println("Konstruktor parametrlarining turlari:");
System.out.println(constructorParametersGenerics);
Agar natijani ko'rsak, konstruktorlarimiz parametrlarining juda batafsil ma'lumotlarini olamiz:
[java.lang.String arg0, java.lang.String arg1, java.util.List<java.lang.String> arg2]
Parametrlar turlari :
[class java.lang.String, class java.lang.String, interface java.util.List]
Konstruktor parametrlarining turlari :
[class java.lang.String, class java.lang.String, java.util.List<java.lang.String>]
Biz har bir metodning farqini aniq ko'ramiz. Parametrlar turlari haqida alohida ma'lumot, wrapper klasslarining ma'lumotlari va hamma narsani umuman olish mumkinligini ko'rish mumkin. Super! Biz Constructor klassi bilan tanishishni tugalladik va endi asosiy maqola mavzusiga - obyektlarni yaratishga qaytishimiz mumkin.
Constructor.newInstance() orqali obyekt yaratish
Obyektlarni yaratishning ikkinchi usuli - konstruktorda newInstance metodini chaqirish. Ishning namunasiga qaraylik va qanday qilib ma'lum bir konstruktorni olish mumkinligini ko'raylik.
Agar ma'lum bir konstruktorni olish muammosi turganda, sen getConstructor metodidan foydalanishing kerak (barcha konstruktorlar massivi qaytaradigan getConstructors bilan adashtirma). getConstructor metod sukut bo'yicha konstruktorni qaytaradi.
public static void main(String[] args) throws NoSuchMethodException {
Class employeeClass = Employee.class;
Constructor<?> employeeConstructor = employeeClass.getConstructor();
System.out.println(employeeConstructor);
}
Va agar ma'lum bir konstruktorni olishni istasak, biz bu metodga konstruktor ichidagi parametr turlarini o'tkazishimiz kerak.
Bizning privet konstruktorimizni faqat getDeclaredConstructor metodi yordamida olishimiz mumkinligini unutma.
Constructor<?> employeeConstructor2 = employeeClass.getDeclaredConstructor(String.class, String.class, List.class);
System.out.println(employeeConstructor2);
Shunday qilib, ma'lum bir konstruktorni olishimiz mumkin. Endi esa, privet va ochiq konstruktor orqali obyekt yaratishga harakat qilamiz.
Ochiq konstruktor:
Class employeeClass = Employee.class;
Constructor<?> employeeConstructor = employeeClass.getConstructor(String.class, String.class, int.class);
System.out.println(employeeConstructor);
Employee newInstance = (Employee) employeeConstructor.newInstance("NeIvan", "NeIvanov", 10);
System.out.println(newInstance);
Va natijada bizga ishlash uchun obyekt bor:
Employee{name=’NeIvan’ surname=’NeIvanov’, age=10}
Hammasi ajoyib ishlaydi! Endi privet konstruktor bilan sinab ko'ramiz:
Constructor<?> declaredConstructor = employeeClass.getDeclaredConstructor(String.class, String.class, List.class);
System.out.println(declaredConstructor);
Employee newInstance2 = (Employee) declaredConstructor.newInstance("NeIvan", "NeIvanov", new ArrayList<>());
System.out.printf(newInstance2.toString());
Va natijada konstruktorimiz privetligi haqida xatoni olamiz:
Java bu konstruktor orqali obyekt yaratishga qodir emas edi, lekin aslida biz main metodida ko'rsatadigan kichik sehrli narsa bor. Bu konstruktorimizga kirishni o'rnatib, klassimizdan obyekt yaratishga imkon beradi:
declaredConstructor.setAccessible(true);
Obyekt yaratish natijasi:
Employee{name=’NeIvan’, surname=’NeIvanov’, age=-1}
Biz konstruktorda yoshni o'rnatmaymiz, va u initsializatsiya bo'yicha shundayligicha qoladi.
Ajoyib, natijalarni yakunlash vaqti keldi!
Constructor.newInstance() orqali yaratishning afzalliklari
Ikkala metodning nomi bir xil ko'rinishi mumkin, lekin ular o'rtasida farqlar bor:
| Class.newInstance() | Constructor.newInstance() |
|---|---|
| Faqat sukut bo'yicha no-arg konstruktorni chaqira oladi. | Har qanday konstruktorni chaqira oladi, parametrlar sonidan qat'i nazar. |
| Konstruktor ko'rinadigan bo'lishini talab qiladi. | Ma'lum sharoitlarda privet konstruktorlarni ham chaqira oladi. |
| Konstruktor tomonidan e'lon qilingan har qanday istisnoni (tekshirilgan yoki tekshirilmagan) chiqaradi. | Har doim chiqarilgan istisnoni InvocationTargetException bilan o'rab beradi. |
Shu sababli Constructor.newInstance() Class.newInstance() dan afzalroq, va aynan u turli frameworklar va API, masalan, Spring, Guava, Zookeeper, Jackson, Servlet va boshqalarda ishlatiladi.
GO TO FULL VERSION