دانستنی‌ها

همه چیز از دست نرفته است! (جشنواره عید تا عید)

(این مقاله از طرف جناب آقای رضا خشنودنیا برای جشنواره عید تا عید جاواکاپ ارسال شده است و محتوای این مطلب لزوماً موردتأیید جاواکاپ نیست. لطفاً با مطالعه، بازنشر و امتیازدهی به این مطلب، به انتخاب برترین مقاله در این جشنواره کمک نمایید.)

 

همانطور که می دانید، در جاوا می توان با امکان Generic، کلاس هایی تعریف کرد که یک یا چند نوع داده مورداستفاده خود را به صورت پارامتریک تعریف می کنند. بدین ترتیب شما کلاس هایی می نویسید که قابلیت کار با انواع مختلف داده را دارند.

نکته ای که در مورد کلاس های عام در جاوا مطرح است، این است که نوع داده عام، در زمان اجرا وجود ندارد. در واقع تعریف کلاس به صورت عام، فقط در زمان کامپایل تاثیرگذار است و در پس از کامپایل نوع داده عام از دست می رود. این نوع پیاده سازی Generic در زبان جاوا، اگرچه هدف اصلی را که انتقال خطاها از زمان اجرا به زمان کامپایل است، برآورده می کند، اما محدودیت هایی را در زمان توسعه برای برنامه نویس به همراه دارد. به عنوان مثال امکان Instance ساختن از نوع داده عام وجود ندارد. (برای اطلاعات بیشتر در مورد Generic، Type Erasure و محدودیت های آن می توانید به فیلم آموزشی جاواکاپ در این باره مراجعه کنید)

picture

اما سوال این است که این محدودیت از کجا ناشی می شود؟ اگر اندکی با ساختار زبان جاوا آشنایی داشته باشیم دلیل این امر واضح به نظر می رسد. می دانیم کد منبع کلاس های نوشته شده توسط برنامه نویس، در زمان کامپایل به فایل های .class تبدیل شده که در واقع یک زبان میانی و مستقل از سکو است. در زمان اجرا، JVM این فایل ها را parse کرده و اطلاعات هر کلاس شامل لیست فیلدها، توابع، بدنه ی آن ها و سایر اطلاعات را در Instance ای از یک کلاس به نام java.lang.Class ذخیره می کند! این در واقع همان اطلاعاتی است که از طریق Reflection API در اختیار برنامه نویس قرار می گیرد. اما چه ارتباطی بین این موضوع و Type Erasure وجود دارد؟ Type Erasure از دید فنی به این معناست که در کلاس java.lang.Class اطلاعاتی در رابطه با نوع داده های عام تعریف شده، ذخیره نمی شود. دلیل آن هم این است نوع داده های عام در زمان استفاده (یعنی برای Generic Class ها در زمان new کردن و برای Generic Method ها در زمان اجرای تابع) مشخص می شوند. حال آنکه اطلاعاتی که در java.lang.Class ذخیره می شود مستقل از Instance ها و شیوه استفاده از آن کلاس/تابع است. به همین خاطر رفع این محدودیت، نیاز به بازطراحی بخش هایی از API و همین طور JVM جاوا داشت که طراحان زبان جاوا برای حفظ Backward Compatibility تصمیم گرفتند از آن صرف نظر کنند.

اما صبر کنید. همه چیز از دست نرفته است! درست است که شما به نوع داده عام از طریق خود کلاس عام دسترسی ندارید، اما در بسیاری از حالت ها امکان دسترسی به این اطلاعات در جایی که از کلاس/تابع عام استفاده کرده اید، امکان پذیر است. در ادامه به بررسی برخی از این حالت ها و نحوه استخراج نوع داده عام می پردازیم:

  • کلاسی که دارای Generic SuperClass است:
public class MyList extends ArrayList<String> {
	…
}

اگر کلاس شما دارای یک SupperClass دارای Generic است و نوع داده عام آن مشخص شده باشد می توانید از طریق زیر به نوع داده عام دسترسی پیدا کنید:

ParameterizedType clazz=(ParameterizedType)MyList.class.getGenericSuperclass();
System.out.println(clazz.getActualTypeArguments()[0]);
  • توابعی که کلاس های عام برمی گردانند:
public List<String> getList(){
	…
}

به صورت زیر می توان نوع داده عام را به دست آورد:

Method method=clazz.getMethod("getList",null);
ParameterizedType returnType=(ParameterizedType)method.getGenericReturnType();
System.out.println(returnType.getActualTypeArguments()[0]);
  • توابعی که دارای آرگومان از نوع کلاس های عام هستند:
public void setList(List<String> list){
	…
}

نوع داده عام به شکل زیر قابل حصول است:

Method method=clazz.getMethod("setList",List.class);
ParameterizedType param=(ParameterizedType)method.getGenericParameterTypes()[0];
System.out.println(param.getActualTypeArguments()[0]);
  • فیلدهای تعریف شده از نوع کلاس های عام:
    public class MyClass{
    	private List<String> list;
    	...
    }

دسترسی به نوع داده عام از طریق زیر ممکن است:

ParameterizedType field=(ParameterizedType)MyList.class.getField("list").getGenericType();
System.out.println(field.getActualTypeArguments()[0]);

آیا می توانید کاربردی برای استخراج نوع داده عام از این طریق پیدا کنید؟

منابع:

http://tutorials.jenkov.com/java-reflection/generics.html

http://stackoverflow.com/questions/11822904/what-are-the-exceptions-to-type-erasu

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا