ClassNotFoundException לעומת NoClassDefFoundError

1. הקדמה

שניהם ClassNotFoundException ו NoClassDefFoundError להתרחש כאשר ה- JVM לא יכול למצוא מחלקה מבוקשת בשביל הכיתה. למרות שהם נראים מוכרים, ישנם כמה הבדלי ליבה בין שני אלה.

במדריך זה נדון בכמה מהסיבות להתרחשותן ולפתרונותיהן.

2. ClassNotFoundException

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

זה קורה בעיקר כשמנסים לטעון שיעורים באמצעות Class.forName (), ClassLoader.loadClass () אוֹ ClassLoader.findSystemClass (). לכן עלינו להקפיד במיוחד java.lang.ClassNotFoundException תוך כדי עבודה עם השתקפות.

לדוגמה, בואו ננסה לטעון את מחלקת הנהגים JDBC מבלי להוסיף תלות נחוצה שתביא אותנו ClassNotFoundException:

@Test (צפוי = ClassNotFoundException.class) חלל ציבורי givenNoDrivers_whenLoadDriverClass_thenClassNotFoundException () זורק ClassNotFoundException {Class.forName ("oracle.jdbc.driver.OracleDriver"); }

3. NoClassDefFoundError

NoClassDefFoundError זו שגיאה אנושה. זה קורה כאשר JVM לא יכול למצוא את ההגדרה של הכיתה בזמן שהוא מנסה:

  • מייצרים שיעור באמצעות חָדָשׁ מילת מפתח
  • טען כיתה עם שיחת שיטה

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

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

אם ננסה לטעון שוב את אותה הכיתה, נקבל את NoClassDefFoundError:

מחלקה ציבורית ClassWithInitErrors {נתונים סטטיים int = 1/0; }
מחלקה ציבורית NoClassDefFoundErrorExample {public ClassWithInitErrors getClassWithInitErrors () {ClassWithInitErrors test; נסה {test = new ClassWithInitErrors (); } לתפוס (לזרוק t) {System.out.println (t); } test = ClassWithInitErrors חדש (); מבחן החזרה; }}

בואו נכתוב מקרה מבחן לתרחיש זה:

@Test (צפוי = NoClassDefFoundError.class) חלל ציבורי givenInitErrorInClass_whenloadClass_thenNoClassDefFoundError () {NoClassDefFoundErrorExample sample = new NoClassDefFoundErrorExample (); sample.getClassWithInitErrors (); }

4. החלטה

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

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

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

5. סיכום

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

זמן ריצה של Java זורק ClassNotFoundException בזמן שניסה לטעון כיתה בזמן ריצה בלבד והשם סופק בזמן ריצה. במקרה של NoClassDefFoundError, ה- class היה נוכח בזמן הקומפילציה, אך זמן הריצה של Java לא הצליח למצוא אותו במסלול Java במהלך זמן הריצה.

כמו תמיד, ניתן למצוא את הקוד השלם לכל הדוגמאות ב- GitHub.