2017-02-01 4 views
0

У меня есть метод ниже класса A. Все классы A, B, C и основной класс, из которых вызывается «A», находятся в одной и той же банке.Как решить java.lang.NoClassDefFoundError, происходящий в одной и той же банке?

public class A {  
    private static void init() { 
     if (!init) { 
      synchronized (B.class) { 
       if (!init) { 
        map = C.creat(); 
        init = true; 
       } 
      } 
     } 
    } 
} 

Код бросает Throwable, java.lang.NoClassDefFoundError на synchronized блок (линия № 4). Что может быть причиной, поскольку все классы находятся в одном банке, нет возможности не найти класс во время выполнения.

Я пропустил решение в Existing Question, но не смог найти решение. Пожалуйста помоги.

Есть статические блоки инициализации и статические переменные в классе B.

Проблема может быть фиксированными, если я использую static object/class A Синхронизировать фрагмент кода вместо «B». Мне любопытно узнать, почему я столкнулся с исключением и как исправить это, используя только класс B.

+2

Почему вы используете B.class для синхронизации? Я не думаю, что это лучшая практика. – duffymo

+0

Может ли быть, что статические блоки в B вызывают метод 'A.init'? – RealSkeptic

+0

Можете ли вы показать структуру упаковки банки?Вы можете jd-gui декомпилировать – Optimus

ответ

0

Если вы действительно скомпилировали , то код в JAR; и что JAR содержит B.class; то этого не может произойти.

Возможны следующие варианты: JAR, который вы используете, поврежден; или он не содержит того, что вы предполагаете, он должен содержать.

Таким образом: проверьте свой JAR. Что-то должно быть не так. Например, используйте jar tf jarfile.jar, чтобы перечислить весь контент; и проверьте, действительно ли B.class.

0

Объекты классов или метаданные загружаются загрузчиками классов при запуске Java-приложения.

Приведенный выше код может оказаться в java.lang.NoClassDefFoundError из-за следующего.

1> Указанный выше статический метод init вызывается из статического блока в классе A. Может случиться так, что класс B все еще не загружен перед классом A, а загрузчик классов пытается получить блокировку объекта класса (метаданных) класса B и не может найти определения класса.

Это работает, если вы syncronise на A.class, потому что загрузчик классов имеет класс мета ссылку на него

Для того, чтобы сделать работу с классом B.class вы, возможно, придется лениво вызвать метод инициализации в классе А и позволяют загрузчику классов загружать метаинформацию классов. Пожалуйста, избегайте использования метода init() в классе A из любого статического блока инициализатора.

+0

Не совсем верно. Ссылка на 'B.class' вызовет загрузку' B'. Это в JLS. Как и тот факт, что ссылка на 'B.class' не будет инициировать инициализацию класса. –

0

Не применимо ли какое-либо отношение к любому методу или переменной в B до использования B.class? Если нет, то B не повторил, не был инициализирован. Ссылка на литерал class не инициирует инициализацию класса. «Статический блок» - неправильный термин. Это «статический инициализатор блок». Который не запускался.

Используйте final Object член либо A, либо B для синхронизации, а не class буквально.

Смежные вопросы