تمام عناصری که Reflection API به آنها دسترسی میدهد دارای نام هستند: کلاسها، فیلدها، متدها، Constructor ها و پارامترهای متدها و Constructor ها. این بخش نحوه بازیابی نام کلاسها را پوشش میدهد. Reflection API چندین قرارداد (Convention) برای نام کلاسها تعریف میکند که همه در این بخش بررسی میشوند.
در واقع چندین روش برای دریافت نام یک کلاس وجود دارد. دو متودی که احتمالاً استفاده خواهید کرد getCanonicalName() و getSimpleName() هستند. اولی نام کامل (Fully Qualified Name) کلاس را برمیگرداند و دومی فقط نام را بدون پکیج برمیگرداند.
در مثال زیر، وقتی کلاس بهصورت صریح نامگذاری شده، نتیجه همان چیزی است که انتظار دارید:
Class<?> arrayList = Class.forName("java.util.ArrayList");
IO.println("Canonical name: " + arrayList.getCanonicalName());
خروجی:
Canonical name: java.util.ArrayList
در مواردی نام کلاس بهصورت صریح در کد شما ظاهر نمیشود:
List<String> strings1 = new ArrayList<>();
List<String> strings2 = Arrays.asList("one", "two", "three");
List<String> strings3 = List.of("one", "two", "three");
IO.println("Canonical name 1: " + strings1.getClass().getCanonicalName());
IO.println("Canonical name 2: " + strings2.getClass().getCanonicalName());
IO.println("Canonical name 3: " + strings3.getClass().getCanonicalName());
نامهای کلاسهای Runtime دریافت میشوند:
Canonical name 1: java.util.ArrayList
Canonical name 2: java.util.Arrays.ArrayList
Canonical name 3: java.util.ImmutableCollections.ListN
نام ساده یک کلاس همان نامی است که در کد منبع (Source Code) ظاهر میشود.
Class<?> c = String.class;
IO.println("Simple name: " + c.getSimpleName());
Simple name: String
همه کلاسها بهصورت صریح در کد منبع ظاهر نمیشوند. این مورد شامل کلاسهای Anonymous و Lambda Expression ها است.
نام ساده یک کلاس Anonymous در واقع خالی است:
Object key = new Object() {};
Class<?> c = key.getClass();
IO.println("Simple name: " + c.getSimpleName());
Simple name:
همچنین میتوانید نام ساده کلاس نمایانگر یک Lambda Expression را چاپ کنید:
Supplier<String> supplier = () -> "Hello";
Class<?> c = supplier.getClass();
IO.println("Simple name: " + c.getSimpleName());
خروجی (توجه کنید که Main نام ساده کلاسی است که این Lambda در آن اعلام شده و ممکن است متفاوت باشد):
Simple name: Main$$Lambda/0x0000025851003538
نام کانونیکال یک کلاس در مشخصات زبان تعریف شده است. بهزبان ساده، معادل نام کامل آن است — یعنی نام ساده با پیشوند نام پکیج. همه کلاسها نام کانونیکال ندارند. این شامل کلاسهای Local، کلاسهای Anonymous و کلاسهای Hidden که در Java SE 15 اضافه شدهاند، میشود.
وقتی کلاسی نام کانونیکال ندارد، متود getCanonicalName() مقدار null برمیگرداند.
مثال زیر Canonical Name ها را نمایش میدهد:
Class<?> c1 = String.class;
IO.println("Canonical name: " + c1.getCanonicalName());
Object key = new Object() {};
Class<?> c2 = key.getClass();
IO.println("Canonical name: " + c2.getCanonicalName());
Supplier<String> supplier = () -> "Hello";
Class<?> c3 = supplier.getClass();
IO.println("Canonical name: " + c3.getCanonicalName());
خروجی نشان میدهد کلاسهای Anonymous و Lambda ها نام کانونیکال ندارند:
Canonical name: java.lang.String
Canonical name: null
Canonical name: null
نام Type یک کلاس یک رشته اطلاعاتی درباره آن کلاس است. این متود در Interface Type تعریف شده که در Java SE 8 اضافه شده است.
بیایید Type Name های مختلف برای کلاسهای معمولی، کلاسهای Anonymous و Lambda ها را بررسی کنیم و تفاوت با Canonical Name را ببینیم:
Class<?> c1 = String.class;
IO.println("Type name: " + c1.getTypeName());
Object key = new Object() {};
Class<?> c2 = key.getClass();
IO.println("Type name: " + c2.getTypeName());
Supplier<String> supplier = () -> "Hello";
Class<?> c3 = supplier.getClass();
IO.println("Type name: " + c3.getTypeName());
کلاسهای Anonymous و Lambda ها Type Name دارند که نام کلاس ایجادشده توسط کامپایلر است:
Type name: java.lang.String
Type name: org.devjava.Main$1
Type name: org.devjava.Main$$Lambda/0x00000275a0003748
Class.getName() روش دیگری برای دریافت نام کلاس است. نام موجودیت (Entity) را که توسط این شیء Class نمایش داده میشود برمیگرداند — چه کلاس، Interface، آرایه، Type اولیه (Primitive) یا void باشد.
برای همه کلاسهایی که آرایه نیستند، فراخوانی این متود معادل Class.getTypeName() است. رفتار برای آرایهها متفاوت است که در بخش بعدی بررسی میشود.
اشیاء Class میتوانند آرایهها را نیز نمایش دهند و آرایهها قراردادهای نامگذاری خاصی دارند. Simple Name، Type Name و Canonical Name ساده هستند:
int[] array = {};
Class<?> c = array.getClass();
IO.println("Simple name: " + c.getSimpleName());
IO.println("Type name: " + c.getTypeName());
IO.println("Canonical name: " + c.getCanonicalName());
Simple name: int[]
Type name: int[]
Canonical name: int[]
نامی که از Class.getName() دریافت میشود قرارداد متفاوتی دارد:
int[] array = {};
Class<?> c = array.getClass();
IO.println("Name: " + c.getName());
Name: [I
قرارداد به این صورت است و دقیقاً در Javadoc متود Class.getName() توضیح داده شده:
نام یک آرایه شامل تعدادی کاراکتر [ باز شدن پرانتز مربعی است که معادل تعداد آرایههای تو در تو است.
اگر Type آرایه یک Type اولیه (Primitive) باشد، جدول زیر برای رمزگذاری آن استفاده میشود. توجه کنید که long با J رمزگذاری میشود، نه L:
| Primitive Type | رمزگذاری |
|---|---|
| boolean | Z |
| byte | B |
| short | S |
| int | I |
| long | J |
| char | C |
| float | F |
| double | D |
اگر Type آرایه یک Reference Type به نام N باشد، رمزگذاری شامل یک L، سپس نام Type و سپس کاراکتر ; است.
بیایید دو مثال ساده را بررسی کنیم:
long[][] bidiLongs = new long[0][];
Class<?> c1 = bidiLongs.getClass();
IO.println("c1: " + c1.getName());
String[][] bidiString = new String[0][];
Class<?> c2 = bidiString.getClass();
IO.println("c2: " + c2.getName());
c1: [[J
c2: [[Ljava.lang.String;
نکته جالب این است که برای آرایهها میتوانید از رشته بازگرداندهشده توسط این متود برای دریافت کلاس آن آرایه استفاده کنید:
Class<?> c = Class.forName("[[Ljava.lang.String;");
IO.println("c = " + c);
c = class [[Ljava.lang.String;
در ادامه این مجموعه آموزش خواهید دید چگونه میتوانید از این کلاس برای ایجاد آرایهای از همین Type استفاده کنید.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/