פורסם 2015 באוגוסט 1010 שנים שלום לכולם,יש לי בעיה אמיתית אני אתן דוגמה:יש לי מחלקה אבסטרקטית A.מתחתיה יש לי מחלקה רגילה B שיורשת אותה.לצידה של מחלקה B יש לי מחלקה אבסטרקטית C שיורשת גם היא את מחלקה A, ומתחת ל-C יש לי מחלקה רגילה D שיורשת את C.כל אלו נמצאות באותה ספרייה(יעני באותו חלון project בבלו-ג'יי, מקווה שאני משתמש במושג הנכון).באותה ספרייה אני פותח סתם מחלקה חדשה לגמרי, נגיד check.במחלקה check בפונק' הראשית public static void main(String[] args) אני יוצר משתנה(=אובייקט, עצם) מסוג B בשם objB ומשתנה מסוג D בשם objD.אח"כ אני כותב את התנאי if(objB instanceof C).בהגיון שלי הביטוי בתנאי אמור להחזיר false ולכן התנאי לא יתקיים, אבל במקום זה אני מקבל שגיאה בזמן ההידור:inconvertible typesrequired: D; found: Bאוקיי עכשיו לבעיה יותר מהותית:בנוסף להכל, יש לי עוד מחלקה רגילה שיורשת את A, נגיד sisterB.גם מתחת ל-C יש לי עוד מחלקה רגילה שיורשת אותה, נגיד sisterD.למחלקה C יש תכונה- איזשהו מספר savedNum מסוג int בהרשאת protected(כלומר שלכל המחלקות שיורשות את המחלקה C יש גישה אליו) שמייצג קצה של איזשהו טווח מספרים(שאותו כל המחלקות, כולל יורשות של A, יודעות כבר) אבל הוא משתנה כל הזמן ע"פ תנאי שתכף אגיד(זה מה שייחודי במחלקה C).למחלקה C יש פונק' get ו-set ל-savedNum הזה. שניהן בהרשאת public ככה שבוודאות לכל המחלקות שיורשות את מחלקה C יש גישה לפונק' האלה.לכל אחת מהמחלקות B, sisterB, D ו-sisterD יש פונק' שנקראת giveNum, שמגרילה מספר מסוג int בטווח המספרים הידוע הזה ומחזירה אותו(בפועל בספרייה שלי הטכניקה קצת שונה אבל פה זה לצורך העניין).אני יוצר מערך Aים בשם arr שכל תא בו הוא אובייקט מסוג B, sisterB, D או sisterD וכותב את הקוד הבא:int numFromUser;for(int i=0; i<arr.length; i++){ numFromUser=arr[i].giveNum(); for(int j=0; j<arr.length; j++) { if(arr[j] instanceof C) { if(numFromUser<((C)arr[j]).getSavedNum()) { arr[j].setSavedNum(numFromUser); } } }}אוקיי חבר'ה תודה על הסבלנות, עכשיו לבעיה-קודם כל, הפעם אין בעיה בזמן ההידור. אני מנחש שזה בגלל שהפעם אני רק בודק תאים במערך, ואז הבלו-ג'יי אומר שיכול להיות שיש במערך תאים שדווקא יגרמו לביטוי בתוך התנאי הראשון להיות true אז אין בעיה. הקטע הוא שגם כשהביטוי הזה אמור להיות false(נגיד תא שיש בו עצם מסוג B) אז הביטוי באמת שווה false והתנאי באמת לא מתקיים, ואין שגיאה בזמן ההידור כמו בהתחלה.העניין הוא כזה- כשאני מריץ את הקטע הזה, אין בעיה עם התנאי הראשון אבל יש בעיה עם התנאי השני.כשהמשתנה numFromUser מקבל ערך מהפונקציה giveNum() באחת המחלקות שיורשות את A חוץ מ-C(המחלקות B ו-sisterB), בזמן הריצה אני מקבל את השגיאהjava.lang.ClassCastException: B cannot be cast to C at check.main(check.java:|Line number|).יכול להיות גם sisterB במקום. ה-Line number זה המספר שורה של התנאי השני והמהדר מצביע עליה.אם הערך מתקבל מהפונקציה giveNum() באחת המחלקת D או sisterD הכל בסדר והפעולה בתוך התנאי השני מתקיימת.תודה, תומר. נערך 2015 באוגוסט 1010 שנים על-ידי LennonRulz
פורסם 2015 באוגוסט 1010 שנים לגבי הבעיה הראשונה - B ו-C שייכים לענפים שונים לחלוטין בהיררכיה, ולכן ההשוואה ביניהם נתפסת כשגיאה בעיני הקומפיילר. לעומת זאת, אם תגדיר:A objB = new B();השורהobjB instanceof Cתתקמפל כראוי, מכיוון שאובייקט מסוג A *יכול* להיות C- - - תגובה אוחדה: - - -לגבי השאלה השניה, אני לא רואה בעיה מיידית (חוץ מזה שבשורה שקוראת ל-set אין casting אז לא יכול להיות שהקוד שלך מתקמפל ככה סתם...)אם תוכל להראות את ההכרזה והאתחול של המערך זה יעזור למצוא מה הבעיה
פורסם 2015 באוגוסט 1010 שנים מחבר לגבי הבעיה הראשונה - B ו-C שייכים לענפים שונים לחלוטין בהיררכיה, ולכן ההשוואה ביניהם נתפסת כשגיאה בעיני הקומפיילר. לעומת זאת, אם תגדיר:A objB = new B();השורהobjB instanceof Cתתקמפל כראוי, מכיוון שאובייקט מסוג A *יכול* להיות C- - - תגובה אוחדה: - - -לגבי השאלה השניה, אני לא רואה בעיה מיידית (חוץ מזה שבשורה שקוראת ל-set אין casting אז לא יכול להיות שהקוד שלך מתקמפל ככה סתם...)אם תוכל להראות את ההכרזה והאתחול של המערך זה יעזור למצוא מה הבעיהוואלה תודה. רגע בעצם אם A היא מחלקה אבסטרקטית אז איך אפשר ליצור מערך של Aים?...וצודק עשיתי casting פשוט שכחתי לרשום בהודעה.בהכרזה פשוט ביקשתי מהמשתמש להכניס מס' ואז עשיתי מערך Aים בגודל של המספר שהוא הכניס.אח"כ עברתי על המערך תא-תא וביקשתי ממנו שיכניס מספר שייצג סוג אובייקט- 0 עבור B, אחד עבור sisterB וכן הלאה...import java.util.*;....static Scanner reader=new Scanner(System.in);....System.out.println("Enter number: ");int n=reader.nextInt();int type;A[] arr=new A[n];for(int i=0; i<arr.length; i++){ System.out.println("Enter type: "); switch(type) { case 0: new B(); break; case 1: new sisterB(); break; case 2: new D(); break; case 3: new sisterD(); break; }}
פורסם 2015 באוגוסט 1010 שנים אם תמשיך לכתוב כאן קוד שדומה לקוד שאתה באמת מריץ, לא באמת נמצא את הבעיה, אתה יודעA מחלקה אבסטרקטית, אבל אתה מאתחל מערך של אובייקטים מסוג A, כלומר אתה לא יוצר אובייקט קונקרטי מטיפוס A, אלא רק מערך. בתוך המערך אתה מכניס טיפוסים קונקרטיים כמו שהראית.
פורסם 2015 באוגוסט 1010 שנים אם כל האובייקטים במערך הם בנים של C אז למה אתה צריך לעשות CAST שאתה משתמש בפונקציה?אתה אמור להבין מהשגיאה (ומהקוד שלך) שאין לך אפשרות לעשות CAST מB לC כי הם אחיםאם לשניהם יש את הפונקציה הזאת (בין אם בתוך המחלקה עצמה או בהורשה מאב כלשהו) אז הפונקציה הזאת זמינה גם בלי לעשות CAST
פורסם 2015 באוגוסט 1010 שנים תבדיל בין אובייקט לבין instance (מופע) שלו. אתה יכול שמשתנה יהיה מסוג A אם A או אבסטרקטי או ממשק, אבל אתה לא יכול ליצור מופע שלו, כלומר אתה לא יכול לכתוב ()new Aזו בעצם המהות של פולימורפיזם וממשק. בדיוק כמו שאתה יכול לכתוב פונקציה שמקבלת List. אתה לא יודע באיזה List מדובר מאחר ו-List זה ממשק - אתה יודע שאתה ניגש לאיבר עם get למשל וכולי. אתה לא יודע אם זה LinkedList או ArrayList וגם לא מעניין אותך.
פורסם 2015 באוגוסט 1010 שנים מחבר אם תמשיך לכתוב כאן קוד שדומה לקוד שאתה באמת מריץ, לא באמת נמצא את הבעיה, אתה יודעA מחלקה אבסטרקטית, אבל אתה מאתחל מערך של אובייקטים מסוג A, כלומר אתה לא יוצר אובייקט קונקרטי מטיפוס A, אלא רק מערך. בתוך המערך אתה מכניס טיפוסים קונקרטיים כמו שהראית.האמת שזה קוד קצת גדול, אני מנסה לפתור את התרגיל במדריך הזה https://he.wikibooks.org/wiki/%D7%AA%D7%9B%D7%A0%D7%95%D7%AA_%D7%9E%D7%AA%D7%A7%D7%93%D7%9D_%D7%91-Java/%D7%A4%D7%95%D7%9C%D7%99%D7%9E%D7%95%D7%A8%D7%A4%D7%99%D7%96%D7%9D/%D7%AA%D7%A8%D7%92%D7%99%D7%9C%D7%99%D7%9Dהתחלתי ללמוד את הנושא לפני כמה ימים.בכל מקרה הנה כל המחלקות:מחלקה של המשחק: http://pastebin.com/y0G7kLRKמחלקה של שחקן באופן כללי: http://pastebin.com/i2YtpNqdמחלקה של שחקן מסוג בן אדם: http://pastebin.com/x8mdUGH6מחלקה של שחקן מסוג קוף: http://pastebin.com/TfMrZuewמחלקה של שחקן אינטליגנטי(שמסוגל לזכור טווח מספרים שהמספר נמצא בו, משהו שלא נמצא בתרגיל): http://pastebin.com/4gCD4rcXמחלקה של מחשב מהמר: http://pastebin.com/DgkdEAyZמחלקה של מחשב חכם: http://pastebin.com/VfvJXFV2עכשיו הבעיה קורה כשמגיע תורו של בן אדם/קוף לנחש מספר. הם מנחשים מספר והוא נשמר במשתנה playerGuess במחלקה Game. התכנית בודקת אם הוא גדול/קטן מהמספר שצריך לנחש, מדפיסה הודעה מתאימה ועוברת שוב פעם עם לולאה פנימית על המערך. כשהיא נתקלת בשחקן מסוג מחשב חכם או מחשב מהמר היא אמורה לשנות את קצוות טווח המספרים שלהם, אבל במקום זה היא מחזירה בזמן הריצה את השגיאהjava.lang.ClassCastException: Monkey cannot be cast to intelPlayer at Game.main(Game.java:93).הדבר הזה לא קורה כששחקן מסוג מחשב חכם או מחשב מהמר מנחש מספר.אם כל האובייקטים במערך הם בנים של C אז למה אתה צריך לעשות CAST שאתה משתמש בפונקציה?אתה אמור להבין מהשגיאה (ומהקוד שלך) שאין לך אפשרות לעשות CAST מB לC כי הם אחיםאם לשניהם יש את הפונקציה הזאת (בין אם בתוך המחלקה עצמה או בהורשה מאב כלשהו) אז הפונקציה הזאת זמינה גם בלי לעשות CASTכל האובייקטים במערך הם בנים/נכדים/צאצא כל שהוא של A לא של C.עכשיו, מה שאתה אומר נכון וגם אני חשבתי ככה, אבל ה-cast הזה בכל מקרה מתרחש רק אצל צאצאים של C(ע"פ התנאי) אז זה בסדר.בכל מקרה, בהתחלה גם אני ניסיתי להפעיל את הפונקציה getSavedNum() בלי לעשות cast אבל עדיין קיבלתי הודעה שהפונק' לא נמצאה במחלקה(למרות ש-D ו-sisterD בוודאות יורשים את C) וזה היה לי מוזר, אז בסוף קצת שיחקתי עם זה עד שגיליתי שזה עובד עם cast(דרך אגב עד עכשיו אני לא מבין למה אם תוכל להסביר לי אשמח).תבדיל בין אובייקט לבין instance (מופע) שלו. אתה יכול שמשתנה יהיה מסוג A אם A או אבסטרקטי או ממשק, אבל אתה לא יכול ליצור מופע שלו, כלומר אתה לא יכול לכתוב ()new Aזו בעצם המהות של פולימורפיזם וממשק. בדיוק כמו שאתה יכול לכתוב פונקציה שמקבלת List. אתה לא יודע באיזה List מדובר מאחר ו-List זה ממשק - אתה יודע שאתה ניגש לאיבר עם get למשל וכולי. אתה לא יודע אם זה LinkedList או ArrayList וגם לא מעניין אותך.רגע אבל פה אני בפירוש רשמתי new A[]. זה שזה מערך אומר שזה לא מופע של A? נערך 2015 באוגוסט 1010 שנים על-ידי LennonRulz
פורסם 2015 באוגוסט 1010 שנים מחבר תבדוק את האינדקסים בלולאה הפנימית אתה בסדר עם הקאסטינג לעעעעעעעעעעעעעעעעעעעעעע!!! חחח תותח! ענק עזרת לי מאוד תודה רבה. רגע אבל יש לי עכשיו שאלה אחרת שגם שאלתי קודם- למה בעצם זה מכריח אותי לעשות קאסטינג? אם אני עובר על המערך ומגיע לשחקן מסוג מחשב חכם או מחשב מהמר שיורשים את המחלקה של שחקן אינטליגנטי, למה אני לא יכול לעשות פשוט לעשות player[j].setTop(playerGuess)?
פורסם 2015 באוגוסט 1010 שנים תשנה את הכותרת של התראד ל"למה אנשים צריכים להדביק את הקוד המקורי והמלא מההתחלה"
פורסם 2015 באוגוסט 1010 שנים מחבר תשנה את הכותרת של התראד ל"למה אנשים צריכים להדביק את הקוד המקורי והמלא מההתחלה"האמת למדתי, כל יום לומדים משהו חדש.אבל בנוגע לקטע עם ה-cast, למה זה הכרחי? עדיין לא הבנתי כ"כ.
פורסם 2015 באוגוסט 1010 שנים כי הקומפיילר לא יודע ש-[player[j הוא מסוג IntelPlayer ושיש לו פונקציה בשם setTop. בזמן הקומפילציה הטיפוס של [player[j הוא רק Player.
פורסם 2015 באוגוסט 1110 שנים מחבר כי הקומפיילר לא יודע ש-[player[j הוא מסוג IntelPlayer ושיש לו פונקציה בשם setTop. בזמן הקומפילציה הטיפוס של [player[j הוא רק Player.אחלה תודה רבה לכל הגולשים אני מתחיל בנושא ועזרתם לי מאוד.יש לי אבל שאלה אחרת שעלתה בינתיים לא קשורה לירושה-שיניתי קצת את המחלקה גיים: http://pastebin.com/UZSmeYe7(שורה 92 ודומותיה). במקום לכתוב נגיד "Human instance of intelPlayer=false" זה כותב "Human@46a0e13e instanceof intelPlayer=false", ובמקום נגיד "GamblingComputer instanceof intelPlayer=true" זה כותב "GamblingComputer@239a6904 instanceof intelPlayer=true". הקטע שאחרי שם המחלקה(סימן @ והרצף מספרים ואותיות הזה) נשאר זהה עבור כל שחקן גם בניחושים של שאר השחקנים. מישהו יודע למה?ונגיד אני מכניס בשם של שחקן מסוים "יוסי" וזה אמור להדפיס:"שלום יוסי!......", זה מדפיס במקום "יוסי" ג'יבריש.אולי פשוט משהו במהדר עצמו(משתמש בבלו-ג'יי).תודה.
פורסם 2015 באוגוסט 1210 שנים כשאתה בא להדפיס אובייקט אז האובייקט מומר למחרוזת. כיוון שלתוכנה אין מושג איך אתה מצפה שהמחרוזת הזו תראה, יש איזה מימוש סטנדרטי (שם המחלקה + מזהה ייחודי למופע). אם אתה רוצה שההדפסה תתן משהו משמעותי אז אתה צריך לממש את הפונקציה toString.לגבי השם: באנגלית זה עובד? אם כן אז זה בעיה של קידוד. אתה צריך לומר ל-reader לעבוד ביוניקוד, דהיינו:reader = new Scanner(in, "UTF-8");
ארכיון
דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.