شیء Constructor به شما امکان دریافت اطلاعات بیشتر درباره Constructor مربوطه را میدهد: Modifier ها، Type و نام پارامترها و همچنین فراخوانی آن برای ایجاد نمونههایی از اشیا با پاس دادن آرگومانهای لازم. این بخش نحوه کشف Constructor ها در یک کلاس را نیز پوشش میدهد.
کلاس Class دو دسته متود برای دسترسی به Constructor ها ارائه میدهد:
توجه کنید Constructor ها ارث برده نمیشوند، پس معادلی برای متدهای جستجوی فیلدها یا متدها در کلاسهای ارثبریشده ندارید.
| Class API | آرایه Constructor ها؟ | Constructor های Private؟ |
|---|---|---|
getDeclaredConstructor(Class...) | خیر | بله |
getConstructor(Class...) | خیر | خیر |
getDeclaredConstructors() | بله | بله |
getConstructors() | بله | خیر |
یک اعلام Constructor شامل نام، Modifier ها، پارامترها و لیست Exception های قابل پرتاب است. کلاس java.lang.reflect.Constructor راهی برای دریافت این اطلاعات ارائه میدهد.
بیایید Constructor های کلاس String را بررسی کنیم. کد زیر ۱۹ Constructor موجود در این کلاس در JDK 23 را چاپ میکند:
Class<?> c = String.class;
Constructor<?>[] constructors = c.getDeclaredConstructors();
IO.println("# constructors = " + constructors.length);
for (Constructor<?> constructor : constructors) {
IO.println("constructor = " + constructor);
}
همه Constructor ها Public نیستند:
# constructors = 19
constructor = public java.lang.String(java.lang.StringBuilder)
constructor = private java.lang.String(char[],int,int,java.lang.Void)
constructor = java.lang.String(java.lang.AbstractStringBuilder,java.lang.Void)
constructor = private java.lang.String(java.nio.charset.Charset,byte[],int,int)
constructor = public java.lang.String(byte[],int,int,java.nio.charset.Charset)
constructor = public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException
constructor = public java.lang.String(byte[],java.nio.charset.Charset)
constructor = public java.lang.String(byte[],int,int)
constructor = public java.lang.String(byte[])
constructor = public java.lang.String(java.lang.StringBuffer)
constructor = java.lang.String(byte[],byte)
constructor = public java.lang.String(char[],int,int)
constructor = public java.lang.String(char[])
constructor = public java.lang.String(java.lang.String)
constructor = public java.lang.String()
constructor = public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException
constructor = public java.lang.String(byte[],int)
constructor = public java.lang.String(byte[],int,int,int)
constructor = public java.lang.String(int[],int,int)
میتوانید Constructor خاصی را نیز پیدا کنید، بهعنوان مثال Constructorی که آرایهای از byte میگیرد. سینتکس byte[].class برای نشان دادن کلاس آرایه byte استفاده میشود:
Class<?> c = String.class;
Constructor<?> constructor = c.getConstructor(byte[].class);
IO.println("constructor = " + constructor);
constructor = public java.lang.String(byte[])
کلاس Constructor دسترسی به پارامترهای یک Constructor خاص را فراهم میکند. مشابه متدها، Type خام با Constructor.getParameterTypes() و Type Generic با Constructor.getGenericParameterTypes() دریافت میشود.
بیایید Constructor های کلاس ArrayList را بررسی کنیم:
ابتدا Type خام پارامترها:
Class<?> c = ArrayList.class;
Constructor<?>[] constructors = c.getConstructors();
for (Constructor<?> constructor : constructors) {
IO.println("constructor with " + constructor.getParameterCount() + " parameter(s)");
for (Class<?> type : constructor.getParameterTypes()) {
IO.println(" " + type.getName());
}
}
constructor with 1 parameter(s)
java.util.Collection
constructor with 0 parameter(s)
constructor with 1 parameter(s)
int
و Type Generic:
Class<?> c = ArrayList.class;
Constructor<?>[] constructors = c.getConstructors();
for (Constructor<?> constructor : constructors) {
IO.println("constructor with " + constructor.getParameterCount() + " parameter(s)");
for (Type type : constructor.getGenericParameterTypes()) {
IO.println(" " + type.getTypeName());
}
}
constructor with 1 parameter(s)
java.util.Collection<? extends E>
constructor with 0 parameter(s)
constructor with 1 parameter(s)
int
کلاس Constructor دسترسی به Exception های declared شده را فراهم میکند. این Exception ها بهصورت آرایهای از Class یا Type بازگردانده میشوند.
Exception های Constructor کلاس FileWriter که یک String میگیرد:
Class<?> c = FileWriter.class;
Constructor<?> constructor = c.getConstructor(String.class);
for (Class<?> exceptionType : constructor.getExceptionTypes()) {
IO.println("Exception type: " + exceptionType.getName());
}
for (Type exceptionType : constructor.getGenericExceptionTypes()) {
IO.println("Generic exception type: " + exceptionType.getTypeName());
}
Exception type: java.io.IOException
Generic exception type: java.io.IOException
فراخوانی یک Constructor نمونه جدیدی از کلاس ایجاد میکند. دو روش Reflective برای ایجاد نمونه وجود دارد: Class.newInstance() و Constructor.newInstance() که دومی روش توصیهشده است.
روش اول فراخوانی متود newInstance() کلاس Class است. این متود Constructor بدون پارامتر کلاس را فراخوانی میکند. اگر Constructor وجود نداشته باشد یا قابل مشاهده نباشد (مثلاً Private باشد)، Exception پرتاب میکند.
متود
Class.newInstance()از Java SE 9 منسوخ (Deprecated) شده و دیگر نباید استفاده شود. دلایل متعددی دارد:
Class.newInstance()فقط Constructor بدون پارامتر را فراخوانی میکند، در حالی کهConstructor.newInstance()هر Constructorای را فراخوانی میکند.Class.newInstance()تمام Exception ها شامل Checked Exception ها را پرتاب میکند و عملاً بررسی Exception در زمان کامپایل را دور میزند.Class.newInstance()نیاز دارد Constructor قابل مشاهده باشد، در حالی کهConstructor.newInstance()در شرایط خاص Constructor های Private را نیز فراخوانی میکند.
روش دوم که باید استفاده کنید، دریافت رفرنس به یک از Constructor ها و فراخوانی آن است.
Class<String> stringClass = String.class;
String emptyString = stringClass.getConstructor().newInstance();
IO.println("Empty? " + emptyString.isEmpty());
Empty? true
نکات:
stringClass.getConstructor() اگر Constructor بدون پارامتر وجود نداشته باشد، NoSuchMethodException پرتاب میکند.newInstance() Exception های متعددی پرتاب میکند:
InvocationTargetException: Exception احتمالی ناشی از فراخوانی Constructor را بستهبندی میکند.InstantiationException: اگر کلاس قابل نمونهسازی نباشد (مثلاً Abstract Class یا Interface).IllegalAccessException: اگر Constructor بدون پارامتر از کد فراخوانی قابل دسترسی نباشد.فرض کنید Record زیر را دارید:
public record Point(int x, int y) {
public Point() {
this(0, 0);
}
}
Constructor بدون پارامتر را فراخوانی کنید:
Class<Point> c = Point.class;
Constructor<Point> constructor = c.getConstructor();
Point p = constructor.newInstance();
IO.println("p = " + p);
p = Point[x=0, y=0]
Constructor کانونیکال (Canonical) را نیز میتوانید فراخوانی کنید. این Constructor بهصورت صریح در کد نوشته نشده اما کامپایلر آن را تولید کرده است:
Class<Point> c = Point.class;
Constructor<Point> constructor = c.getConstructor(int.class, int.class);
Point p = constructor.newInstance(1, 1);
IO.println("p = " + p);
p = Point[x=1, y=1]
فراخوانی یک Constructor Private از خارج کلاس، IllegalAccessException پرتاب میکند.
میتوانید ابتدا constructor.setAccessible(true) را فراخوانی کنید تا دسترسی فراهم شود. مشابه فیلدها و متدها، محدودیتهایی برای Constructor هایی که میتوانید قابل دسترسی کنید وجود دارد.
فراخوانی
setAccessible(true)روی یک Constructor آن را Public نمیکند. فقط بررسیهای Access Control را غیرفعال میکند.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/