שאלת מבחן בתכנות מונחה עצמים - אוניברסיטת בר-אילן 2018 - איטרטורים
פליידרום הוא מחרוזת השווה להמחרוזות התחרוזתית של שלה.
נתנו הקטע הבא:
הפלט של הקטע הוא:
PALINDROMEEMORDNILAP
abccba
א. (4 נקודות) איזה משמעות משנעה המחלקה
ב. (16 נקודות) השווה את המחלקה
נתנו הקטע הבא:
הפלט של הקטע הוא:
PALINDROMEEMORDNILAP
abccba
א. (4 נקודות) איזה משמעות משנעה המחלקה
MyClass?ב. (16 נקודות) השווה את המחלקה
MyClass כך המחלקה או משנעה נוספים הדרושים. כדי לקבול את התנתנוגות המחזורות. שימו לב: הימנוש שלכם צריך לתשג כרוגות בתחזורה מעחרוזות זו הקילוע.העתק שאלה
שתף שאלה
סמן כחשוב
סמן כבוצע
אוניברסיטת בר-אילןמועד א2018סמסטר ב
★★★★★
איטרטוריםממשקיםגנריותמעקב אחר קודמחלקותאובייקטים
התחביר של לולאת for-each דורש שהמחלקה תממש את הממשק
Iterable. כדי לממש Iterable, יש להחזיר אובייקט Iterator מותאם אישית, אשר ינהל את המעבר על המחרוזת קדימה ואז אחורה.א. השאלה ככל הנראה מכוונת לשאול "איזה ממשק מממשת המחלקה
התשובה נובעת ישירות מהשימוש במחלקה בלולאת for-each (enhanced for-loop) בקוד הנתון:
ב. כדי להשיג את הפלט המבוקש (הדפסת המחרוזת ואחריה היפוכה), עלינו לממש את המחלקה
הסבר המימוש:
1. `MyClass` מממשת את `Iterable<Character>`. היא מכילה שדה
2. מתודת `iterator()` שנדרש לממש יוצרת ומחזירה מופע חדש של המחלקה הפנימית
3. `PalindromeIterator` מממשת את `Iterator<Character>` ואת הלוגיקה של המעבר הכפול על המחרוזת.
* היא שומרת מצב פנימי (אינדקס נוכחי) כדי לדעת היכן היא נמצאת באיטרציה.
*
*
להלן קוד המימוש המלא:
import java.util.Iterator;
import java.util.NoSuchElementException;
public class MyClass implements Iterable<Character> {
private String str;
public MyClass(String s) {
this.str = s;
}
@Override
public Iterator<Character> iterator() {
return new PalindromeIterator();
}
// מחלקה פנימית פרטית המממשת את האיטרטור
private class PalindromeIterator implements Iterator<Character> {
private int currentIndex;
private final int originalLength;
private final int totalLength;
public PalindromeIterator() {
this.currentIndex = 0;
this.originalLength = MyClass.this.str.length();
this.totalLength = this.originalLength * 2;
}
@Override
public boolean hasNext() {
return this.currentIndex < this.totalLength;
}
@Override
public Character next() {
if (!hasNext()) {
throw new NoSuchElementException("No more elements");
}
char c;
// החלק הראשון: המחרוזת המקורית
if (this.currentIndex < this.originalLength) {
c = MyClass.this.str.charAt(this.currentIndex);
}
// החלק השני: המחרוזת ההפוכה
else {
int reverseIndex = this.totalLength - 1 - this.currentIndex;
c = MyClass.this.str.charAt(reverseIndex);
}
this.currentIndex++;
return c;
}
}
}
MyClass?".התשובה נובעת ישירות מהשימוש במחלקה בלולאת for-each (enhanced for-loop) בקוד הנתון:
for(Character c : x). תחביר זה אפשרי רק אם המחלקה של האובייקט x (כלומר, MyClass) מממשת את הממשק `java.lang.Iterable`. מאחר שמשתנה הלולאה c הוא מטיפוס Character, המחלקה נדרשת לממש את הגרסה הגנרית של הממשק: `Iterable<Character>`. ממשק זה מחייב מימוש של מתודה יחידה, iterator(), המחזירה אובייקט מסוג Iterator<Character>.ב. כדי להשיג את הפלט המבוקש (הדפסת המחרוזת ואחריה היפוכה), עלינו לממש את המחלקה
MyClass כך שתחזיר איטרטור מותאם אישית. האיטרטור יעבור על תווי המחרוזת המקורית, ולאחר מכן ימשיך לעבור על תווי המחרוזת בסדר הפוך. דרך נוחה לממש זאת היא באמצעות מחלקה פנימית (inner class) פרטית.הסבר המימוש:
1. `MyClass` מממשת את `Iterable<Character>`. היא מכילה שדה
String לאחסון המחרוזת וקונסטרוקטור לאתחולו.2. מתודת `iterator()` שנדרש לממש יוצרת ומחזירה מופע חדש של המחלקה הפנימית
PalindromeIterator.3. `PalindromeIterator` מממשת את `Iterator<Character>` ואת הלוגיקה של המעבר הכפול על המחרוזת.
* היא שומרת מצב פנימי (אינדקס נוכחי) כדי לדעת היכן היא נמצאת באיטרציה.
*
hasNext(): מחזירה true כל עוד האינדקס הנוכחי קטן מהאורך הכולל של האיטרציה (פעמיים אורך המחרוזת המקורית).*
next(): בודקת אם האיטרציה נמצאת בחלק הראשון (המחרוזת המקורית) או בחלק השני (המחרוזת ההפוכה) ומחזירה את התו המתאים. עבור החלק השני, היא מחשבת את האינדקס המתאים במחרוזת המקורית כדי לדמות קריאה מהסוף להתחלה.להלן קוד המימוש המלא:
import java.util.Iterator;
import java.util.NoSuchElementException;
public class MyClass implements Iterable<Character> {
private String str;
public MyClass(String s) {
this.str = s;
}
@Override
public Iterator<Character> iterator() {
return new PalindromeIterator();
}
// מחלקה פנימית פרטית המממשת את האיטרטור
private class PalindromeIterator implements Iterator<Character> {
private int currentIndex;
private final int originalLength;
private final int totalLength;
public PalindromeIterator() {
this.currentIndex = 0;
this.originalLength = MyClass.this.str.length();
this.totalLength = this.originalLength * 2;
}
@Override
public boolean hasNext() {
return this.currentIndex < this.totalLength;
}
@Override
public Character next() {
if (!hasNext()) {
throw new NoSuchElementException("No more elements");
}
char c;
// החלק הראשון: המחרוזת המקורית
if (this.currentIndex < this.originalLength) {
c = MyClass.this.str.charAt(this.currentIndex);
}
// החלק השני: המחרוזת ההפוכה
else {
int reverseIndex = this.totalLength - 1 - this.currentIndex;
c = MyClass.this.str.charAt(reverseIndex);
}
this.currentIndex++;
return c;
}
}
}