النوع الجنيس هو صنف أو واجهة جنيسة مُعاملة على أنواع. وهذا يسمح للمترجم بفرض أمان الأنواع على الصنف أو الواجهة.
خذ بعين الاعتبار واجهة 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);
القوائم هي المجموعة المتسلسلة المرتبة في Java.
وعلى خلاف المصفوفات، تستطيع List أن تنمو في الحجم لتستوعب أي عدد من العناصر.
ومن التطبيقات القياسية ArrayList، وهي مدعومة بمصفوفة قابلة لتغيير حجمها.
ومن التطبيقات القياسية أيضًا صنف LinkedList، وهو مدعوم بقائمة مترابطة مزدوجة.
قد تكون القوائم فارغة أو تحمل أي عدد من العناصر (بما في ذلك العناصر المكررة). والقوائم هي واجهة جنيسة تُحدَّد بنوع لتشير إلى نوع الكائنات التي يمكن أن تحتوي عليها. على سبيل المثال:
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<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)
Karl يريد متابعة مصفوفة من اللغات ليتعلّمها على موقع Exercism. يحتاج Karl إلى أن يكون قادرًا على إضافة لغات جديدة، وحذف لغات قديمة، والتحقق مما إذا كانت لغات معيّنة موجودة في المصفوفة. سيكون أمرًا مثيرًا جدًا أن يريد Karl تعلّم Java أو Kotlin!
يحتاج Karl إلى معرفة ما إذا كانت مصفوفة لغاته ستفرغ يومًا ما، حتى يذهب للبحث عن المزيد ليتعلّمها!
عرّف طريقة باسم isEmpty تُرجع true إذا لم تكن هناك أي لغات في المصفوفة.
if (languageList.isEmpty()) {
findMoreLanguagesToLearn();
}
يتطلع Karl إلى تعلّم Kotlin وPython!
ساعد Karl على البدء بتعريف طريقة باسم addLanguage تأخذ اللغة التي يريد تعلّمها وتضيفها إلى المصفوفة.
languageList.addLanguage("Kotlin");
languageList.addLanguage("Python");
قرّر Karl أنه لا يريد تعلّم Scala الآن.
ساعد Karl على حذفها من المصفوفة بتعريف طريقة باسم removeLanguage تأخذ اللغة التي يحذفها وتحذفها من المصفوفة.
languageList.removeLanguage("Scala");
يريد Karl أن يتذكّر أول لغة أضافها إلى المصفوفة (والتي ما زالت في المصفوفة).
عرّف طريقة باسم firstLanguage تُرجع أول لغة في المصفوفة.
String kotlin = languageList.firstLanguage(); // "Kotlin"
يحتاج Karl إلى معرفة عدد اللغات التي يحاول تعلّمها.
ساعد Karl على إيجاد الإجابة بتعريف طريقة باسم count تُرجع عدد اللغات في المصفوفة.
int two = languageList.count(); // 2
يحاول Karl أن يتذكّر ما إذا كان يريد تعلّم Python أو Ruby.
عرّف طريقة باسم containsLanguage تأخذ اللغة التي يسأل عنها حتى يعرف Karl الإجابة!
boolean learningPython = languageList.containsLanguage("Python"); // true
boolean learningRuby = languageList.containsLanguage("Ruby"); // false
إذا أراد Karl تعلّم Java أو Kotlin، فهذا مثير جدًا!
عرّف طريقة باسم isExciting تُرجع صحيحًا إذا أراد Karl تعلّم Java أو Kotlin.
javaLanguageList.isExciting() // true
neitherKotlinNorJavaLanguageList.isExciting() // false
سجّل في Exercism لتتعلّم وتتقن Java عبر 26 مفهومًا158 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.