Содержание
- java.lang.NoClassDefFoundError – How to solve No Class Def Found Error
- The Structure of NoClassDefFoundError
- Constructors
- The NoClassDefFoundError in Java
- The NoClassDefFoundError during static initialization
- How to deal with the NoClassDefFoundError
- java.lang.ClassNotFoundException – How to solve Class Not Found Exception (with video)
- 1. The java.lang.ClassNotFoundException in Java
- 2. How to deal with the java.lang.ClassNotFoundException
- 3. ClassNotFoundException vs NoClassDefFoundError vs UnSupportedClassVersionError
- 4. More articles
- 5. Download the source code
java.lang.NoClassDefFoundError – How to solve No Class Def Found Error
In this tutorial we will discuss How to solve No Class Def Found Error ( NoClassDefFoundError ). This error is thrown when the Java Virtual Machine (JVM) or an instance of the ClassLoader class tries to load the definition of a class, but the definition could not be found. It extends the LinkageError class, which is used to indicate error cases, where a class has a dependency on some other class and that class has incompatibly changed after the compilation.
The definition of a class can be requested during a method call, or while creating a new instance using a new expression. Also, it is important to mention that the definition of the class existed when the application code was compiled, but the definition can no longer be found in the runtime.
Finally, the NoClassDefFoundError exists since the first version of Java.
The Structure of NoClassDefFoundError
Constructors
-
- NoClassDefFoundError()
Creates an instance of the NoClassDefFoundError class.
Creates an instance of the NoClassDefFoundError class, using the specified string as message.
The NoClassDefFoundError in Java
As we have already mentioned, the NoClassDefFoundError is thrown when the definition of class in not available during runtime. This error also indicates that the definition of the class was found during the compilation of the application, but it is not available in the application’s classpath during runtime. In general, this is a difficult error to deal with and through this tutorial, we will present a number of different solutions.
To begin with, let’s demonstrate an example that throws the aforementioned error. First, we define a Test class with a simple constructor:
Then, we define a NoClassDefFoundErrorExample class that contains a static instance of the Test class:
The next step is to create an executable .jar file that shall execute the aforementioned main method. In order to achieve that, we first create a manifest file, called Manifest.txt and inside the file, we copy the following:
Using the terminal (Linux or Mac) or the command prompt (Windows), we execute the following commands, in order to first, compile our source Java files and then, create our executable file:
Now, we are ready to execute our code using the following command:
A sample execution is shown below:
The NoClassDefFoundError was thrown because the definition of the Test class was not included in the application’s classpath. If we execute the following command:
and then, execute our code, we shall get the following output:
The NoClassDefFoundError during static initialization
The NoClassDefFoundError can also be thrown during the static initialization of a class. If an exception occurs during the loading and initialization of a class and the definition of another class depends on the former class, then an ExceptionInInitializerError is thrown.
The following class reproduces the aforementioned problem:
In this example, we defined a Record class with a static field, called ID . When, the Record class is about to get loaded and initialized, the getRandomInteger() method throws a RuntimeException and thus, the main method that is static and requires the definition of the Record class throws an ExceptionInInitializerError .
A sample execution is shown below:
How to deal with the NoClassDefFoundError
- Verify that all required Java classes are included in the application’s classpath. The most common mistake is not to include all the necessary classes, before starting to execute a Java application that has dependencies on some external libraries.
- The classpath of the application is correct, but the Classpath environment variable is overridden before the application’s execution.
- Verify that the aforementioned ExceptionInInitializerError does not appear in the stack trace of your application.
This was a tutorial on How to solve No Class Def Found Error ( NoClassDefFoundError ) in Java.
Источник
java.lang.ClassNotFoundException – How to solve Class Not Found Exception (with video)
In this tutorial, we will discuss the java.lang.classnotfoundexception – ClassNotFoundException . This exception is thrown when an application tries to load a class through its string name, but no definition for the specified class name could be found. A class can be loaded using one of the following methods:
- The forName method that resides inside the Class class.
- The findSystemClass method that resides inside the ClassLoader class.
- The loadClass method that resides inside the ClassLoader class.
You can also check this tutorial in the following video:
This exception java.lang.classnotfoundexception extends the ReflectiveOperationException , which is defined as the common superclass of exceptions thrown by reflective operations in core reflection. Finally, after the Java 1.4 release, the ClassNotFoundException has been retrofitted to conform to the general purpose exception-chaining mechanism. The raising exception may be accessed via the Throwable.getCause() method.
1. The java.lang.ClassNotFoundException in Java
The java.lang.ClassNotFoundException is thrown when the Java Virtual Machine (JVM) tries to load a particular class and the specified class cannot be found in the classpath. The Java ClassNotFoundException is a checked exception and thus, must be declared in a method or constructor’s throws clause.
The following example tries to load a class using the forName method. However, the specified class name cannot be found and thus, a ClassNotFoundException is thrown. ClassNotFoundExceptionDemo.java
A sample execution is shown below:
To fix the exception download the mysql-connector jar from Oracle website and include in your class path.
Above scenario is the most common scenario when CLassNotFoundException is raised. However, it can become bit ugly or messy sometimes in a complex web deployment environments. Suppose your application is deployed as an EAR and it contains multiple jar and WAR files, it can sometimes raise this exception because of class visibility issues. Jar files and class files under EAR’s lib folder are visible to classes in WAR file, however jars and classes under war file’s lib folder can’t be seen by other modules or jars. It becomes even messier when different modules involved refer to different versions of same jar file. You need to be careful when such inter-dependencies exist.
2. How to deal with the java.lang.ClassNotFoundException
- Verify that the name of the requested class is correct and that the appropriate .jar file exists in your classpath. If not, you must explicitly add it to your application’s classpath.
- In case the specified .jar file exists in your classpath then, your application’s classpath is getting overridden and you must find the exact classpath used by your application.
- In case the exception is caused by a third party class, you must identify the class that throws the exception and then, add the missing .jar files in your classpath.
Below is the simple example to illustrate ClassNotFoundException and a way to fix it.
MainClass is dependent on DependentClass for the successful execution, if everything is there as expected then you will see below output,
For the demo purpose, I have removed DependentClass.class from the output directory. Now if you try to run the MainClass you get below output,
To fix this we need to make DependentClass.class available. This can be done by rebuilding the project in our case. Otherwise you need to verify the classes and libraries in your class path and fix the same.
Below is the code for our example, DependentClass.java MainClass.java
3. ClassNotFoundException vs NoClassDefFoundError vs UnSupportedClassVersionError
ClassNotFoundException is generally thrown when you try to load a class using Class.forname or loadClass and findSytemClass methods in ClassLoader methods, the class you are trying to load is not present in the Classpath. Another scenario when it can happen is the class you are trying to load is not a valid class.
NoClassDefFoundError is an error and it occurs when a class is present at compile-time and the same is missing at the run time. This is a fatal error and happens when you try to instantiate class or when you try to call a static method.
UnSupportedClassVersionEorror this error happens when the class is compiled with a higher JDK version than the one used for execution. When you encounter this error, verify the installed Java version and the Java path set in the JAVA_HOME environment variable.
4. More articles
5. Download the source code
For the demo program, I have used IntelliJ Idea IDE and Java 11 version.
Last updated on Jul. 23rd, 2021
Источник
Перевод: Саянкин А.А.
Содержание
- 1 Введение
- 2 В чём причина NoClassDefFoundError в Java?
- 3 Разница между java.lang.NoClassDefFoundError и ClassNotFoundException в Java
- 4 NoClassDefFoundError в Java. Примеры и сценарии
- 5 Загрузчик классов в Java
- 6 NoClassDefFoundError в Java из-за исключения в статическом инициализирующем блоке
- 7 Перечень использованных ссылок
Предисловие переводчика
Данная статья представляет перевод оригинальных публикаций следующих авторов:
- Джэйвин Пол (Javin Paul) Difference between ClassNotFoundException vs NoClassDefFoundError in Java, 3 ways to solve java.lang.NoClassDefFoundError in Java J2EE;
- Пьер Хьюго Шарбоне (Pierre Hugues Charbonneau) java.lang.NoClassDefFoundError: How to resolve – Part 1;
- coobird What is the difference between NoClassDefFoundError and ClassNotFoundException?
Переводчик выражает благодарность Виктору Жуковскому за ценные правки и обсуждение рукописи.
Введение
Известно насколько неприятно видеть исключение java.lang.NoClassDefFoundError в потоке «main«. Многие разработчики проводят много времени прежде всего пытаясь понять, что пошло не так, какого класса не хватает и в чём суть проблемы. Во-первых, они путают между собой ClassNotfoundException и NoClassDefFoundError, хотя на самом деле это два совершенно разных исключения. Во-вторых, они используют метод «научного тыка» для решения проблемы NoClassDefFoundError вместо ясного понимания почему ошибка случилась и как её исправить. В этой статье по Java мы откроем некоторые секреты исправления ошибки NoClassDefFoundError в Java и поделимся своим опытом решения подобной проблемы.
Ошибка NoClassDefFoundError не является чем-то, что не может быть устранено или чем-то, что очень трудно устраняемо — нет, NoClassDefFoundError всего лишь проявление другой, более глубинной ошибки, что сбивает с толку большинство Java разработчиков. NoClassDefFoundError наиболее распространённая ошибка в Java разработке наряду с java.lang.OutOfMemoroyError: Java heap space и java.lang.OutOfMemoryError: PermGen space. Давайте посмотрим почему в Java происходит NoClassDefFoundError и что делать, чтобы её исправить.
В чём причина NoClassDefFoundError в Java?
NoClassDefFoundError в Java происходит тогда, когда виртуальная машина Java во время исполнения кода не может найти определённый класс, который был доступен во время компиляции. Например, если мы вызываем метод из класса или обращаемся к статическому члену класса и этот класс не доступен во время выполнения, то виртуальная машина Java выбрасывает NoClassDefFoundError. Важно понимать, что эта ошибка отличается от исключения ClassNotFoundException, которое происходит при попытке загрузки класса во время выполнения, причём важно, что имя этого класса было определено только во время выполнения, но не во время компиляции кода. Многие Java разработчики путают эти две ошибки и приходят в тупик при попытке разрешить вопрос.
Коротко говоря, NoClassDefFoundError происходит, если класс присутствовал во время компиляции, но не доступен в classpath во время исполнения. Обычно в этом случае вы увидите следующую строку в журнале ошибок:
Exception in thread «main» java.lang.NoClassDefFoundError
Фраза Exception in thread «main» означает, что именно поток «main» не может найти определённый класс. Вместо «main» может быть любой поток. Разница между тем, когда эта ошибка возникает в потоке «main» и в другом потоке в состоит том, что при возникновении в потоке «main» программа останавливается, а при возникновении в ином потоке, напротив, продолжает выполнение после ошибки.
Разница между java.lang.NoClassDefFoundError и ClassNotFoundException в Java
Прежде чем рассмотреть разницу между ClassNotFoundException и NoClassDefFoundError давайте рассмотрим, что между ними общего и что приводит к путанице между этими двумя ошибками:
- Обе ошибки связаны с недоступностью класса во время выполнения;
- Обе ошибки связаны с Java Classpath .
Теперь о различиях.
- ClassNotFoundException возникает в Java, если мы пытаемся загрузить класс во время выполнения используя методы Class.forName(), ClassLoader.loadClass() или ClassLoader.findSystemClass() , причём необходимый класс не доступен для Java. Зачастую причина тому — неправильный Classpath. В большинстве своём нам кажется, что мы используем корректный Classpath, но оказывается, что приложение использует совсем другой Classpath — не тот, который мы ожидали. Например, Classpath , заданный в манифесте jar файла, перезаписывает Classpath в переменной окружения CLASSPATH или опции -cp , заданной при запуске jar файла. В отличие от ClassNotFoundException в случае с NoClassDefFoundError проблемный класс присутствовал во время компиляции, и, поэтому, программа успешно прошла компиляцию, но по некоторой причине класс отсутствует во время исполнения. На мой взгляд решить NoClassDefFoundError легче чем ClassNotFoundException, поскольку вы точно знаете, что класс присутствовал во время сборки, но, в общем случае, это сильно зависит от среды разработки. Если вы работаете с J2EE окружением, вы можете получить NoClassDefFoundError даже если класс присутствует, поскольку он может быть невидимым для соответствующего загрузчика классов.
- ClassNotFoundException представляет собой проверяемое исключение, унаследованное непосредственно от класса java.lang.Exception, требующее явной обработки, в то время как NoClassDefFoundError это java.lang.Error, унаследованный от java.lang.LinkageError.
- ClassNotFoundException возникает в результате явной загрузки класса методами Class.forName(), ClassLoader.loadClass() или ClassLoader.findSystemClass(), в то время как NoClassDefFoundError — результат неявной загрузки класса, происходящей при попытке вызова метода из другого класса или доступа к его свойству.
NoClassDefFoundError в Java. Примеры и сценарии
Итак, очевидная причина NoClassDefFoundError состоит в том, что определённый класс не доступен в Classpath, так что нам нужно добавить его в Classpath или понять почему его нет в Classpath, хотя мы ожидаем его там найти. Для этого могут быть несколько причин:
- Класс не задан непосредственно в самой переменной Classpath.
- Распечатайте значение System.getproperty(«java.classpath») в Java программе.
- Проверьте, не перезаписывает ли значение переменной окружения Classpath скрипт, запускающий приложение. Запустите программу с явной опцией -classpath, где укажите тот classpath, который по вашему мнению сработает, и если в этом случае программа заработает, то это хороший знак, что кто-то перезатирает ваш classpath.
- Класс отсутствует по местоположению, указанному в переменной Classpath.
- Проверьте, не удалил ли кто-то ваш jar-файл, или быть может переименовал его.
- Загрузчик классов не имеет прав на чтение файла, указанного в переменной Classpath, на уровне операционной системы.
- Используйте один и тот же id пользователя для всех ресурсов вашего приложения: JAR файлов, библиотек и файлов конфигурации.
- Класс не определён в атрибуте ClassPath файла манифеста, при запуске программы с помощью команды jar.
- Если вы используете файл сборки ANT для создания JAR архива и файла манифеста, то проверьте получает ли скрипт сборки ANT правильное значение classpath и добавляет ли его в файл manifest.mf.
- Виртуальная машина Java не нашла одну из зависимостей, например, нативную библиотеку. Эта ошибка выбрасывается поскольку NoClassDefFoundError является наследником java.lang.LinkageError.
- Храните ваши dll совместно с jar-файлами.
- Виртуальная машина Java не смогла завершить статическую инициализацию класса.
- Проверьте наличие ошибки java.lang.ExceptionInInitializerError в вашем журнале ошибок.
- Родительский загрузчик классов не видит класс, поскольку тот был уже загружен дочерним загрузчиком. Если вы работаете со средой J2EE, то неверная настройка видимости класса среди загрузчиков классов может также привести к java.lang.NoClassDefFoundError.
- Опечатка в XML конфигурации также может привести к NoClassDefFoundError в Java. Большинство программных платформ вроде Spring и Struts используют XML конфигурации для определения бинов. Случайно перепутав имя бина, вы можете получить java.lang.NoClassDefFoundError при загрузке другого класса, который зависит от бина. Это случается довольно часто в программных платформах Spring MVC и Apache Struts, где вы получаете тонны ошибок Exception in thread «main» java.lang.NoClassDefFoundError во время установки WAR или EAR файла.
- Переменные окружения или JDK установлены неверно.
- Проверьте переменные PATH и JAVA_HOME.
- Поставьте JDK другой версии.
Загрузчик классов в Java
Вкратце напомним, что загрузчик классов использует три основных принципа в своей работе: делегирование, видимость и уникальность.
- Делегирование означает, что каждый запрос на загрузку класса делегируется родительскому загрузчику классов.
- Видимость означает возможность найти классы загруженные загрузчиком классов: все дочерние загрузчики классов могут видеть классы, загруженные родительским загрузчиком, но родительский загрузчик не может видеть класс, загруженный дочерним.
- Уникальность гарантирует, что класс, загруженный родительским загрузчиком, не загружается повторно дочерним загрузчиком.
Каждый экземпляр загрузчика классов имеет связанный с ним родительский загрузчик классов. Предположим, загрузчик классов вашего приложения должен загрузить класс A. Первым делом загрузчик классов вашего приложения попытается делегировать поиск класса A своему родительскому загрузчику, прежде чем сам попытается его загрузить. Вы можете пройтись по длинной цепочке родительских загрузчиков пока не дойдёте до стартового загрузчика виртуальной машины Java.
Так в чём же тут проблема? Если класс A найден и загружен каким-нибудь родительским загрузчиком, это значит, что дочерний загрузчик загружать его уже не будет, а вы, возможно, именно этого и ждёте, что и приводит к NoClassDefFoundError.
Для лучшего понимания изобразим весь процесс загрузки в контексте платформы Java EE.
Как вы можете видеть при попытке загрузки класса дочерний загрузчик (Web App #1) делегирует загрузку родительскому загрузчику (Java EE App #1), который в свою очередь делегирует её системному стартовому загрузчику JVM. Если системный стартовый загрузчик не может загрузить класс, он возвращает управление родительскому загрузчику и так далее по цепочке пока класс не будет загружен каким-либо загрузчиком.
Рассмотрим простой пример, приводящий к NoClassDefFoundError из-за разной видимости классов между дочерним и родительским загрузчиками. Сделаем свой загрузчик MyClassLoader, наследник от java.lang.ClassLoader такой, чтобы он загружал классы с расширением .test вместо .class, находящиеся в пакете net.javacogito. Отметим, что стандартный загрузчик по умолчанию загружает данные только из файлов с расширением .class, так что загрузить Bar.test он не сможет. Схема дальнейшей работы такая:
- JVM загружает класс Bar из файла Bar.test.
- Класс Bar печатает свой загрузчик классов. Это MyClassLoader.
- JVM загружает класс Foo из файла Foo.class.
- Класс Foo печатает свой загрузчик классов. Это sun.misc.Launcher.AppClassLoader.
- Класс Foo вызывает статический метод printClassLoader() у класса Bar.
В этот момент JVM выдаёт NoClassDefFoundError, не смотря на то, что Bar был загружен ранее, поскольку родительский загрузчик AppClassLoader не видит классы, загруженные дочерним загрузчиком MyClassLoader.
Ниже на рисунке изображена схема делегирования загрузки, приводящая к NoClassDefFoundError.
Исходный код. Класс Bar.
package net.javacogito; public class Bar { public static void printClassLoader() { System.out.println("Bar ClassLoader: " + Bar.class.getClassLoader()); } }
Класс Foo.
package net.javacogito; public class Foo { public static void printBarClassLoader(){ Bar.printClassLoader(); } public static void printClassLoader() { System.out.println("Foo ClassLoader: " + Foo.class.getClassLoader()); } }
Класс MyClassLoader.
package net.javacogito; import java.io.DataInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; public class MyClassLoader extends ClassLoader{ public MyClassLoader(ClassLoader parent) { super(parent); } @Override public Class loadClass(String name) throws ClassNotFoundException { System.out.println("Loading Class '" + name + "'"); if (name.startsWith("net.javacogito")) { System.out.println("Loading Class using MyClassLoader"); return getClass(name); } return super.loadClass(name); } private Class getClass(String name) throws ClassNotFoundException { String file = name.replace('.', File.separatorChar) + ".test"; byte[] b = null; try { b = loadClassFileData(file); Class c = defineClass(name, b, 0, b.length); resolveClass(c); return c; } catch (IOException e) { e.printStackTrace(); return null; } } private byte[] loadClassFileData(String name) throws IOException { InputStream stream = getClass().getClassLoader().getResourceAsStream(name); int size = stream.available(); byte buff[] = new byte[size]; DataInputStream in = new DataInputStream(stream); in.readFully(buff); in.close(); return buff; } }
Класс Runner.
package net.javacogito; import java.lang.reflect.Method; public class Runner { public static void main(String[] args) throws Exception{ MyClassLoader myClassLoader = new MyClassLoader(Runner.class.getClassLoader()); Class clazz = myClassLoader.loadClass("net.javacogito.Bar"); Method printClassLoader = clazz.getMethod("printClassLoader"); printClassLoader.invoke(null, new Object[0]); Foo.printClassLoader(); Foo.printBarClassLoader(); } }
Порядок запуска.
cd src/main/java javac net/javacogito/Runner.java mv net/javacogito/Bar.class net/javacogito/Bar.test java net.javacogito.Runner
Результат запуска.
Loading Class 'net.javacogito.Bar' Loading Class using MyClassLoader Loading Class 'java.lang.Object' Loading Class 'java.lang.System' Loading Class 'java.lang.StringBuilder' Loading Class 'java.lang.Class' Loading Class 'java.io.PrintStream' Bar ClassLoader: net.javacogito.MyClassLoader@527c6768 Foo ClassLoader: sun.misc.Launcher$AppClassLoader@3326b249 Exception in thread "main" java.lang.NoClassDefFoundError: net/javacogito/Bar at net.javacogito.Foo.printBarClassLoader(Foo.java:5) at net.javacogito.Runner.main(Runner.java:16) Caused by: java.lang.ClassNotFoundException: net.javacogito.Bar at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:306) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:247) ... 2 more
Из результатов запуска видно, что MyClassLoader загрузил класс Bar, а AppClassLoader (наследник абстрактного класса java.lang.ClassLoader) загрузил класс Foo. Класс Bar присутствует в файловой системе и JVM его загрузила, но родительский загрузчик ClassLoader не видит его, что и приводит к NoClassDefFoundError.
NoClassDefFoundError в Java из-за исключения в статическом инициализирующем блоке
Исключения в статическом инициализирующем блоке — другая частая причина java.lang.NoClassDefFoundError. Ваш класс выполняет некоторую статическую инициализацию в статическом блоке. Например, многие синглетоны инициализируют себя в статическом блоке, чтобы получить преимущества потоко-безопасности, предоставляемые виртуальной машиной Java во время процесса инициализации класса. В этом случае, если статический блок выбросит исключение, то класс, ссылающийся на этот синглетон, выбросит NoclassDefFoundError в Java. При просмотре вашего журнала ошибок вы должны внимательно следить, не возникла ли ошибка java.lang.ExceptionInInitializerError, поскольку она может привести к java.lang.NoClassDefFoundError: Could not initialize class в другом месте. Как и в примере кода ниже, во время загрузки и инициализации класс User выбрасывает исключение из статического инициализирующего блока, что приводит к ExceptionInInitializerError во время первой загрузки класса User при вызове new User(). Дальше все остальные вызовы new User() завершаются java.lang.NoClassDefFoundError. Ситуация становится намного хуже, если исходную ошибку ExceptionInInitializerError, являющуюся первопричиной, скрывает последующий код.
/** * Java program to demonstrate how failure of static initialization subsequently cause * java.lang.NoClassDefFoundError in Java. * @author Javin Paul */ public class NoClassDefFoundErrorDueToStaticInitFailure { public static void main(String args[]){ List<User> users = new ArrayList<User>(2); for(int i=0; i<2; i++){ try{ users.add(new User(String.valueOf(i))); //will throwNoClassDefFoundError }catch(Throwable t){ t.printStackTrace(); } } } } class User{ private static String USER_ID = getUserId(); public User(String id){ this.USER_ID = id; } private static String getUserId() { throw new RuntimeException("UserId Not found"); } }
Результат запуска.
java.lang.ExceptionInInitializerError at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDef FoundErrorDueToStaticInitFailure.java:23) Caused by: java.lang.RuntimeException: UserId Not found at testing.User.getUserId(NoClassDefFoundErrorDueToStaticInitFailure.java:41) at testing.User.<clinit>(NoClassDefFoundErrorDueToStaticInitFailure.java:35) ... 1 more java.lang.NoClassDefFoundError: Could not initialize class testing.User at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDef FoundErrorDueToStaticInitFailure.java:23)
Перечень использованных ссылок
- http://javarevisited.blogspot.com/2011/07/classnotfoundexception-vs.html
- http://javarevisited.blogspot.com/2011/06/noclassdeffounderror-exception-in.html
- http://stackoverflow.com/questions/1457863/what-is-the-difference-between-noclassdeffounderror-and-classnotfoundexception
- http://www.javacodegeeks.com/2012/06/javalangnoclassdeffounderror-how-to.html
Я потратил довольно много времени, чтобы выяснить как исправить ошибку java.lang.NoClassDefFoundError в Java.
В этой инструкции я покажу как исправить эти ошибки, раскрою некоторые секреты NoClassDefFoundError и поделюсь своим опытом в этой области.
NoClassDefFoundError – это самая распространенная ошибка в разработке Java. В любом случае, давайте посмотрим, почему это происходит и что нужно сделать для разрешения проблемы.
NoClassDefFoundError в Java возникает, когда виртуальная машина Java не может найти определенный класс во время выполнения, который был доступен во время компиляции.
Например, если у нас есть вызов метода из класса или доступ к любому статическому члену класса, и этот класс недоступен во время выполнения, JVM сгенерирует NoClassDefFoundError.
Важно понимать, что это отличается от ClassNotFoundException, который появляется при попытке загрузить класс только во время выполнения, а имя было предоставлено во время выполнения, а не во время компиляции. Многие Java-разработчики смешивают эти две ошибки и запутываются.
NoClassDefFoundError возникнет, если класс присутствовал во время компиляции, но не был доступен в java classpath во время выполнения. Обычно появляется такая ошибка:
Exception in thread "main" java.lang.NoClassDefFoundError
Разница между java.lang.NoClassDefFoundError и ClassNotFoundException в Java
[ads-pc-3]
java.lang.ClassNotFoundException и java.lang.NoClassDefFoundError оба связаны с Java Classpath, и они полностью отличаются друг от друга.
ClassNotFoundException возникает, когда JVM пытается загрузить класс во время выполнения, т.е. вы даете имя класса во время выполнения, а затем JVM пытается загрузить его, и если этот класс не найден, он генерирует исключение java.lang.ClassNotFoundException.
Тогда как в случае NoClassDefFoundError проблемный класс присутствовал во время компиляции, и поэтому программа успешно скомпилирована, но не доступна во время выполнения по любой причине.
Приступим к решению ошибки java.lang.NoClassDefFoundError.
Нам нужно добавить NoClassDefFoundError в Classpath или проверить, почему он не доступен в Classpath. Там может быть несколько причин, таких как:
- Класс недоступен в Java Classpath.
- Возможно, вы запускаете вашу программу с помощью jar, а класс не определен в атрибуте ClassPath.
- Любой сценарий запуска переопределяет переменную среды Classpath.
Поскольку NoClassDefFoundError является подклассом java.lang.LinkageError, он также может появиться, если библиотека может быть недоступна. - Проверьте наличие java.lang.ExceptionInInitializerError в файле журнала. NoClassDefFoundError из-за сбоя инициализации встречается довольно часто.
- Если вы работаете в среде J2EE, то видимость Class среди нескольких Classloader также может вызвать java.lang.NoClassDefFoundError.
Примеры
- Простой пример NoClassDefFoundError – класс принадлежит отсутствующему файлу JAR, или JAR не был добавлен в путь к классам, или имя jar было изменено кем-то.
- Класс не находится в Classpath, нет способа узнать это, но вы можете просто посмотреть в System.getproperty (“java.classpath”), и он напечатает classpath оттуда, где можно получить представление о фактическом пути к классам во время выполнения.
- Просто попробуйте запустить явно -classpath с тем классом, который, по вашему мнению, будет работать, и если он работает, это верный признак того – что-то переопределяет java classpath.
NoClassDefFoundError в Java из-за исключения в блоке инициализатора
Это еще одна распространенная причина java.lang.NoClassDefFoundError, когда ваш класс выполняет некоторую инициализацию в статическом блоке и если статический блок генерирует исключение, класс, который ссылается на этот класс, получит NoclassDefFoundError.
Смотрите в журнале java.lang.ExceptionInInitializerError, потому что это может вызвать java.lang.NoClassDefFoundError: Could not initialize class.
Как и в следующем примере кода, во время загрузки и инициализации класса, пользовательский класс генерирует Exception из статического блока инициализатора, который вызывает ExceptionInInitializerError при первой загрузке пользовательского класса в ответ на новый вызов User ().
[ads-pc-3]
/** * Java program to demonstrate how failure of static initialization subsequently cause * java.lang.NoClassDefFoundError in Java. * @author Javin Paul */ public class NoClassDefFoundErrorDueToStaticInitFailure { public static void main(String args[]){ List users = new ArrayList(2); for(int i=0; i<2; i++){ try{ users.add(new User(String.valueOf(i))); }catch(Throwable t){ t.printStackTrace(); } } } } class User{ private static String USER_ID = getUserId(); public User(String id){ this.USER_ID = id; } private static String getUserId() { throw new RuntimeException("UserId Not found"); } } Output java.lang.ExceptionInInitializerError at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDefFoundErrorDueToStaticInitFailure.java:23) Caused by: java.lang.RuntimeException: UserId Not found at testing.User.getUserId(NoClassDefFoundErrorDueToStaticInitFailure.java:41) at testing.User.(NoClassDefFoundErrorDueToStaticInitFailure.java:35) ... 1 more java.lang.NoClassDefFoundError: Could not initialize class testing.User at testing.NoClassDefFoundErrorDueToStaticInitFailure.main(NoClassDefFoundErrorDueToStaticInitFailure.java:23)
- Поскольку NoClassDefFoundError также является LinkageError, который возникает из-за зависимости от какого-либо другого класса, вы также можете получить java.lang.NoClassDefFoundError, если ваша программа зависит от собственной библиотеки, а соответствующая DLL отсутствует. Помните, что это может также вызвать java.lang.UnsatisfiedLinkError: no dll in java.library.path. Чтобы решить эту проблему, держите dll вместе с JAR.
- Если вы используете файл ANT, создайте JAR, стоит отметить отладку до этого уровня, чтобы убедиться, что скрипт компоновки ANT получает правильное значение classpath и добавляет его в файл manifest.mf.
- Проблема с правами доступа к файлу JAR. Если вы работаете с Java-программой в многопользовательской операционной системе, такой как Linux, вам следует использовать идентификатор пользователя приложения для всех ресурсов приложения, таких как файлы JAR, библиотеки и конфигурации. Если вы используете разделяемую библиотеку, которая используется несколькими приложениями, работающими под разными пользователями, вы можете столкнуться с проблемой прав доступа, например, файл JAR принадлежит другому пользователю и недоступен для вашего приложения.
- Опечатка в конфигурации XML также может вызвать NoClassDefFoundError в Java. Как и большинство Java-фреймворков, таких как Spring, Struts все они используют конфигурацию XML для определения bean-компонентов. В любом случае, если вы неправильно указали имя компонента, он может вызвать ошибку при загрузке другого класса. Это довольно часто встречается в среде Spring MVC и в Apache Struts, где вы получаете множество исключений при развертывании файла WAR или EAR.
- Когда ваш скомпилированный класс, который определен в пакете, не присутствует в том же пакете во время загрузки, как в случае с JApplet.
- Еще одна причина- это нескольких загрузчиков классов в средах J2EE. Поскольку J2EE не использует стандартную структуру загрузчика классов, а зависит от Tomcat, WebLogic, WebSphere и т.д., от того, как они загружают различные компоненты J2EE, такие как WAR-файл или EJB-JAR-файл. Кроме того, если класс присутствует в обоих файлах JAR и вы вызовете метод equals для сравнения этих двух объектов, это приведет к исключению ClassCastException, поскольку объект, загруженный двумя различными загрузчиками классов, не может быть равным.
- Очень редко может происходить Exception in thread “main” java.lang.NoClassDefFoundError: com/sun/tools/javac/Main. Эта ошибка означает, что либо ваш Classpath, PATH или JAVA_HOME не настроен должным образом, либо JDK установка не правильная. Попробуйте переустановить JDK. Замечено, что проблема возникала после установки jdk1.6.0_33 и последующей переустановки JDK1.6.0_25.