آشنایی با تفاوت میان ClassNotFoundException و NoClassDefFoundError در جاوا

آشنایی با تفاوت میان ClassNotFoundException و NoClassDefFoundError در جاوا

همان‌طور که می‌دانید، زبان برنامه‌نویسی جاوا یک زبان شئ‌گرا یا به اصطلاح OO است و در این زبان تقریباً هر چیزی یک شیئ است؛ از سوی دیگر، برای ایجاد یک شیئ، نیاز به یک کلاس داریم. در حین ساخت کلاس‌ها در جاوا ممکن است با ارورها و اکسپشن‌های مختلفی روبه‌رو شویم که ۲ مورد از رایج‌ترین آن‌ها ClassNotFoundException و NoClassDefFoundError است که در این مقاله قصد داریم تفاوت مابین این دو را بررسی نماییم.

وقتی برنامهٔ نوشته شده را اجرا می‌کنیم، اگر کلاسی از قبل در حافظه بارگذاری نشده باشد، JVM (ماشین مجازی جاوا) آن‌را در حافظه بارگذاری می‌کند؛ مثلاً هنگامی که کد زیر اجرا می‌شود،‌ JVM قبل از این‌که شییٔ را از روی کلاس Employee ایجاد کند، باید بااستفاده از یک ClassLoader، کلاس Employee را بر روی حافظه بارگذاری نماید:

Employee emp = new Employee();

در این مثال، JVM کلاس‌مان را بر روی حافظه بارگذاری خواهد نمود زیرا این کلاس در مسیر اجرای کد قرار دارد و قرار است JVM از روی این کلاس، یک آبجکت بسازد.

همچنین می‌توانیم بااستفاده از نام کلاس در یکی از متدهای ()Class.forName()،‌ ClassLoader.findSystemClass و یا ()ClassLoader.loadClass از JVM بخواهیم که یک کلاس را فقط بارگذاری کند. به‌عنوان مثال، در کد زیر بدون این‌که عمل دیگری صورت بگیرد، کلاس Employee فقط بارگذاری خواهد شد:

Class.forName("Employee");

هم ClassNotFoundException و هم NoClassDefFoundError هنگامی رخ می‌دهند که در حین اجرای کد، یک کلاس خاص پیدا نمی‌شود، اما ماجرای رخ دادن این دو با هم متفاوت است که در ادامه این موضوع را مورد بررسی قرار خواهیم داد.

ClassNotFoundException
این اکسپشن زمانی رخ می‌دهد که ما با وارد کردن نام استرینگی کلاس در یکی از متدهای ()Class.forName()،‌ ClassLoader.findSystemClass و یا ()ClassLoader.loadClass از JVM می‌خواهیم تا کلاسی را بارگذاری نماید اما کلاس مورد نظر در مسیری که انتظار می‌رود باشد یافت نمی‌شود!

اجرای برنامه بدون به‌روزرسانی classpath در فایل JAR،‌ یکی از رایج‌ترین دلایل ایجاد این اکسپشن است؛ به‌عنوان مثال، هنگامی که کد JDBC را برای اتصال به دیتابیس خود (مثلاً MySQL) اجرا می‌کنید، در‌حالی‌که classpath شما فایل JAR آ‌ن‌را ندارد،‌ ClassNotFoundException رخ خواهد داد (کد JDBC یا Java Database Connectivity،‌ یکی از APIهای زبان برنامه‌نویسی جاوا است که چگونگی دسترسی به دیتابیس را تعریف می‌کند.)

برای روشن‌تر شدن این مسئله، به مثال زیر دقت کنید؛ اگر این کد را کامپایل کنیم، کامپایلر ۲ کلاس‌فایل ایجاد خواهد کرد که عبارتند از Test.class و Person.class. اکنون اگر این کد کامپایل شده را اجرا کنیم، همان‌طور که انتظار می‌رود کلمهٔ Hello چاپ خواهد شد اما اگر فایل Person.class را حذف نموده و مجدداً کد را اجرا کنیم،‌ این بار با ClassNotFoundException مواجه خواهیم شد:

public class Test {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("Person");
        Person person = (Person) clazz.newInstance();
        person.saySomething();
    }
}
class Person {
    void saySomething() {
        System.out.println("Hello");
    }
}

NoClassDefFoundError
این ارور یکی از زیرشاخه‌های java.lang.Error است؛ این گروه از خطاها تنها در حین استفاده از JVM ممکن است رخ بدهد. خطای NoClassDefFoundError هنگامی رخ می‌دهد که JVM در تلاش است تا یک کلاس خاص -به‌عنوان بخشی از فراخوانی متدهای معمول و یا بخشی از فرآیند ایجاد یک Instance با استفاده از کلمهٔ‌ کلیدی new- را در حافظه بارگذاری کند اما کلاس مورد نظر در classpath وجود ندارد در‌حالی‌که در زمان کامپایل نمودن کد،‌ این کلاس وجود داشته است.

اگر بخواهید کد خود را اجرا کنید باید آن را کامپایل کنید و اگر در این میان از کلاسی استفاده کرده باشید که دیگر وجود ندارد، با خطای کامپایل مواجه خواهید شد؛ مشابه آنچه که در مورد مثال قبل گفته شد،‌ با اجرای کد زیر نیز ۲ کلاس‌فایل برای ما ایجاد خواهد شد (Test.class و Employee.class) و با اجرای کد،‌ کلمهٔ‌ Hello چاپ خواهد شد:

public class Test {
    public static void main(String[] args) throws Exception {
        Employee emp = new Employee();
        emp.saySomething();
    }
}
class Employee {
    void saySomething() {
        System.out.println("Hello");
    }
}

اما اگر فایل Employee.class را حذف نموده و برنامه را دوباره اجرا کنیم،‌ با خطای NoClassDefFoundError مواجه خواهیم شد:

Exception in thread "main" java.lang.NoClassDefFoundError: Employee
 at Test.main(Test.java:9)
Caused by: java.lang.ClassNotFoundException: Employee
 at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
 ... 1 more

همان‌طور که در مثال فوق مشاهده کردیم، ClassNotFoundException است که موجب می‌شود NoClassDefFoundError رخ دهد زیرا JVM قادر نیست کلاس را در مسیر مورد نظر پیدا کند.

منبع


رائفه خلیلی