جنریک ها در جاوا - Generics in Java

می خوام در مورد generic ها براتون صحبت کنم و البته مثال هایی ار در زبان جاوا براتون بیارم. اول از همه می ریم سراغ اینکه مفهموم generic چیه و چرا ازش استفاده می کنیم.تعریفی که اوراکل از generic ها ارائه میده به این صورت هست:"In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs. The difference is that the inputs to formal parameters are values, while the inputs to type parameters are types."ترجمه متن بالا رو می ذاریم به عهده خواننده و می ریم سراغ یک مثال ساده برای فهم راحت تر قضیه. فرض کنید ما یک متد print داریم که String ها رو روی کنسول چاپ می کنه:public void print(String printMe){ System.out.println(printMe); }خب حالا فرض کنید برای Integer ها همین متد رو لازم داریم. یه راه اینه که یک متد که دقیقا مثل متد بالاست و فقط در نوع آرگومان ورودی متفاوته بنویسم که میشه:public void print(Integer printMe){ System.out.println(printMe); }و در نهایت، کل کلاس Printer ما خواهد شد:public class Printer{ public void print(String printMe){ System.out.println(printMe); } public void print(Integer printMe){ System.out.println(printMe); } // too many other print methods... }حالا اگه همین رو بخوایم برای هر نوع آبجکتی ادامه بدیم کلاسمون پر میشه از کد های تکراری. اینجاست که یه راه حل اصولی و استاندارد این وسط وجود داره به اسم generic. این به ما اجازه میده کدمون رو عمومی تر بنویسیم تا بتونه با تایپ های بیشتری کار کنه و قابلیت re-use در کد ما بالاتر بره. کد بالا با استفاده از generic به این صورت نوشته میشه:public class Printer<T> { public void print(T printMe) { System.out.println(printMe); } }توی این کد به T می گیم generic و کد بالا به این معنی هست که هر ورودی ای، با هر نوع آبجکت رو پرینت می گیره. در ضمن لزومی نداره فقط از حرف T استفاده بشه، می تونید از چیز های دیگه هم استفاده کنید.* یه نکته این وسط وجود داره، generic ها رو نمی تونید برای primitive type ها مثل int استفاده کنید. به طور مثال برای کار کردن با int باید از کلاس Integer استفاده کنید.حالا چرا این <T> احیانا به چشم تون آشناست؟ چون شما از generic بار ها استفاده کردید و اینم نمونه ش:Map<Integer, String> map = new HashMap<>(); ArrayList<Person> personList = new ArrayList<>();الان که مفهوم و چرایی generic رو گفتیم یه نکته آخری رو هم بگیم:وقتی generic رو تعریف کنیم می تونیم اون رو به صورت bounded و unbounded تعریف کنیم. می دونیم که کلاس ها در جاوا بچه ی کلاس Object هستند و در واقع همه شون extends Object رو دارن که ما دیگه نمی نویسیمش. این حکم توی generic هم صادقه، یعنی اگر generic به صورت unbounded تعریف بشه هیچی کنارش قرار نمی گیره مثل کلاس پایین:public class MyClass<E> { private E property; public E getProperty() { return this.property; } }و اگر بخوایم generic مون رو محدود کنیم می تونیم به این صورت بنویسیمشpublic class MyClass<E extends Number> { private E property; public E getProperty() { return this.property; } }همون طوری که می دونیم همه اعداد در جاوا فرزند کلاس Number هستند و ما با این محدود سازی کاری کردیم که فقط میشه به این کلاس فرزندان Number و خودش رو پاس داد که خب در جای خودش بسیار کاربردی هست (در واقع ما می تونیم با محدود سازی در حین توسعه از بروز خطاها و Exception های زمان اجرا به حد خوبی جلوگیری کنیم).