web-dev-qa-db-fra.com

NoSuchFieldError Java

Je reçois une erreur NoSuchFieldError dans mon code. Oracle ne sait pas très bien pourquoi cette erreur est générée, mais se contente de dire: cette erreur ne peut se produire à l'exécution que si la définition d'une classe a changé de façon incompatible.

Est-ce que quelqu'un peut m'expliquer comment on peut «changer incompatiblement» une classe? Le cours dont je parle comprend assez de cours, alors je suppose que cela pourrait avoir un rapport avec cela, mais je ne sais pas par où commencer ni ce que je recherche.

33
Tim

Cette erreur est généralement générée si vous ne recompilez que partiellement votre code. Vous avez un ancien code qui référence un champ qui n'existe plus dans les fichiers de classe recompilés.

La solution consiste à nettoyer tous les fichiers de classe et à tout compiler à partir de fichiers frais.

Mise à jour: Si vous obtenez toujours la même erreur après avoir tout recompilé, vous compilez probablement avec une version d'une bibliothèque externe et utilisez-en une autre au moment de l'exécution.

Ce que vous devez faire maintenant est d’abord d’identifier la classe à l’origine du problème (il semble que vous l’ayez déjà fait), puis d’exécuter votre application avec l’option -verbose:class en ligne de commande. Il va vider beaucoup d'informations de chargement de classe sur votre sortie standard et vous serez en mesure de savoir d'où la classe problématique est chargée exactement. 

53
biziclop

Lorsque le compilateur a compilé le code générant l'erreur, il y avait une autre classe avec un champ, et votre classe pouvait accéder à ce champ (en lecture ou en modifiant la valeur).

Au moment de l'exécution, l'autre classe n'a pas de champ avec ce nom, ce qui entraîne l'erreur mentionnée.

Une des raisons pourrait être que la deuxième classe a changé sans que la première soit recompilée . Recompilez toutes vos classes et vous devriez soit avoir une erreur de compilation (qui vous donnera plus d’informations sur la façon de résoudre ce problème), ou la classe référence la bonne classe.

Une autre raison peut être que vous avez une classe dans plusieurs fichiers jar (ou répertoires) dans le chemin de classe (dans différentes versions), ce qui entraîne l'utilisation d'une autre classe par la mauvaise. Vérifiez tous vos pots sur les classes en double.

6
Paŭlo Ebermann

Lorsque vous tracez ces erreurs dans un IDE (Eclipse dans mon cas), il convient de surveiller les dépendances des projets sur lesquels votre projet peut dépendre. Si vous utilisez différentes versions d'une bibliothèque dans différents projets dépendants, le chargeur de chemins de classes peut choisir la mauvaise. Cela inclut un projet dépendant d'un fichier jar créé à partir d'un projet Eclipse, ainsi qu'un autre projet dépendant de ce projet et du projet à partir duquel le fichier jar a été généré. Les classes obsolètes du fichier jar pourraient éventuellement être chargées à la place des classes du projet. 

Exemple:

project1 dépend de project2 et project3

project3 dépend de project2.jar, un fichier jar généré à partir des fichiers de classe dans project2

Un dernier champ statique est ajouté à une classe dans project2, qui est recompilé, alors que project2.jar n'est pas reconstruit.

L'exécution de project1 peut provoquer une exception, car les classes de project2 peuvent être chargées directement du projet OR dans le fichier jar, qui ne contient pas le champ.

4
Ryan O'Meara

Cela signifie que vous avez probablement recompilé une classe dont dépend une autre classe déjà compilée - et non recompilé la classe dépendante.

Par exemple:

public class MyClass {
    public int num;
    public MyClass() { num = 1; }
}

public class MyDependingClass {
    private int foo;
    public MyDependingClass(MyClass init) {
        foo = init.num;
    }
}

Donc, vous recompilez les deux classes, vraisemblablement à la main (un IDE mettrait normalement à jour l'espace de travail du projet pour vous, donc gérez les classes dépendantes).

Et ça a fonctionné.

Plus tard, vous décidez de refactoriser MyClass:

public class MyClass {
    private int innernum;
    public int getNum() {
        return innernum;
    }
    public MyClass() { innernum = 1; }
}

Si vous compilez MyClass et not MyDependingClass, lorsque vous exécutez votre programme et créez une instance de MyDependingClass, vous obtiendrez votre NoSuchFieldError .

La solution à court terme consiste probablement à recompiler toutes les classes de votre espace de travail, ce qui devrait afficher l'erreur.

La solution à long terme consiste à utiliser Eclipse ou NetBeans ou un autre IDE qui gère cela pour vous.

3
Charles Goodwin

C'était assez difficile pour moi, alors j'écris ma solution. 

Je travaillais dans IntelliJ avec Boot tout allait bien, toutes les versions de Java 8 étaient configurées correctement. 

Après quelques heures, j’ai vérifié sur le terminal la version javac et devinez quoi, il a été réglé sur la version 9. Alors, assurez-vous de chercher javac, je connais son caractère contre-intuitif mais supposément, puisque j’avais réglé le jdk sur bash profil, sur IntelliJ, etc., je ne devrais pas avoir à m'en soucier. 

J'espère que ça aide!

0
Kejsi Struga

Comprenez cette erreur:

Ceci est une erreur Java.lang.LinkageError qui se produit lorsque jvm tente de lier les classes loaed. Notez que le code est d'abord compilé (avec les classes dépendantes), puis toutes les classes impliquées sont chargées, puis ces classes sont liées ensemble. 

Pensez à l'erreur: NoSuchField, cela signifie que lorsque vous liez la classe cible, le champ n'y est pas. Mais lors de la compilation, la classe devrait avoir ce champ, sinon le code ne peut pas être compilé. Lorsqu'il est lié, le JVM découvre que ce champ n'est pas là. Donc, la seule raison est que nous compilons avec une classe avec ce champ, et une autre version de cette classe (qui n'a pas ce champ) est chargée et liée. 

Décidez de votre situation entre deux raisons courantes pour cette erreur

En général, la classe mal chargée est soit un code source que vous avez modifié, soit une classe de l’un de vos packages jar dépendants. Nous pouvons décider en recherchant la classe mal chargée en ajoutant un argument -verbose:class au jvm qui tente d’exécuter votre application, dans votre ide. Cet argument affiche toutes les classes chargées dans la console. Dans Eclipse, nous le plaçons dans: clic droit sur votre projet-> exécuter en tant que-> exécuter configrations-> la balise arguments -> VM arguement.

Une fois que vous avez trouvé la classe mal chargée, il s’agit généralement d’une classe pour laquelle vous avez le code source dans votre projet, ou bien dans un package jar dont dépend votre projet . Des situations différentes mènent à des solutions différentes.

Solution pour le cas de code source:

Il est fort probable que vous ayez changé cette classe (en ajoutant le champ dans le code source) sans le recompiler. Cela peut être dû à différentes raisons, mais vous devez supprimer le fichier .class compilé de l'ancienne version compilé et le recompiler pour laisser le nouveau fichier version .class contenir ce champ.

Solution pour le paquetage jar:

Vous devriez essayer de laisser le projet charger le bon paquet JAR. Mais la raison pour laquelle une version différente est impliquée est généralement due au fait qu’elles sont toutes les deux dépendantes (par différentes parties de votre projet). La situation est très simple (et peut ne pas exister dans le projet du monde réel), si vous écrivez des codes qui dépendent directement des deux, il suffit de choisir l’un et d’en supprimer un autre.

Mais il est probable que votre code indirectement en dépend. Et vous ne voulez pas changer votre code (ou changer le moins possible). 

Une solution consiste à écrire votre propre variable ClassLoader avec les deux: Possibilité d’utiliser deux classes Java avec le même nom et le même package? (je ne l'ai pas essayé)

Si vous choisissez de charger la version correcte (celle qui contient une telle variable field) et que votre code qui, indirectement, dépend de la version wrong peut toujours fonctionner (dans l’espoir), nous avons une solution très simple: laissez votre projet choisir la bonne version.

Prenez Eclipse par exemple, vous pouvez utiliser la balise Order and Export dans votre propriété Java Build Path, ajustez simplement l'ordre pour que la version correcte devance la version wrong, car la fonction de la partie Order est la suivante:

D'une part, il fonctionne comme un ordre de résolution des ressources utilisé dans la construction du projet en question (partie "Commande").

Si la version correcte ou la version incorrecte n'apparaît pas ici, vous devez déterminer quel package en dépend et ajuster son ordre, en raison de la fonction de Export part. Lire L'onglet "Commander et exporter" dans "Chemin de construction Java" pour plus de détails.

0
ZhaoGang