יצירת מערך כללי בג'אווה

1. הקדמה

ייתכן שנרצה להשתמש במערכים כחלק משיעורים או פונקציות התומכות בגנריות. בגלל הדרך שבה ג'אווה מטפלת בגנריות, זה יכול להיות קשה.

במדריך זה נבין את האתגרים של שימוש בגנריות עם מערכים. לאחר מכן ניצור דוגמה למערך כללי.

נבדוק גם היכן פיתחה בעיה דומה ב- Java API.

2. שיקולים בעת שימוש במערכים כלליים

הבדל חשוב בין מערכים וגנריים הוא האופן בו הם אוכפים בדיקת סוגים. באופן ספציפי, מערכים מאחסנים ובודקים מידע על סוג בזמן ריצה. עם זאת, כלליות כלליות בודקות אם קיימות שגיאות סוג בזמן הקומפילציה ואין להן מידע על סוג בזמן הריצה.

התחביר של Java מציע שאולי נוכל ליצור מערך כללי חדש:

T [] אלמנטים = T חדש [גודל];

אבל אם ננסה זאת, נקבל שגיאת הידור.

כדי להבין מדוע, נבחן את הדברים הבאים:

ציבורי T [] getArray (גודל int) {T [] genericArray = T חדש [גודל]; // נניח שזה מותר להחזיר genericArray; }

כסוג כללי לא מאוגד ט פותר ל לְהִתְנַגֵד, השיטה שלנו בזמן ריצה תהיה:

אובייקט ציבורי [] getArray (int גודל) {Object [] genericArray = אובייקט חדש [size]; להחזיר genericArray; }

ואז, אם נקרא לשיטה שלנו ונשמור את התוצאה ב- חוּט מַעֲרָך:

מחרוזת [] myArray = getArray (5);

הקוד יצטבר בסדר אך ייכשל בזמן הריצה עם ClassCastException. הסיבה לכך היא שזה עתה הקצענו לְהִתְנַגֵד[] אל א חוּט[] התייחסות. באופן ספציפי, צוות משתמע של המהדר לא יצליח להמיר לְהִתְנַגֵד[] לסוג הנדרש שלנו חוּט[].

למרות שאיננו יכולים לאתחל מערכים גנריים ישירות, עדיין ניתן להשיג את הפעולה המקבילה אם סוג המידע המדויק מסופק על ידי קוד ההתקשרות.

3. יצירת מערך גנרי

לדוגמא שלנו, בואו ניקח בחשבון מבנה נתוני מחסנית מוגבל MyStack, שם הקיבולת קבועה לגודל מסוים. כמו כן, מכיוון שהיינו רוצים שהערימה תעבוד עם כל סוג שהוא, אפשרות יישום סבירה תהיה מערך כללי.

ראשית, בואו ניצור שדה לאחסון מרכיבי הערימה שלנו, שהוא מערך כללי מסוג ה:

אלמנטים פרטיים של E [];

שנית, בואו נוסיף קונסטרוקטור:

MyStack ציבורי (clazz class, int קיבולת) {elements = (E []) Array.newInstance (clazz, capacity); }

שים לב איך אנו משתמשים java.lang.reflect.Array # newInstance לאתחל את המערך הגנרי שלנו, הדורש שני פרמטרים. הפרמטר הראשון מציין את סוג האובייקט בתוך המערך החדש. הפרמטר השני מציין כמה מקום ליצור למערך. כתוצאה של מערך # חדשInstance הוא מסוג לְהִתְנַגֵד, אנחנו צריכים ללהק את זה ל E [] כדי ליצור את המערך הגנרי שלנו.

עלינו לציין את המוסכמה של מתן שמות לפרמטר סוג clazz ולא מעמד, שהיא מילה שמורה בג'אווה.

4. שוקל רשימת מערך

4.1. באמצעות רשימת מערך במקום מערך

לעתים קרובות קל יותר להשתמש בגנרית רשימת מערך במקום מערך כללי. בואו נראה איך נוכל לשנות MyStack להשתמש ב- רשימת מערך.

ראשית, בואו ניצור שדה לאחסון האלמנטים שלנו:

אלמנטים פרטיים של רשימה;

שנית, בבנאי הערימות שלנו, אנו יכולים לאתחל את ה- רשימת מערך עם קיבולת ראשונית:

אלמנטים = ArrayList חדש (קיבולת);

זה הופך את הכיתה שלנו לפשוטה יותר, מכיוון שאיננו צריכים להשתמש בבבואה. כמו כן, איננו נדרשים לעבור בכיתה מילולית בעת יצירת הערימה שלנו. לבסוף, שכן אנו יכולים להגדיר את הקיבולת הראשונית של רשימת מערך, אנו יכולים לקבל את אותם היתרונות כמו מערך.

לכן, עלינו לבנות מערכים של גנריות רק במצבים נדירים או כאשר אנו מתקשרים עם ספרייה חיצונית כלשהי הדורשת מערך.

4.2. רשימת מערך יישום

מעניין, רשימת מערך עצמו מיושם באמצעות מערכים כלליים. בואו נציץ פנימה רשימת מערך לראות איך.

ראשית, בואו נראה את שדה רכיבי הרשימה:

אובייקט חולף [] elementData;

הודעה רשימת מערך שימושים לְהִתְנַגֵד כסוג האלמנט. מכיוון שהסוג הגנרי שלנו אינו ידוע עד זמן הריצה, לְהִתְנַגֵד משמש כמעמד העל מכל סוג שהוא.

ראוי לציין שכמעט כל הפעולות ב רשימת מערך יכולים להשתמש במערך הגנרי הזה מכיוון שהם לא צריכים לספק מערך שהוקלד מאוד לעולם החיצון, למעט שיטה אחת - toArray!

5. בניית מערך מאוסף

5.1. דוגמא ל- LinkedList

בואו נסתכל על שימוש במערכים כלליים בממשק ה- API של Java Collections, שם נבנה מערך חדש מאוסף.

ראשית, בואו ניצור חדש רשימה מקושרת עם טיעון טיפוסי חוּט והוסף אליו פריטים:

פריטי רשימה = LinkedList חדש (); items.add ("פריט ראשון"); items.add ("פריט שני"); 

שנית, בואו לבנות מערך של הפריטים שהוספנו זה עתה:

מחרוזת [] itemsAsArray = items.toArray (מחרוזת חדשה [0]);

כדי לבנות את המערך שלנו, את רשימה.toArray השיטה דורשת מערך קלט. היא משתמשת במערך זה אך ורק כדי לקבל את מידע הסוג ליצירת מערך החזרה מהסוג הנכון.

בדוגמה שלנו לעיל, השתמשנו מחרוזת חדשה [0] כמערך הקלט שלנו לבניית התוצאה חוּט מַעֲרָך.

5.2. LinkedList.toArray יישום

בואו נציץ פנימה LinkedList.toArray, כדי לראות כיצד הוא מיושם ב- Java JDK.

ראשית, בואו נסתכל על חתימת השיטה:

ציבורי T [] toArray (T [] a)

שנית, בואו נראה כיצד נוצר מערך חדש בעת הצורך:

a = (T []) java.lang.reflect.Array.newInstance (a.getClass (). getComponentType (), size);

שימו לב איך זה עושה שימוש מערך # חדשInstance לבנות מערך חדש, כמו בדוגמת הערימה שלנו קודם. כמו כן, שימו לב לאופן הפרמטר א משמש כדי לספק סוג ל- מערך # חדשInstance. לבסוף, התוצאה מ מערך # חדשInstance הוא יצוק ל T [] ליצור מערך כללי.

6. מסקנה

במאמר זה בדקנו לראשונה את ההבדלים בין מערכים וגנריים, ואחריו דוגמה ליצירת מערך גנרי. לאחר מכן, הראינו כיצד משתמשים ב- רשימת מערך עשוי להיות קל יותר משימוש במערך כללי. לבסוף בדקנו גם את השימוש במערך כללי בממשק ה- API של Collections.

כמו תמיד, קוד הדוגמה זמין ב- GitHub.