สาเหตุและความแตกต่างระหว่าง NoClassDefFoundError และ ClassNotFoundException คืออะไร


371

ความแตกต่างระหว่างNoClassDefFoundErrorและClassNotFoundExceptionคืออะไร?

อะไรทำให้พวกเขาถูกโยนทิ้ง? พวกเขาจะแก้ไขได้อย่างไร?

ฉันมักจะพบข้อผิดพลาดเหล่านี้เมื่อแก้ไขรหัสที่มีอยู่เพื่อรวมไฟล์ jar ใหม่ ฉันได้กดพวกเขาทั้งฝั่งไคลเอ็นต์และฝั่งเซิร์ฟเวอร์สำหรับแอป java ที่แจกจ่ายผ่านเว็บสตาร์ต

เหตุผลที่เป็นไปได้ที่ฉันเจอ:

  1. แพ็คเกจไม่รวมอยู่ในbuild.xmlรหัสฝั่งไคลเอ็นต์
  2. classpath รันไทม์ที่ขาดหายไปสำหรับไหใหม่ที่เราใช้อยู่
  3. เวอร์ชันขัดแย้งกับ jar ก่อนหน้า

เมื่อฉันพบสิ่งเหล่านี้ในวันนี้ฉันใช้วิธีการตามรอยและคลาดเคลื่อนเพื่อให้สิ่งต่าง ๆ ทำงานได้ ฉันต้องการความชัดเจนและความเข้าใจมากขึ้น


ฉันมักจะพบว่าการใช้ JVM ด้วยความช่วยเหลือ-verbose(เช่น-verbose:class -verbose:jni) - แต่รายงาน mogsie ด้านล่างคำตอบของพวกเขาว่านี่ไม่ได้ให้ข้อมูลที่เป็นประโยชน์เพิ่มเติม :(
PJTraill

คำตอบ:


388

ความแตกต่างจากข้อมูลจำเพาะ Java API มีดังนี้

สำหรับClassNotFoundException:

ส่งออกมาเมื่อแอปพลิเคชันพยายามโหลดในคลาสผ่านชื่อสตริงโดยใช้:

  • วิธีการในชั้นเรียนforNameClass
  • วิธีการในชั้นเรียนfindSystemClassClassLoader
  • วิธีการในชั้นเรียนloadClassClassLoader

แต่ไม่พบคำจำกัดความของคลาสที่มีชื่อที่ระบุ

สำหรับNoClassDefFoundError:

โยนถ้า Java Virtual Machine หรือClassLoaderอินสแตนซ์พยายามโหลดในคำจำกัดความของคลาส (เป็นส่วนหนึ่งของการเรียกเมธอดปกติหรือเป็นส่วนหนึ่งของการสร้างอินสแตนซ์ใหม่โดยใช้นิพจน์ใหม่) และไม่พบคำจำกัดความของคลาส

คำจำกัดความคลาสค้นหาสำหรับมีอยู่เมื่อคอมไพล์คลาสที่กำลังดำเนินการอยู่ในปัจจุบัน แต่ไม่สามารถหานิยามได้อีกต่อไป

ดังนั้นจึงปรากฏว่าNoClassDefFoundErrorเกิดขึ้นเมื่อแหล่งรวบรวมเรียบร้อยแล้ว แต่ที่ runtime classไม่พบไฟล์ที่ต้องการ นี่อาจเป็นสิ่งที่สามารถเกิดขึ้นได้ในการแจกจ่ายหรือการผลิตไฟล์ JAR โดยที่ไม่classรวมไฟล์ที่จำเป็นทั้งหมด

สำหรับClassNotFoundExceptionดูเหมือนว่ามันอาจเกิดจากการพยายามโทรกลับไปยังคลาสที่รันไทม์ แต่คลาสที่โปรแกรมกำลังพยายามโทรไม่มีอยู่

ความแตกต่างระหว่างทั้งสองเป็นที่หนึ่งเป็นErrorและอื่น ๆ Exceptionที่เป็น ด้วยNoClassDefFoundErrorเป็นErrorและมันเกิดขึ้นจาก Java Virtual Machine มีปัญหาในการหาชั้นเรียนที่คาดว่าจะหา โปรแกรมที่คาดว่าจะทำงานในเวลาคอมไพล์ไม่สามารถรันได้เนื่องจากclassไม่พบไฟล์หรือไม่เหมือนกับที่ผลิตหรือพบในเวลาคอมไพล์ นี่เป็นข้อผิดพลาดที่สำคัญเนื่องจากโปรแกรมไม่สามารถเริ่มต้นโดย JVM

ในทางกลับกันClassNotFoundExceptionคือเป็นExceptionดังนั้นจึงค่อนข้างคาดหวังและเป็นสิ่งที่กู้คืนได้ การใช้การสะท้อนอาจเกิดข้อผิดพลาดได้ง่าย (เนื่องจากมีความคาดหวังว่าสิ่งต่าง ๆ อาจไม่เป็นไปตามที่คาดไว้ไม่มีการตรวจสอบเวลาคอมไพล์เพื่อดูว่ามีคลาสที่ต้องการทั้งหมดอยู่แล้วดังนั้นปัญหาใด ๆ ในการค้นหาคลาสที่ต้องการ .


53
NoClassDefFoundErrorมักจะเกิดขึ้นเมื่อมีปัญหา (ข้อผิดพลาดโยน) กับบล็อกคงที่หรือเริ่มต้นเขตคงที่ของชั้นเรียนเพื่อให้ชั้นเรียนไม่สามารถเริ่มต้นได้สำเร็จ
Dagang

7
upvote หนึ่งเป็นErrorและอื่น ๆ Exceptionที่เป็น :)
Ravi

83

ClassNotFoundException ถูกส่งออกมาเมื่อไม่พบคลาสที่รายงานโดย ClassLoader โดยทั่วไปหมายความว่าคลาสขาดหายไปจาก CLASSPATH อาจหมายความว่าคลาสที่มีปัญหากำลังพยายามโหลดจากคลาสอื่นซึ่งโหลดใน parent classloader และด้วยเหตุนี้คลาสจาก child classloader จึงไม่สามารถมองเห็นได้ บางครั้งเป็นกรณีนี้เมื่อทำงานในสภาพแวดล้อมที่ซับซ้อนมากขึ้นเช่น App Server (WebSphere เป็นที่น่าอับอายสำหรับปัญหา classloader ดังกล่าว)

คนมักจะมีแนวโน้มที่จะสับสนjava.lang.NoClassDefFoundErrorกับjava.lang.ClassNotFoundExceptionแต่มีข้อแตกต่างที่สำคัญ ตัวอย่างเช่นข้อยกเว้น (ข้อผิดพลาดจริง ๆ เนื่องจากjava.lang.NoClassDefFoundErrorเป็นคลาสย่อยของ java.lang.Error) เช่น

java.lang.NoClassDefFoundError:
org/apache/activemq/ActiveMQConnectionFactory

ไม่ได้หมายความว่าคลาส ActiveMQConnectionFactory ไม่ได้อยู่ใน CLASSPATH Infact มันค่อนข้างตรงข้าม หมายความว่าคลาส ActiveMQConnectionFactory ถูกค้นพบโดย ClassLoader อย่างไรก็ตามเมื่อพยายามโหลดคลาสมันจะมีข้อผิดพลาดในการอ่านคำจำกัดความของคลาส สิ่งนี้มักจะเกิดขึ้นเมื่อคลาสที่มีปัญหามีบล็อกแบบสแตติกหรือสมาชิกที่ใช้คลาสที่ไม่พบ ClassLoader ดังนั้นเพื่อค้นหาผู้ร้ายดูแหล่งที่มาของชั้นเรียนในคำถาม (ActiveMQConnectionFactory ในกรณีนี้) และมองหารหัสโดยใช้บล็อกคงที่หรือสมาชิกคงที่ หากคุณไม่สามารถเข้าถึงแหล่งที่มาได้ก็เพียงแค่ถอดรหัสโดยใช้ JAD

ในการตรวจสอบรหัสสมมติว่าคุณพบบรรทัดของรหัสด้านล่างตรวจสอบให้แน่ใจว่าคลาส SomeClass ใน CLASSPATH ของคุณ

private static SomeClass foo = new SomeClass();

เคล็ดลับ: ในการค้นหาว่า jar เป็นคลาสใดคุณสามารถใช้เว็บไซต์ jarFinder สิ่งนี้อนุญาตให้คุณระบุชื่อคลาสโดยใช้ wildcards และค้นหาคลาสในฐานข้อมูลของไห jarhoo อนุญาตให้คุณทำสิ่งเดียวกัน แต่ไม่สามารถใช้งานได้อีกต่อไป

หากคุณต้องการที่จะหาขวดที่คลาสนั้นอยู่ในเส้นทางท้องถิ่นคุณสามารถใช้ยูทิลิตีเช่น jarscan ( http://www.inetfeedback.com/jarscan/ ) คุณเพียงแค่ระบุชั้นเรียนที่คุณต้องการค้นหาและเส้นทางไดเรกทอรีรากที่คุณต้องการให้เริ่มต้นค้นหาชั้นเรียนในไฟล์ jars และ zip


9
ฉันตลกที่นี่เป็นคำตอบที่ถูกต้องถูกโหวตครั้งสุดท้าย (แม้แต่ -1 ก่อนที่ฉันจะลงคะแนน) ClassNotFoundException หมายความว่า CL ไม่เห็นไฟล์. class NoClassDefFoundError หมายถึงไฟล์. class อยู่ที่นั่นซึ่งไม่สามารถโหลดได้ (อาจเป็นข้อผิดพลาด JNI)
user43685

1
คำตอบนี้ไม่ขัดแย้งกับแบบฟอร์มคำตอบหรือไม่?
zardosht

ฉันลองตัวอย่างที่คล้ายกันของบล็อกคง Class1 ของฉันมีตัวแปรแบบคงที่ "ส่วนตัวคง B foo = new B ();" หลังจากรวบรวมฉันลบไฟล์ B.class ออกจากโฟลเดอร์ bin ตอนนี้จากวิธีหลักของคลาสที่สามเมื่อฉันสร้างวัตถุของ Class1 rror นั้นเป็น follws: -------- "Exception in thread" main "java.lang.NoClassDefFoundError: spring / B" ........ ดังนั้นมันจึงกล่าวถึงคลาสที่ไม่พบ ieclass อ้างถึงในบล็อกแบบคงที่และไม่ได้เป็นชั้นนอกดังนั้นมันตรงกันข้ามกับคำตอบนี้
Kaushik Lele

+1 สำหรับคำชี้แจงเกี่ยวกับการ "ไม่ได้หมายความว่าชนชั้น ActiveMQConnectionFactory ไม่ได้อยู่ใน CLASSPATH ว่า"
Akila

35

NoClassDefFoundErrorเป็นข้อผิดพลาดในการเชื่อมโยงโดยทั่วไป มันเกิดขึ้นเมื่อคุณลองและยกตัวอย่างวัตถุ (คงที่กับ "ใหม่") และจะไม่พบเมื่อมันเป็นในระหว่างการรวบรวม

ClassNotFoundExceptionกว้างขึ้นและเป็นข้อยกเว้นแบบรันไทม์เมื่อคุณพยายามใช้คลาสที่ไม่มีอยู่ ตัวอย่างเช่นคุณมีพารามิเตอร์ในฟังก์ชั่นยอมรับส่วนต่อประสานและบางคนผ่านไปในชั้นเรียนที่ใช้ส่วนต่อประสานนั้น แต่คุณไม่สามารถเข้าถึงชั้นเรียนได้ นอกจากนี้ยังครอบคลุมกรณีของการโหลดแบบไดนามิกระดับเช่นการใช้หรือloadClass()Class.forName()


29

NoClassDefFoundError (NCDFE) เกิดขึ้นเมื่อรหัสของคุณรัน "new Y ()" และไม่พบคลาส Y

อาจเป็นเพราะ Y หายไปจากตัวโหลดคลาสของคุณเช่นเดียวกับข้อคิดเห็นอื่น ๆ ที่แนะนำ แต่อาจเป็นได้ว่าคลาส Y ไม่ได้ลงชื่อหรือมีลายเซ็นไม่ถูกต้องหรือ Y ถูกโหลดโดย classloader อื่นที่ไม่สามารถมองเห็นได้ในรหัสของคุณ หรือแม้กระทั่งว่า Y ขึ้นอยู่กับ Z ซึ่งไม่สามารถโหลดได้ด้วยเหตุผลใด ๆ ข้างต้น

หากสิ่งนี้เกิดขึ้น JVM จะจดจำผลลัพธ์ของการโหลด X (NCDFE) และมันจะโยน NCDFE ใหม่ทุกครั้งที่คุณถามหา Y โดยไม่บอกสาเหตุ:

ชั้นเรียน {
  คลาส b แบบคงที่ {}
  โมฆะคงที่สาธารณะหลัก (String args []) {
    System.out.println ("ความพยายามครั้งแรกใหม่ b ():");
    ลอง {new b (); } catch (Throwable t) {t.printStackTrace ();}
    System.out.println ("\ n วินาทีลองใหม่ b ():");
    ลอง {new b (); } catch (Throwable t) {t.printStackTrace ();}
  }
}

บันทึกสิ่งนี้เป็น a.java ที่ไหนสักแห่ง

รหัสนั้นพยายามที่จะยกตัวอย่างคลาส "b" ใหม่สองครั้งนอกเหนือจากนั้นไม่มีข้อบกพร่องใด ๆ และจะไม่ทำอะไรเลย

คอมไพล์โค้ดด้วยjavac a.java, จากนั้นรัน a โดยการเรียกใช้java -cp . a- มันควรพิมพ์ข้อความสองบรรทัดและมันก็จะทำงานได้ดีโดยไม่มีข้อผิดพลาด

จากนั้นลบไฟล์ "a $ b.class" (หรือเติมด้วยขยะหรือคัดลอก a.class ไป) เพื่อจำลองชั้นที่ขาดหายไปหรือเสียหาย นี่คือสิ่งที่เกิดขึ้น:

ความพยายามครั้งแรกใหม่ b ():
java.lang.NoClassDefFoundError: a $ b
    ที่ a.main (a.java/5)
เกิดจาก: java.lang.ClassNotFoundException: a $ b
    ที่ java.net.URLClassLoader $ 1.run (URLClassLoader.java:200)
    ที่ java.security.AccessController.doPrivileged (วิธีดั้งเดิม)
    ที่ java.net.URLClassLoader.findClass (URLClassLoader.java:188)
    ที่ java.lang.ClassLoader.loadClass (ClassLoader.java:307)
    ที่ sun.misc.Launcher $ AppClassLoader.loadClass (Launcher.java:301)
    ที่ java.lang.ClassLoader.loadClass (ClassLoader.java:252)
    ที่ java.lang.ClassLoader.loadClassInternal (ClassLoader.java:320)
    ... อีก 1

ความพยายามครั้งที่สองใหม่ b ():
java.lang.NoClassDefFoundError: a $ b
    ที่ a.main (a.java:7)

การเรียกใช้ครั้งแรกส่งผลให้ ClassNotFoundException (ส่งโดยตัวโหลดคลาสเมื่อไม่สามารถหาคลาสได้) ซึ่งต้องถูกล้อมรอบใน NoClassDefFoundError ที่ไม่ถูกตรวจสอบเนื่องจากโค้ดที่เป็นปัญหา ( new b()) ควรใช้งานได้

แน่นอนว่าความพยายามครั้งที่สองจะล้มเหลวเช่นกัน แต่อย่างที่คุณเห็นว่าข้อยกเว้นที่ห่อไว้นั้นไม่มีอีกต่อไปเพราะ ClassLoader ดูเหมือนจะจำคลาสตัวโหลดที่ล้มเหลวได้ คุณเห็นเฉพาะ NCDFE ที่ไม่มีเงื่อนงำอย่างแน่นอนว่าเกิดอะไรขึ้น

ดังนั้นหากคุณเคยเห็น NCDFE โดยไม่มีสาเหตุคุณจำเป็นต้องดูว่าคุณสามารถติดตามย้อนกลับไปในครั้งแรกที่มีการโหลดคลาสเพื่อค้นหาสาเหตุของข้อผิดพลาด


สิ่งที่เกี่ยวกับการใช้ JVM ด้วย-verboseหรือตัวเลือกที่คล้ายกันขึ้นอยู่กับ JVM เฉพาะ อาจ-verbose:classบางที-verbose:class:jniถ้าใช้ JNI แต่ผมไม่แน่ใจว่าเกี่ยวกับไวยากรณ์ หากสิ่งนี้มีประโยชน์บางทีคุณอาจแสดงผลลัพธ์
PJTraill

ทั้ง-verbose:classมิได้-verbose:jniให้การส่งออกเพิ่มเติมใด ๆ ที่เกี่ยวข้องกับระดับที่ขาดหายไป
mogsie

1
ขอบคุณที่ทดลองใช้แม้ว่าผลลัพธ์จะน่าผิดหวัง (PS ตั้งแต่ฉันพบว่า-verbose:class:jniผิด: หนึ่งจะต้องระบุสองตัวเลือกที่แยกจากกัน: -verbose:class -verbose:jni.)
PJTraill

2
ประโยคสุดท้าย * 1,000,000: ดังนั้นหากคุณเคยเห็น NCDFE โดยไม่มีสาเหตุคุณจำเป็นต้องดูว่าคุณสามารถติดตามย้อนกลับไปในครั้งแรกที่มีการโหลดคลาสเพื่อค้นหาสาเหตุของข้อผิดพลาด
batwad

20

จากhttp://www.javaroots.com/2013/02/classnotfoundexception-vs.html :

ClassNotFoundException: เกิดขึ้นเมื่อ class loader ไม่พบคลาสที่ต้องการในคลาสพา ธ ดังนั้นโดยทั่วไปคุณควรตรวจสอบเส้นทางของคลาสและเพิ่มคลาสใน classpath

NoClassDefFoundError: การดีบักนั้นยากกว่าและหาสาเหตุ สิ่งนี้จะถูกโยนเมื่อเวลาคอมไพล์คลาสที่ต้องการมีอยู่ แต่ ณ เวลารันคลาสจะถูกเปลี่ยนหรือลบออกหรือแบบสแตติกของคลาสเริ่มต้นข้อยกเว้นการโยน มันหมายถึงคลาสที่ได้รับการโหลดมีอยู่ใน classpath แต่หนึ่งในคลาสที่ต้องการโดยคลาสนี้จะถูกลบออกหรือไม่สามารถโหลดโดยคอมไพเลอร์ ดังนั้นคุณควรเห็นคลาสที่ขึ้นอยู่กับคลาสนี้

ตัวอย่าง :

public class Test1
{
}


public class Test 
{
   public static void main(String[] args)
   {
        Test1 = new Test1();    
   }

}

ตอนนี้หลังจากรวบรวมทั้งชั้นเรียนถ้าคุณลบไฟล์ Test1.class และรันชั้นเรียนทดสอบก็จะโยน

Exception in thread "main" java.lang.NoClassDefFoundError: Test
    at Test1.main(Test1.java:5)
Caused by: java.lang.ClassNotFoundException: Test
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    ... 1 more

ClassNotFoundException: โยนเมื่อแอปพลิเคชันพยายามโหลดในคลาสผ่านชื่อของมัน แต่ไม่พบคำจำกัดความของคลาสที่มีชื่อที่ระบุ

NoClassDefFoundError: โยนหาก Java Virtual Machine พยายามโหลดในคำจำกัดความของคลาสและไม่พบคำจำกัดความของคลาส


สิ่งที่เกี่ยวกับการใช้ JVM ด้วย-verboseหรือตัวเลือกที่คล้ายกันขึ้นอยู่กับ JVM เฉพาะ อาจ-verbose:classบางที-verbose:class:jniถ้าใช้ JNI แต่ผมไม่แน่ใจว่าเกี่ยวกับไวยากรณ์
PJTraill

-verbose:class:jniเป็นสิ่งที่ผิด -verbose:class -verbose:jniแต่คุณสามารถส่งผ่านสองตัวเลือกเฉพาะกิจการ:
PJTraill

15

อะไรคือเหตุผลที่ทำให้พวกเขาแต่ละคนและกระบวนการคิดเกี่ยวกับวิธีจัดการกับข้อผิดพลาดดังกล่าว?

พวกมันเกี่ยวข้องกันมาก A ClassNotFoundExceptionถูกโยนเมื่อ Java ไปหาคลาสที่ต้องการโดยใช้ชื่อและไม่สามารถโหลดได้สำเร็จ A NoClassDefFoundErrorถูกโยนเมื่อ Java ไปหาคลาสที่เชื่อมโยงกับโค้ดที่มีอยู่แล้ว แต่ไม่สามารถหาได้ด้วยเหตุผลใดเหตุผลหนึ่งหรืออย่างอื่น (เช่น classpath ผิด Java เวอร์ชันผิดเวอร์ชันของไลบรารีผิดเวอร์ชัน) และผิดพลาดอย่างทั่วถึง ตามที่ระบุว่ามีบางอย่างผิดปกติ

หากคุณมีพื้นหลัง C, CNFE เป็นเหมือนความล้มเหลวในการdlopen()/ dlsym()และ NCDFE เป็นปัญหากับ linker; ในกรณีที่สองคลาสไฟล์ที่เกี่ยวข้องไม่ควรรวบรวมในการกำหนดค่าที่คุณพยายามใช้


11

ตัวอย่าง # 1:

class A{
 void met(){
   Class.forName("com.example.Class1");
 }
}

หากcom/example/Class1ไม่มีอยู่ใน classpaths ใด ๆ จากนั้นจะโยนClassNotFoundExceptionแล้วมันจะพ่น

ตัวอย่างที่ 2:

Class B{
  void met(){
   com.example.Class2 c = new com.example.Class2();
 }
}

หากcom/example/Class2มีอยู่ในขณะที่รวบรวม B แต่ไม่พบในขณะที่การดำเนินการแล้วมันจะโยนNoClassDefFoundErrorแต่ไม่พบในขณะที่การดำเนินการแล้วมันจะพ่น

ทั้งสองข้อยกเว้นเวลาทำงาน


9

ClassNotFoundExceptionถูกส่งออกมาเมื่อมีความพยายามโหลดคลาสโดยอ้างอิงผ่าน String ตัวอย่างเช่นพารามิเตอร์ to ใน Class.forName () เป็น String และสิ่งนี้จะเพิ่มศักยภาพของชื่อไบนารีที่ไม่ถูกต้องซึ่งจะถูกส่งผ่านไปยัง classloader

ClassNotFoundException ถูกส่งออกมาเมื่อพบชื่อไบนารีที่ไม่ถูกต้อง ตัวอย่างเช่นถ้าชื่อคลาสมีอักขระ '/' คุณจะได้รับ ClassNotFoundException มันจะถูกโยนทิ้งเช่นกันเมื่อคลาสที่อ้างอิงโดยตรงไม่สามารถใช้ได้ใน classpath

ในทางกลับกันNoClassDefFoundErrorจะถูกโยนทิ้ง

  • เมื่อการแสดงแบบฟิสิคัลจริงของคลาส - ไฟล์. class ไม่พร้อมใช้งาน
  • หรือคลาสที่โหลดแล้วใน classloader ที่แตกต่างกัน (โดยปกติแล้ว classloader หลักจะมีการโหลดชั้นเรียนและด้วยเหตุนี้ไม่สามารถโหลดคลาสอีกครั้ง)
  • หรือหากพบคำนิยามคลาสที่เข้ากันไม่ได้ - ชื่อในไฟล์คลาสไม่ตรงกับชื่อที่ร้องขอ
  • หรือ (ที่สำคัญที่สุด) หากไม่สามารถระบุตำแหน่งและโหลดคลาสที่ต้องพึ่งพา ในกรณีนี้คลาสที่อ้างอิงโดยตรงอาจถูกระบุตำแหน่งและโหลด แต่คลาสที่อ้างอิงไม่พร้อมใช้งานหรือไม่สามารถโหลดได้ นี่คือสถานการณ์ที่สามารถโหลดคลาสที่อ้างอิงโดยตรงผ่าน Class.forName หรือวิธีการที่เทียบเท่า สิ่งนี้บ่งบอกถึงความล้มเหลวในการเชื่อมโยง

ในระยะสั้น NoClassDefFoundError มักจะถูกโยนลงบนคำสั่งใหม่ () หรือการเรียกใช้เมธอดที่โหลดคลาสที่ขาดไปก่อนหน้านี้ (เมื่อเทียบกับการโหลดตามคลาสของสตริงสำหรับ ClassNotFoundException) เมื่อ classloader ไม่สามารถค้นหาหรือโหลดนิยามคลาส () s)

ในที่สุดมันก็เกินการใช้งาน ClassLoader เพื่อโยนอินสแตนซ์ของ ClassNotFoundException เมื่อไม่สามารถโหลดคลาสได้ การปรับใช้ classloader แบบกำหนดเองส่วนใหญ่ดำเนินการนี้เนื่องจากจะขยาย URLClassLoader โดยปกติ classloaders ไม่ได้โยน NoClassDefFoundError อย่างชัดเจนในการใช้งานวิธีใด ๆ - ข้อยกเว้นนี้มักจะโยนจาก JVM ในคอมไพเลอร์ HotSpot และไม่ได้โดยตัวโหลดคลาสเอง


โหวตขึ้นเพื่อกล่าวถึง 'ชื่อในไฟล์คลาสไม่ตรงกับชื่อที่ร้องขอ' นี่เป็นสาเหตุที่พบบ่อยมาก
มาร์ควิสแห่ง Lorne

8

ความแตกต่างระหว่าง ClassNotFoundException กับ NoClassDefFoundError

ป้อนคำอธิบายรูปภาพที่นี่


ไม่ใส "ไม่ได้อัปเดตใน classpath" นั้นคลุมเครือ / ไม่แน่นอน นี่เป็นเรื่องเกี่ยวกับ JAR ที่ไม่มีอยู่ใน classpath หรือJAR เวอร์ชันที่ไม่ถูกต้องอยู่ใน classpath และสะกดผิด และ (ถอนหายใจ) เนื่องจากคุณโพสต์ข้อมูลของคุณเป็นกราฟิกที่ขี้ขลาดเราไม่สามารถแก้ไขได้
สตีเฟ่นซี

8

ที่มีชื่อของตัวเองเราสามารถระบุหนึ่งและอีกหนึ่งคนจาก ExceptionError

ข้อยกเว้น:ข้อยกเว้นเกิดขึ้นระหว่างการทำงานของโปรแกรม โปรแกรมเมอร์สามารถจัดการข้อยกเว้นเหล่านี้ได้โดยลอง catch catch เรามีข้อยกเว้นสองประเภท ตรวจสอบข้อยกเว้นที่พ่นในเวลารวบรวม ข้อยกเว้นรันไทม์ซึ่งถูกส่งออกมาในขณะดำเนินการข้อยกเว้นเหล่านี้มักเกิดขึ้นเนื่องจากการเขียนโปรแกรมที่ไม่ถูกต้อง

ข้อผิดพลาด: สิ่งเหล่านี้ไม่ใช่ข้อยกเว้น แต่มันอยู่นอกเหนือขอบเขตของโปรแกรมเมอร์ ข้อผิดพลาดเหล่านี้มักจะถูกโยนโดย JVM


ป้อนคำอธิบายรูปภาพที่นี่ แหล่งที่มาของภาพ

ความแตกต่าง:

ClassNotFoundException:

  • คลาสรถตักดินล้มเหลวในการตรวจสอบรหัสระดับไบต์เราพูดถึงในการเชื่อมโยงขั้นตอนของการโหลดคลาสระบบย่อยClassNotFoundExceptionที่เราได้รับ
  • ClassNotFoundExceptionเป็นข้อยกเว้นที่เลือกที่ได้รับโดยตรงจากjava.lang.Exceptionชั้นเรียนและคุณจำเป็นต้องให้การจัดการที่ชัดเจนสำหรับมัน
  • ClassNotFoundExceptionเกิดขึ้นเมื่อมีการโหลดคลาสอย่างชัดเจนเกี่ยวข้องโดยระบุชื่อของคลาสที่รันไทม์โดยใช้ ClassLoader.loadClass (), Class.forName () และ ClassLoader.findSystemClass ()

NoClassDefFoundError:

  • รถตักดินชั้นล้มเหลวในการแก้ไขปัญหาการอ้างอิงของชั้นเรียนในการเชื่อมโยงขั้นตอนของการโหลดคลาสระบบย่อยNoClassDefFoundErrorที่เราได้รับ
  • NoClassDefFoundErrorเป็นข้อผิดพลาดที่ได้มาจากLinkageErrorคลาสซึ่งใช้เพื่อระบุกรณีข้อผิดพลาดที่คลาสมีการอ้างอิงในคลาสอื่นและคลาสนั้นมีการเปลี่ยนแปลงที่เข้ากันไม่ได้หลังจากคอมไพล์
  • NoClassDefFoundErrorเป็นผลลัพธ์ของการโหลดคลาสโดยนัยเนื่องจากการเรียกเมธอดจากคลาสนั้นหรือการเข้าถึงตัวแปรใด ๆ

ความคล้ายคลึงกัน:

  • ทั้งสองNoClassDefFoundErrorและClassNotFoundExceptionเกี่ยวข้องกับความไม่พร้อมของชั้นเรียนในเวลาทำงาน
  • ทั้งสองClassNotFoundExceptionและNoClassDefFoundErrorเกี่ยวข้องกับ Java classpath

3

รับการดำเนินการ sussystem Class loader:

http://www.artima.com/insidejvm/ed2/images/fig7-1.gif

นี่เป็นบทความที่ช่วยให้ฉันเข้าใจความแตกต่างได้มากมาย: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html

หากเกิดข้อผิดพลาดระหว่างการโหลดคลาสอินสแตนซ์ของคลาสย่อยของLinkageErrorต้องถูกส่งไปที่จุดในโปรแกรมที่ (โดยตรงหรือโดยอ้อม) ใช้คลาสหรืออินเตอร์เฟสที่โหลด

หาก Java Virtual Machine พยายามโหลดคลาส C ระหว่างการตรวจสอบ (§5.4.1) หรือความละเอียด (§5.4.3) (แต่ไม่ใช่การเริ่มต้น (§5.5)) และคลาสโหลดเดอร์ที่ใช้เพื่อเริ่มการโหลด C พ่นตัวอย่างของ ClassNotFoundExceptionแล้วโปรแกรม Java Virtual Machine จะต้องโยนตัวอย่างของNoClassDefFoundErrorซึ่งเกิดเป็นตัวอย่างของClassNotFoundException

ดังนั้นClassNotFoundExceptionเป็นสาเหตุของNoClassDefFoundError
และNoClassDefFoundErrorเป็นกรณีพิเศษของข้อผิดพลาดในการโหลดประเภทที่เกิดขึ้นที่การเชื่อมโยงขั้นตอนการ


2

เพิ่มหนึ่งเหตุผลที่เป็นไปได้ในการปฏิบัติ:

  • ClassNotFoundException: ตามที่กล่าวไว้ว่า cletus คุณใช้อินเทอร์เฟซในขณะที่คลาสของอินเทอร์เฟซที่สืบทอดมาไม่ได้อยู่ใน classpath เช่นรูปแบบของผู้ให้บริการ (หรือผู้ให้บริการ ) พยายามค้นหาบางคลาสที่ไม่มีอยู่
  • NoClassDefFoundError: พบคลาสที่กำหนดในขณะที่ไม่พบการพึ่งพาของคลาสที่กำหนด

ในทางปฏิบัติข้อผิดพลาดอาจถูกส่งไปอย่างเงียบ ๆเช่นคุณส่งงานตัวจับเวลาและในงานตัวจับเวลาที่จะเกิดข้อผิดพลาดในขณะที่ในกรณีส่วนใหญ่โปรแกรมของคุณจะจับข้อยกเว้นเท่านั้น จากนั้นวนรอบตัวจับเวลาหลักจะสิ้นสุดลงโดยไม่มีข้อมูลใด ๆ ข้อผิดพลาดที่คล้ายกันกับ NoClassDefFoundError คือExceptionInInialializerErrorเมื่อ initializer แบบสแตติกของคุณหรือ initializer สำหรับตัวแปรแบบคงที่มีข้อยกเว้น


1

ClassNotFoundExceptionเป็นข้อยกเว้นที่ถูกตรวจสอบที่เกิดขึ้นเมื่อเราบอกให้ JVM โหลดคลาสด้วยชื่อสตริงโดยใช้ Class.forName () หรือ ClassLoader.findSystemClass () หรือ ClassLoader.loadClass () วิธีการและคลาสที่กล่าวถึงไม่พบ classpath

ส่วนใหญ่ข้อยกเว้นนี้เกิดขึ้นเมื่อคุณพยายามเรียกใช้แอปพลิเคชันโดยไม่ต้องอัปเดตคลาสพา ธ ด้วยไฟล์ JAR ที่ต้องการ ตัวอย่างเช่นคุณอาจเห็นข้อยกเว้นนี้เมื่อทำรหัส JDBC เพื่อเชื่อมต่อกับฐานข้อมูลของคุณ ieMySQL แต่ classpath ของคุณไม่มี JAR

NoClassDefFoundErrorข้อผิดพลาดเกิดขึ้นเมื่อ JVM พยายามโหลดคลาสเฉพาะที่เป็นส่วนหนึ่งของการเรียกใช้โค้ดของคุณ (เป็นส่วนหนึ่งของการเรียกเมธอดปกติหรือเป็นส่วนหนึ่งของการสร้างอินสแตนซ์โดยใช้คำหลักใหม่) และคลาสนั้นไม่ปรากฏใน classpath ของคุณ นำเสนอในเวลารวบรวมเพราะเพื่อที่จะรันโปรแกรมของคุณคุณต้องรวบรวมมันและถ้าคุณพยายามใช้คลาสที่ไม่มีคอมไพเลอร์ในปัจจุบันจะทำให้เกิดข้อผิดพลาดในการคอมไพล์

ด้านล่างนี้เป็นคำอธิบายสั้น ๆ

ป้อนคำอธิบายรูปภาพที่นี่

คุณสามารถอ่านทุกอย่างเกี่ยวกับ ClassNotFoundException Vs NoClassDefFoundErrorสำหรับรายละเอียดเพิ่มเติม


0

ฉันเตือนตัวเองต่อไปนี้ซ้ำแล้วซ้ำอีกเมื่อฉันต้องการรีเฟรช

ClassNotFoundException

ลำดับชั้นของคลาส

ClassNotFoundException extends ReflectiveOperationException extends Exception extends Throwable

ขณะทำการดีบั๊ก

  1. jar ที่ต้องการคลาสขาดหายไปจาก classpath
  2. ตรวจสอบว่าไหที่ต้องการทั้งหมดอยู่ใน classpath ของ jvm

NoClassDefFoundError

ลำดับชั้นของคลาส

NoClassDefFoundError extends LinkageError  extends Error extends Throwable

ขณะทำการดีบั๊ก

  1. ปัญหากับการโหลดคลาสแบบไดนามิกซึ่งรวบรวมอย่างถูกต้อง
  2. ปัญหาเกี่ยวกับบล็อกแบบคงที่ตัวสร้างวิธี init () ของคลาสที่ขึ้นต่อกันและข้อผิดพลาดจริงถูกห่อหลายเลเยอร์ [โดยเฉพาะเมื่อคุณใช้สปริงจำศีลข้อยกเว้นจริงจะถูกห่อและคุณจะได้รับ NoClassDefError]
  3. เมื่อคุณเผชิญกับ "ClassNotFoundException" ภายใต้บล็อกแบบคงที่ของคลาสที่อ้างถึง
  4. ปัญหากับรุ่นของคลาส สิ่งนี้เกิดขึ้นเมื่อคุณมีสองรุ่น v1, v2 ของคลาสเดียวกันภายใต้ jar / แพ็คเกจที่แตกต่างกันซึ่งถูกรวบรวมเรียบร้อยแล้วโดยใช้ v1 และ v2 ถูกโหลดที่รันไทม์ซึ่งไม่มีวิธีการ / vars ที่เกี่ยวข้องและคุณจะเห็นข้อยกเว้นนี้ [ฉันเคยแก้ไขปัญหานี้โดยการลบคลาสที่เกี่ยวข้องกับ log4j ที่ซ้ำกันในหลาย ๆ ขวดที่ปรากฏใน classpath]

-1

ClassNotFoundException และ NoClassDefFoundError เกิดขึ้นเมื่อไม่พบคลาสที่รันไทม์อย่างไรก็ตามจะเกิดขึ้นในสถานการณ์ที่แตกต่างกัน

ClassNotFoundException เป็นข้อยกเว้นที่เกิดขึ้นเมื่อคุณพยายามโหลดคลาสในขณะใช้งานโดยใช้เมธอด Class.forName () หรือ loadClass () และคลาสที่กล่าวถึงไม่พบใน classpath

    public class MainClass
    {
        public static void main(String[] args)
        {
            try
            {
                Class.forName("oracle.jdbc.driver.OracleDriver");
            }catch (ClassNotFoundException e)
            {
                e.printStackTrace();
            }
        }
    }



    java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Unknown Source)
    at pack1.MainClass.main(MainClass.java:17)

NoClassDefFoundError เป็นข้อผิดพลาดที่เกิดขึ้นเมื่อมีคลาสที่เฉพาะเจาะจงในเวลารวบรวม แต่หายไปในเวลาทำงาน

    class A
    {
      // some code
    }
    public class B
    {
        public static void main(String[] args)
        {
            A a = new A();
        }
    }

เมื่อคุณคอมไพล์โปรแกรมข้างต้นไฟล์. class สองไฟล์จะถูกสร้างขึ้น หนึ่งคือ A.class และอีกหนึ่งคือ B.class หากคุณลบไฟล์ A.class และรันไฟล์ B.class ระบบ Java Runtime จะขว้าง NoClassDefFoundError ดังนี้:

    Exception in thread "main" java.lang.NoClassDefFoundError: A
    at MainClass.main(MainClass.java:10)
    Caused by: java.lang.ClassNotFoundException: A
    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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.