آموزش جنریک (Generic) در جاوا
خیلی جالب خواهد بود اگر ما تنها یک تابع sort ایجاد کنیم، که بتواند مقادیر آرایه ای از نوع Integer، یا آرایه ای از نوع String یا آرایه ای از هر نوعی داده ای را که امکان مرتب شدن دارد را مرتب کند.
توابع و کلاس های Generic در جاوا (Java)، برنامه نویس را قادر می سازد، تا با تعریف تنها یک تابع، مجموعه ای از توابع مرتبط را، و یا با تعریف تنها یک کلاس، مجموعه ای از کلاس های مرتبط را تحت پوشش قرار دهد.
Generic ها در جاوا، همچنین به برنامه نویس اجازه می دهد نوع داده های نامعتبر را در زمان کامپایل (compile-time) تشخیص دهد، که این موضوع ایمنی نوع داده در زمان کامپایل را فراهم می کند.
با استفاده از مفهوم Generic در جاوا، ما ممکن است یک تابع Generic برای مرتب کردن آرایه ای از نوع Object نوشته، و سپس تابع Generic را برای مرتب کردن مقادیر آرایه با آرایه ای از نوع Integer، یا Double، یا String و غیره فراخوانی کنیم.
توابع Generic
شما می توانید یک تعریف تابع Generic را ایجاد کنید، که می تواند با آرگومان هایی از نوع داده های گوناگون صدا زده شود. کامپایلر بر اساس نوع داده ی آرگومان ارسال شده به تابع Generic، فراخوانی تابع مناسب را تشخیص می دهد. در ادامه قواعد تعریف تابع Generic آمده است:
- توابع Generic دارای قسمت پارامتر نوع است که درون علامت بزرگتر و کوچکتر (< و >) و قبل از تعیین نوع بازگشتی تابع قرار می گیرد.
- هر قسمت پارامتر نوع می تواند دارای یک یا بیشتر پارامتر باشد که توسط کاما از یکدیگر جدا می شوند.
- پارامترهای نوع داده می توانند برای تعریف نوع بازگشتی استفاده شوند، و همانند placeholder برای نوع داده ارسال شده به تابع Generic عمل کنند.
- بدنه تابع Generic همانند توابع معمولی تعریف می شود، توجه داشته باشید که نوع پارامترهای ارسالی به توابع Generic تنها می توانند از نوع مرجع باشند، و نه نوع primitive (مانند int، double و char).
مثال
مثال زیر چگونگی چاپ یک آرایه از نوع های گوناگون را با استفاده از تابع Generic نشان می دهد:
public class GenericMethodTest {
// generic method printArray
public static < E > void printArray( E[] inputArray ) {
// Display array elements
for(E element : inputArray) {
System.out.printf("%s ", element);
}
System.out.println();
}
public static void main(String args[]) {
// Create arrays of Integer, Double and Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println("Array integerArray contains:");
printArray(intArray); // pass an Integer array
System.out.println("\nArray doubleArray contains:");
printArray(doubleArray); // pass a Double array
System.out.println("\nArray characterArray contains:");
printArray(charArray); // pass a Character array
}
}
خروجی برنامه بالا:
Array integerArray contains:
1 2 3 4 5
Array doubleArray contains:
1.1 2.2 3.3 4.4
Array characterArray contains:
H E L L O
پارامترهای با نوع محدود شده (Bounded)
مواقعی وجود دارد که شما می خواهید نوع داده هایی را که اجازه دارند به تابع Generic ارسال شوند محدود کنید. برای مثال، یک تابع که بر روی اعداد عملیات انجام می دهد، ممکن است بخواهد تنها داده هایی از نوع Number و یا کلاس های فرزند آن را قبول کند. دقیقا این دلیلی است که پارامتر های با نوع محدود شده ایجاد شده اند.
مثال
مثال زیر چگونگی کاربرد extends را با همان معانی extends و impletemen در کلاس نشان می دهد. این مثال یک تابع Generic است که بزرگترین مقدار قابل مقایسه را باز می گرداند:
public class MaximumTest {
// determines the largest of three Comparable objects
public static <T extends Comparable<T>> T maximum(T x, T y, T z) {
T max = x; // assume x is initially the largest
if(y.compareTo(max) > 0) {
max = y; // y is the largest so far
}
if(z.compareTo(max) > 0) {
max = z; // z is the largest now
}
return max; // returns the largest object
}
public static void main(String args[]) {
System.out.printf("Max of %d, %d and %d is %d\n\n",
3, 4, 5, maximum( 3, 4, 5 ));
System.out.printf("Max of %.1f,%.1f and %.1f is %.1f\n\n",
6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ));
System.out.printf("Max of %s, %s and %s is %s\n","pear",
"apple", "orange", maximum("pear", "apple", "orange"));
}
}
خروجی برنامه بالا:
Max of 3, 4 and 5 is 5
Max of 6.6,8.8 and 7.7 is 8.8
Max of pear, apple and orange is pear
کلاس های Generic
تعریف کلاس Generic مشابه تعریف کلاس معمولی است، به غیر آنکه قسمت نوع پارامتر بعد از نام کلاس می آید.
همانند توابع Generic قسمت نوع پارامتر کلاس Generic می تواند یک یا بیشتر باشد که توسط کاما از یکدیگر جدا می شوند. این کلاس ها را کلاس های پارامتری نیز می نامنند چرا که یک یا بیشتر پارامتر را قبول می کنند.
مثال
مثال زیر چگونگی تعریف یک کلاس Generic را نشان می دهد:
public class Box {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box integerBox = new Box();
Box stringBox = new Box();
integerBox.add(10);
stringBox.add(new String("Hello World"));
System.out.printf("Integer Value :%d\n\n", integerBox.get());
System.out.printf("String Value :%s\n", stringBox.get());
}
}
خروجی برنامه بالا:
Integer Value :10
String Value :Hello World