«نوع جنریک» یک کلاس یا رابط جنریک است که روی انواع پارامتری شده است. این کار به کامپایلر اجازه میدهد ایمنی نوع را روی کلاس یا رابط اعمال کند.
این رابط غیرجنریک Container را در نظر بگیرید:
class Container {
private Object object;
public void set(Object object) { this.object = object; }
public Object get() { return object; }
}
چون انواع Object را میپذیرد و برمیگرداند، با هر نوع غیراولیه کار میکند. اما این کار هزینه هم دارد: ممکن است بخشی از کد get را با انتظار Integer فراخوانی کند، در حالی که بخشی دیگر set را برای افزودن String فراخوانی میکند. نتیجه، یک استثنای زمان اجرا است.
یک «کلاس جنریک» و «رابط جنریک» قالب زیر را دارند:
class ClassName<T1, T2, ..., Tn> { ... }
interface InterfaceName<T1, T2, ..., Tn> { ... }
بخش پارامترهای نوع که با علامتهای کوچکتر و بزرگتر (<>) مشخص میشود و بعد از اسم کلاس یا رابط میآید، پارامترهای نوع را تعیین میکند: T1، T2، ... و Tn (به اینها متغیرهای نوع هم میگویند). میتوان از این پارامترها در بدنهی کلاس یا رابط استفاده کرد تا ایمنی نوع جنریک به دست آید.
این هم نسخهی جنریک Container است:
class Container<E> {
private E object;
public void set(E object) { this.object = object; }
public E get() { return object; }
}
هنگام ساختن آن، حالا باید اعلام کنیم چه نوعی را نگه میدارد و کامپایلر همان محدودیت را اعمال میکند:
// empty <> can infer from context
Container<String> stringContainer = new Container<>();
// compiler knows this is a String, so it is allowed
stringContainer.set("Some string");
// no cast needed, compiler knows it is a String
String result = stringContainer.get();
// this causes a compiler error:
stringContainer.set(42);
لیستها در جاوا مجموعهای هستند که عناصر را بهصورت دنبالهای مرتب نگه میدارند. برخلاف آرایهها، یک List میتواند بزرگتر شود تا هر تعداد عنصر را در خود جای دهد. یکی از پیادهسازیهای استاندارد، ArrayList است که بر پایهی یک آرایهی قابل تغییر اندازه ساخته شده است. پیادهسازی استاندارد دیگر، کلاس LinkedList است که بر پایهی یک لیست پیوندی دوطرفه ساخته شده است.
Listها میتوانند خالی باشند یا هر تعداد عنصری را نگه دارند (حتی عناصر تکراری). Listها یک رابط جنریک هستند که نوعشان نشان میدهد چه نوع اشیایی را میتوانند در خود داشته باشند. برای مثال:
List<String> emptyListOfStrings = List.of();
List<Integer> singleInteger = List.of(1);
List<Boolean> threeBooleans = List.of(true, false, true);
List<Object> listWithMultipleTypes = List.of("hello", 1, true);
Listها متدهای مفیدی برای افزودن، حذف کردن، گرفتن و بررسی حضور یک عنصر دارند:
List<Character> vowels = new ArrayList<>(List.of('a', 'e', 'i', 'o', 'i', 'e', 'a'));
int startingSize = vowels.size(); // 7
vowels.add('u'); // vowels is now ['a', 'e', 'i', 'o', 'i', 'e', 'a', 'u']
char a = vowels.get(0); // 'a'
boolean hadI = vowels.remove('i'); // true and vowels is now ['a', 'e', 'o', 'i', 'e', 'a', 'u']
boolean hasI = vowels.contains('i'); // true (still have one more left)
کارل میخواهد فهرستی از زبانهایی را که میخواهد در وبسایت Exercism یاد بگیرد پیگیری کند. کارل باید بتواند زبانهای تازه اضافه کند، زبانهای قدیمی را حذف کند و بررسی کند که آیا زبانهای خاصی در فهرست هستند یا نه. اگر کارل بخواهد Java یا Kotlin یاد بگیرد، خیلی هیجانانگیز میشود!
کارل باید بداند که آیا فهرست زبانهایش روزی خالی میشود تا بتواند برود زبانهای بیشتری برای یادگیری پیدا کند!
متدی به اسم isEmpty تعریف کنید که اگر هیچ زبانی در فهرست نباشد، true برمیگرداند.
if (languageList.isEmpty()) {
findMoreLanguagesToLearn();
}
کارل بیصبرانه منتظر یادگیری Kotlin و Python است!
به کارل کمک کنید تا شروع کند و متدی به اسم addLanguage تعریف کنید که زبان مورد نظرش را میگیرد و آن را به فهرست اضافه میکند.
languageList.addLanguage("Kotlin");
languageList.addLanguage("Python");
کارل تصمیم گرفته است که فعلاً نمیخواهد Scala یاد بگیرد.
به کارل کمک کنید تا آن را از فهرست حذف کند؛ برای این کار متدی به اسم removeLanguage تعریف کنید که زبانی را که دارد حذف میکند میگیرد و آن را از فهرست برمیدارد.
languageList.removeLanguage("Scala");
کارل میخواهد اولین زبانی را که به فهرست اضافه کرده (و هنوز در فهرست هست) به خاطر بسپارد.
متدی به اسم firstLanguage تعریف کنید که اولین زبان در فهرست را برمیگرداند.
String kotlin = languageList.firstLanguage(); // "Kotlin"
کارل باید بداند که چند زبان را میخواهد یاد بگیرد.
به کارل کمک کنید تا جواب را پیدا کند؛ برای این کار متدی به اسم count تعریف کنید که تعداد زبانهای فهرست را برمیگرداند.
int two = languageList.count(); // 2
کارل میخواهد یادش بیاید که میخواست Python یاد بگیرد یا Ruby.
متدی به اسم containsLanguage تعریف کنید که زبانی را که دربارهاش میپرسد میگیرد تا کارل بتواند جواب را بفهمد!
boolean learningPython = languageList.containsLanguage("Python"); // true
boolean learningRuby = languageList.containsLanguage("Ruby"); // false
اگر کارل بخواهد Java یا Kotlin یاد بگیرد، این خیلی هیجانانگیز است!
متدی به اسم isExciting تعریف کنید که اگر کارل بخواهد Java یا Kotlin یاد بگیرد، true برمیگرداند.
javaLanguageList.isExciting() // true
neitherKotlinNorJavaLanguageList.isExciting() // false