Generics ها در جاوا
اگر بخواهید توابع و کلاس های شما حالت عمومی تر داشته باشد باید از متدها generic یا کلاس های generic استفاده کنید. به طور مثال متدی بنویسید که آرایه ای از هر جنس را بگیرد و تمامی المان های آن را چاپ کند. یا متدی داشته باشید که آرایه ای از هر جنس بگیرد و آن را مرتب کند کما این که این آرایه از جنس int باشد یا string .
generic ها این امکان را به ما می دهند که کلاس ها و اینترفیس ها و متدهایی تعریف کنیم که ورودی ها و خروجی هایی از نوع general داشته باشند.
نوع داده های مجاز برای استفاده در generic ها
نوع داده هایی که در generic ها استفاده می شود باید از نوع Reference باشد و نمی توان از نوع داده های اصلی استفاده کرد. ما در جاوا wrapper class هایی داریم که یک مقدار از نوع اصلی را در خود می پیچاند ، بنابراین می توان مقداری از نوع داده اصلی داشت که مثل نوع داده ارجاعی با آن رفتار می شود.
Primitive Type | Wrapper class |
---|---|
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
زمانی که دارید یک کلاس یا متد generic را تعریف را فراخوانی می کنید ورودی خود را از نوع wrapper class تعریف کنید:
- در زمان instance کلاس ها نوع داده wrapper class رو استفاده کنید.(معمولا نوع داده در زمان instance برای متد سازنده استفاده می شود)
- یعنی نوع داده wrapper class رو بسازید و به متد مربوطه پاس بدید.
تعریف یک کلاس generic
مثلا
public class Gen<T>{}
- PARAMSNAMEیک نوع داده است که در طول کلاس یا متد می توان از آن استفاده کرد.
- منظور از PARAMSNAME همان داده ایست که در زمان ساخت شی به آن داده می شود تا در سازنده از آن استفاده شود.
- PARAMSNAME می تواندی یک یا چند پارامتر باشد که با , از هم جدا شده باشند.
instance گیری از کلاس های generic
مثلا
Gen<Integer> g = new Gen<>(5);
- در زمان نمونه گیری از کلاس generic باید نوع داده از جنس wrapper class را نیز در زمان نوع داده متغیر درجلو آن قرار داد.
- PARAMS می تواند پارامتری از جنس نوع داده درونی wrapper class باشد.
مثال:
public class Box<T , E> { private T t; private E e; public Box(T t,E e){ this.t = t; this.e = e; } public T get_t(){ return this.t; } public E get_e() { return this.e; } public static void main(String args[]){ Box<Integer,Integer> b = new Box<>(10,20); int e = b.get_e(); int t = b.get_t(); System.out.printf("t is %d \ne is %d", t, e); } }
- در طول کلاس و متد های آن از T , E به صورت یک نوع داده رفتار می کنیم.
- در زمان instance گیری (عملا در زمان مقدار دهی به متد سازنده) از wrapper class ها استفاده می کنیم.
- ما برای پارامتر های کلاس یا متد generic معمولا از نام های T , E استفاده می کنیم.
تعریف متد از نوع generic
در داخل یک کلاس ما می توانیم یک متد از نوع generic داشته باشیم که هم خروجی آن می تواند general باشد و هم ورودی آن می تواند general باشد و یا هر دو.
مثلا
public static <T> void test(T t) { }
متدهای جنریک یک نوع داده برای پارامتر ورودی و خروجی دارند که هنگام تعریف به جای این که از انواع داده که قبلا گفتیم استفاده کنند از یک شاخص بین دو کاراکتر <> استفاده می شود که می توان از همین نوع داده () به عنوان ورودی و یا از همین نوع خروجی داشته باشد.
public class genMethod { public static <E> void printArray(E[] inputArray){ for(E tmp: inputArray){ System.out.println(tmp); } } public static <T> T test(T t){ return t; } public static void main(String args[]){ Integer int_arr[] = {1,2,3,4,5}; String str_arr[] = {"mahdi","abolfazl","mohamad","kurosh"}; Double dbl_arr[] = {1.2,2.8,6.4,5.3}; System.out.println("* integer array *"); genMethod.printArray(int_arr); System.out.println("* string array *"); genMethod.printArray(str_arr); System.out.println("* double array *"); genMethod.printArray(dbl_arr); } }
- متد test هم ورودی از نوع general دارد و خروجی.
- متد printArray تنها ورودی از نوع general دارد.
- در زمان فراخوانی متد printArray نوع داده ارجاعی را با استفاده از wrapper class ساختیم و بعد به متد generic دادیم.
- شاخص <T> تعریف نوع پارامتر ورودی و خروجی در متد test هست.
محدودکردن پارامتر های generic
می تونیم با کلمه کلیدی extends پارامتر های generic رو محدود کنیم. مثلا متدی که فقط داده از نوع عددی (Number) بگیرد حال از نوع int , double , short , …
حال می تونه اون Number برابر با ورودی های رشته ای باشه .
public class restrictWCT<T extends Number> { private T t; public restrictWCT(T t){ this.t = t; } public T get_t(){ return this.t; } public static void main(String args[]){ restrictWCT<Integer> r = new restrictWCT<>(10); int i = r.get_t(); System.out.printf("integer is %d",i); } }
در مثال بالا متد سازنده کلاس restricWCT فقط داده ورودی از نوع عددی می گیرد.
خیلی عالی توضیح داده بودید.
خداقوت به شما.