java.lang.NoClassDefFoundError: ไม่สามารถเริ่มต้นคลาส XXX ได้


165
public class PropHolder {
  public static Properties prop;

  static {
    //code for loading properties from file
  }
}

// Referencing the class somewhere else:
Properties prop = PropHolder.prop;

class PropHolderเป็นคลาสของฉันเอง คลาสอยู่ในไฟล์ JAR เดียวกันของคลาสหลัก ดังนั้นไม่ควรเพราะ JAR ใด ๆ หายไปจาก classpath

เมื่อฉันดูไฟล์ JAR โดยjar tf myjarfileฉันสามารถดูPropHolder.classรายการได้

Btw: รหัสกำลังทำงานได้ดีบนเครื่องของฉัน แต่ไม่สามารถทำงานได้เมื่อฉันปรับใช้กับสคริปต์บางอย่างบนเซิร์ฟเวอร์ Linux ดังนั้นฉันคิดว่ามันไม่ใช่ปัญหาของรหัส แต่ด้วยเหตุผลบางอย่าง กระบวนการปรับใช้นั้นยากมากในการติดตาม

มีปัญหาอะไร


โครงสร้างไดเรกทอรีที่เหมาะสมในขวดของคุณเพื่อให้ตรงกับแพคเกจชั้น?
John B

ต้องดูที่มาบางสิ่งหลายอย่างสามารถทำให้เกิดสิ่งนี้ ตัวอย่างเช่นคำสั่ง 'แพ็คเกจ' แต่ไฟล์ไม่ได้อยู่ในพา ธ ที่สอดคล้องกัน
จริงๆ

3
สาเหตุหนึ่งคือข้อยกเว้นในระหว่างการเริ่มต้น - มีข้อผิดพลาดอื่น ๆ ที่ส่งออก?
Michael Brewer-Davis

คำตอบ:


211

ทางออกที่ดีที่สุดของฉันคือมีปัญหาที่นี่:

static {
    //code for loading properties from file
}

มันจะปรากฏข้อยกเว้นที่ไม่ได้ตรวจสอบเกิดขึ้นและแพร่กระจายไปถึง ClassLoader จริงที่พยายามโหลดชั้นเรียน เราจะต้องใช้ stacktrace เพื่อยืนยันสิ่งนี้

อาจเกิดขึ้นเมื่อสร้างPropHolder.propตัวแปรแบบคงที่


ฉันประสบปัญหาครั้งแล้วครั้งเล่า ฉันแน่ใจว่าเป็นเพราะstaticปัญหา ต้องทำอะไรเพื่อแก้ไขปัญหา
viper

1
คุณจะต้องระบุว่ามีข้อยกเว้นใดบ้างที่ถูกส่งออกไปจากstaticบล็อก เพื่อแก้ปัญหามันวางtry/catch(Exception e)รอบบล็อกทั้งหมดและบันทึกข้อยกเว้น คุณจะต้องแก้ไขข้อยกเว้นนั้น โดยทั่วไปแล้วข้อยกเว้นจะถูกบันทึกไว้ แต่อาจหายากเนื่องจากมีการบันทึกไว้ในระหว่างการโหลดคลาสซึ่งอาจเกิดขึ้นเร็วมาก
John Vint

ใช่ฉันเก็บรหัสในการป้องกันและก็กล่าวว่าtry catch ผมคิดว่ามันเป็นปัญหาของFailed to initialize ClassA JVMฉันรีสตาร์ทระบบแล้วทุกอย่างทำงานได้ดี ฉันจะแก้ไขปัญหานี้ในอนาคตได้อย่างไรโดยไม่ต้องรีสตาร์ทระบบและแก้ปัญหาด้วยวิธีแก้ไขปัญหาอย่างง่าย
viper

ล้มเหลวในการเริ่มต้น ClassA เป็นผลข้างเคียงจากสิ่งอื่น คุณจะต้องการดูcauseถ้ามี A NoClassDefFoundErrorมักจะเกี่ยวข้องกับข้อผิดพลาดอื่นคุณจะต้องค้นหาในบันทึกหรือพยายามที่จะบันทึกอย่างเหมาะสมมากขึ้น (เช่นบังคับให้เข้าสู่ระบบไฟล์ใหม่ในระบบไฟล์)
John Vint

มันจะตรวจสอบย้อนกลับได้ง่ายขึ้นถ้า Java จะโยนข้อผิดพลาด CouldNotInitializeStaticPartOfClassError หรือบางอย่าง ถ้าอย่างนั้นเราในฐานะนักพัฒนาจะรู้ว่าจะต้องดูที่ไหน
Maarten

126

คุณกำลังได้รับjava.lang.NoClassDefFoundErrorซึ่งไม่ได้หมายความว่าชั้นของคุณจะหายไป (ในกรณีที่คุณจะได้รับjava.lang.ClassNotFoundException) ClassLoader พบข้อผิดพลาดขณะอ่านคำจำกัดความของคลาสเมื่อพยายามอ่านคลาส

ใส่ลอง / จับภายใน initializer คงของคุณและดูข้อยกเว้น หากคุณอ่านไฟล์บางไฟล์ที่นั่นและมันแตกต่างจากสภาพแวดล้อมท้องถิ่นของคุณอาจเป็นสาเหตุของปัญหา (อาจจะหาไฟล์ไม่พบไม่มีสิทธิ์ ฯลฯ )


1
หนึ่ง clarifaction คือแม้ว่า NoClassDefFoundError ไม่ได้หมายความถึง ClassNotFoundException แต่ก็ยังคงเป็นสาเหตุที่เป็นไปได้ของ NoClassDefFoundError
John Vint

1
buf ถ้าคุณมี ClassNotFoundException แล้ว ClassLoader จะ / ไม่เคยลองโหลดคลาสใช่มั้ย
jeha

4
คลาสสามารถโหลดคลาสอื่นที่ไม่พบ สาเหตุในอินสแตนซ์นั้นยังคงเป็น ClassNotFoundException
John Vint

1
ฉันควรจะชี้แจงฉันแค่หมายถึงข้อยกเว้น getCause ()
จอห์น Vint

1
อันนี้มีประโยชน์จริง ๆ ที่นี่เนื่องจากฉันใช้เวลาประมาณ 20 นาทีในการตรวจสอบ JAR (รวมอยู่ในคลาสที่รายงาน) เมื่อฉันรู้ว่าฉันกำลังมองไปในทิศทางที่ไม่ถูกต้องฉันเข้าใจได้ง่ายว่ามีโอกาสที่คำอธิบายประกอบบางชั้นหายไปและ voila รายงานที่ถูกประกาศเป็น@Statelessดังนั้นฉันเพิ่งเพิ่มการพึ่งพาที่สอดคล้องกันและสามารถดำเนินการต่อไปได้ ขอบคุณสำหรับทิป!
RAM237

33

NoClassDefFoundError ไม่ได้ให้เงื่อนงำอะไรมากมายกับสิ่งที่เกิดขึ้นภายในบล็อกแบบคงที่ มันเป็นแนวปฏิบัติที่ดีที่จะมีบล็อกแบบนี้อยู่เสมอภายในรหัสเริ่มต้น {... } แบบคงที่:

static {
  try {

    ... your init code here

  } catch (Throwable t) {
    LOG.error("Failure during static initialization", t);
    throw t;
  }
}

วิธีทำใน kotlin
Marlon

ขอบคุณที่ให้คำใบ้ ในกรณีของฉันฉันได้รับ NPE ในการเริ่มต้นสายคงที่
Abhishek

3

ฉันมีข้อยกเว้นเดียวกันนี่คือวิธีที่ฉันแก้ไขปัญหา:

เงื่อนไข:

  1. Junit class (และ test) ที่ขยายอีก class

  2. ApplicationContext เตรียมใช้งานโดยใช้สปริงซึ่งเริ่มต้นโครงการ

  3. บริบทแอพลิเคชันถูกเตรียมใช้งานในวิธี @Before

สารละลาย:

เริ่มต้นบริบทแอปพลิเคชันจากเมธอด @BeforeClass เนื่องจากคลาสพาเรนต์ต้องการคลาสบางส่วนที่เริ่มต้นจากภายในบริบทแอปพลิเคชัน

หวังว่าจะช่วยได้


2

ตามที่กล่าวไว้ข้างต้นอาจมีหลายสิ่ง ในกรณีของฉันฉันมีตัวแปรเริ่มต้นแบบคงที่ซึ่งอาศัยรายการที่ขาดหายไปในไฟล์คุณสมบัติของฉัน เพิ่มรายการที่ขาดหายไปในไฟล์คุณสมบัติและปัญหาได้รับการแก้ไข


1

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

mvn -U clean  test -Dtest=path 

เพื่อเรียกใช้งานและเนื่องจากตัวแปรสแตติกของฉันคือการเริ่มต้นคอนเทนเนอร์ (หรือคุณอาจเริ่มต้น classloader ใหม่) ดังนั้นมันจะยังคงอยู่จนกระทั่ง jvm หยุดและ jvm หยุดเมื่องานทั้งหมดในกระบวนการเดียวหยุด ทุกงานจะเริ่มคอนเทนเนอร์ใหม่ (หรือ classloader) และทำให้ jvm สับสน เป็นผลให้เกิดข้อผิดพลาด ดังนั้นวิธีการแก้มันได้อย่างไร ทางออกของฉันคือการเพิ่มคำสั่งใหม่ไปยังคำสั่ง maven และทำให้ทุกงานไปที่ภาชนะเดียวกัน

-Dxxx.version=xxxxx #sorry can't post more

บางทีคุณอาจแก้ไขปัญหานี้ได้แล้ว แต่ก็ยังหวังว่าจะช่วยคนอื่นที่พบปัญหาเดียวกัน


ยิ่งไปกว่านั้นเมื่อโค้ดทำงานบนเครื่อง linux ทำตามข้อผิดพลาดด้านบนมีปัญหาอื่น: java.lang.ExceptionInInitializerError: nullหมายความว่าไม่สามารถหาคลาสใน classloader ได้หรือไม่รู้ว่าจะโหลดอันไหน (ฉันเดา) คุณเจอไหม?
MonkeyKing

1

ฉันมีข้อยกเว้นเดียวกัน - แต่เฉพาะในขณะที่ทำงานในโหมดแก้ไขข้อบกพร่องนี่คือวิธีที่ฉันแก้ไขปัญหา (หลังจาก 3 วันทั้งหมด): ใน build.gradle ฉันมี: "multiDexEnabled จริง" ตั้งอยู่ในส่วน defaultConfig

        defaultConfig {
    applicationId "com.xxx.yyy"
    minSdkVersion 15
    targetSdkVersion 28
    versionCode 5123
    versionName "5123"
    // Enabling multidex support.
    multiDexEnabled true
}

แต่ดูเหมือนจะไม่เพียงพอ แต่เมื่อฉันเปลี่ยน:

public class MyAppClass  extends Application 

ถึง:

public class MyAppClass  extends MultiDexApplication 

นี้แก้ไขได้ หวังว่านี่จะช่วยใครซักคน


0

หากคุณกำลังทำงานในโครงการ Android ตรวจสอบให้แน่ใจว่าคุณไม่ได้เรียกวิธีการคงที่ในคลาส Android ใด ๆ ฉันใช้ JUnit + Mockito เท่านั้นดังนั้นบางทีเฟรมเวิร์กอื่นอาจช่วยคุณหลีกเลี่ยงปัญหาได้ทั้งหมดฉันไม่แน่ใจ

ปัญหาของฉันถูกเรียกUri.parse(uriString)เป็นส่วนหนึ่งของ initializer แบบคงที่สำหรับการทดสอบหน่วย คลาส Uri เป็น Android API ซึ่งเป็นสาเหตุที่การสร้างหน่วยทดสอบไม่สามารถหาได้ ฉันเปลี่ยนค่านี้เป็นnullแทนและทุกอย่างกลับเป็นปกติ


0

ฉันมีปัญหาเดียวกัน: java.lang.NoClassDefFoundError: ไม่สามารถเริ่มต้นคลาส com.xxx.HttpUtils

static {
    //code for loading properties from file
}

มันเป็นปัญหาสิ่งแวดล้อมนั่นหมายถึงคุณสมบัติในapplication.ymlไม่ถูกต้องหรือว่างเปล่า!


0

ฉันพบปัญหาเดียวกัน ฉันสร้างวัตถุถั่วในบล็อกแบบคงที่ด้านล่าง:

static {
    try{
        mqttConfiguration = SpringBootBeanUtils.<MqttConfiguration>getBean(MqttConfiguration.class);
    }catch (Throwable e){
        System.out.println(e);
    }
 }

เพียงเพราะกระบวนการที่ต้นถั่วของฉันก่อให้เกิด NPE ฉันจึงมีปัญหา ดังนั้นฉันคิดว่าคุณควรตรวจสอบบล็อกรหัสคงที่ของคุณอย่างระมัดระวัง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.