نوع پارامتریشدهی زیر را در نظر بگیرید:
class Pair<K, V> {
private K key;
private V value;
public Pair(K key, V value) {
this.key = key;
this.value = value;
}
// ...
}
هنگام ایجاد شی Pair، نمیتوانید نوع اولیه را جایگزین Type Parameter K یا V کنید:
Pair<int, char> p = new Pair<>(8, 'a'); // compile-time error
فقط میتوانید انواع غیراولیه را برای Type Parameterهای K و V جایگزین کنید:
Pair<Integer, Character> p = new Pair<>(8, 'a');
توجه کنید کامپایلر جاوا 8 را به Integer.valueOf(8) و 'a' را به Character('a') Autobox میکند:
Pair<Integer, Character> p = new Pair<>(Integer.valueOf(8), new Character('a'));
برای اطلاعات بیشتر درباره Autoboxing، بخش Autoboxing و Unboxing را ببینید.
نمیتوانید از Type Parameter نمونه ایجاد کنید. مثلاً کد زیر خطای زمان کامپایل ایجاد میکند:
public static <E> void append(List<E> list) {
E elem = new E(); // compile-time error
list.add(elem);
}
به عنوان راهحل، میتوانید از طریق Reflection شیای از Type Parameter ایجاد کنید:
public static <E> void append(List<E> list, Class<E> cls) throws Exception {
E elem = cls.newInstance(); // OK
list.add(elem);
}
متد append() را میتوانید به این صورت فراخوانی کنید:
List<String> ls = new ArrayList<>();
append(ls, String.class);
---
فیلد static یک کلاس، متغیر سطحکلاسی است که توسط تمام اشیای غیرثابت کلاس به اشتراک گذاشته میشود. بنابراین فیلدهای static از نوع Type Parameter مجاز نیستند. کلاس زیر را در نظر بگیرید:
public class MobileDevice<T> {
private static T os;
// ...
}
اگر فیلدهای static از نوع Type Parameter مجاز بودند، کد زیر گیجکننده میشد:
MobileDevice<Smartphone> phone = new MobileDevice<>();
MobileDevice<Pager> pager = new MobileDevice<>();
MobileDevice<TabletPC> pc = new MobileDevice<>();
چون فیلد static os توسط phone، pager و pc به اشتراک گذاشته شده، نوع واقعی os چیست؟ نمیتواند همزمان Smartphone، Pager و Type PC باشد. بنابراین نمیتوان فیلدهای static از نوع Type Parameter ایجاد کرد.
چون کامپایلر جاوا تمام Type Parameterها در کد Generic را حذف میکند، نمیتوانید تأیید کنید چه نوع پارامتریشدهای از نوع Generic در زمان اجرا استفاده میشود:
public static <E> void rtti(List<E> list) {
if (list instanceof ArrayList<Integer>) { // compile-time error
// ...
}
}
مجموعهی انواع پارامتریشدهی ارسالشده به متد rtti():
S = { ArrayList<Integer>, ArrayList<String>, LinkedList<Character>, ... }
زمان اجرا Type Parameterها را ردیابی نمیکند، پس نمیتواند تفاوت ArrayList<Integer> و ArrayList<String> را تشخیص دهد. بیشترین کاری که میتوانید انجام دهید استفاده از Wildcard بدون حد برای تأیید اینکه لیست ArrayList است:
public static void rtti(List<?> list) {
if (list instanceof ArrayList<?>) { // OK; instanceof requires a reifiable type
// ...
}
}
معمولاً نمیتوانید به نوع پارامتریشده Cast کنید مگر اینکه با Wildcards بدون حد پارامتری شده باشد. مثال:
List<Integer> li = new ArrayList<>();
List<Number> ln = (List<Number>) li; // compile-time error
اما در برخی موارد کامپایلر میداند Type Parameter همیشه معتبر است و Cast را مجاز میداند. مثال:
List<String> l1 = ...;
ArrayList<String> l2 = (ArrayList<String>)l1; // OK
---
نمیتوانید آرایههایی از انواع پارامتریشده ایجاد کنید. مثلاً کد زیر کامپایل نمیشود:
List<Integer>[] arrayOfLists = new List<Integer>[2]; // compile-time error
کد زیر نشان میدهد چه اتفاقی میافتد وقتی نوعهای مختلف در آرایه درج شوند:
Object[] strings = new String[2];
strings[0] = "hi"; // OK
strings[1] = 100; // An ArrayStoreException is thrown.
اگر همین کار را با لیست Generic امتحان کنید، مشکلی پیش میآید:
Object[] stringLists = new List<String>[2]; // compiler error, but pretend it's allowed
stringLists[0] = new ArrayList<String>(); // OK
stringLists[1] = new ArrayList<Integer>(); // An ArrayStoreException should be thrown,
// but the runtime can't detect it.
اگر آرایههایی از لیستهای پارامتریشده مجاز بودند، کد قبلی ArrayStoreException مورد انتظار را پرتاب نمیکرد.
کلاس Generic نمیتواند مستقیماً یا غیرمستقیماً از کلاس Throwable ارث ببرد. مثلاً کلاسهای زیر کامپایل نخواهند شد:
// Extends Throwable indirectly
class MathException<T> extends Exception { /* ... */ } // compile-time error
// Extends Throwable directly
class QueueFullException<T> extends Throwable { /* ... */ // compile-time error
متد نمیتواند از Type Parameter نمونه Catch کند:
public static <T extends Exception, J> void execute(List<J> jobs) {
try {
for (J job : jobs)
// ...
} catch (T e) { // compile-time error
// ...
}
}
اما میتوانید Type Parameter را در عبارت throws استفاده کنید:
class Parser<T extends Exception> {
public void parse(File file) throws T { // OK
// ...
}
}
---
کلاس نمیتواند دو متد Overload شده داشته باشد که بعد از Type Erasure signature یکسانی داشته باشند.
public class Example {
public void print(Set<String> strSet) { }
public void print(Set<Integer> intSet) { }
}
Overloadها همگی نمایندهی کلاس فایل یکسانی خواهند داشت و خطای زمان کامپایل تولید خواهند کرد.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/