Impossible de faire une référence statique à la méthode non statique

102

Construire une application multilingue en Java. Obtention d'une erreur lors de l'insertion de la valeur de chaîne à partir du R.stringfichier XML de ressource:

public static final String TTT =  (String) getText(R.string.TTT);

Voici le message d'erreur:

Erreur: impossible de faire une référence statique à la méthode non statique getText (int) à partir du type Contexte

Comment cela est-il causé et comment puis-je le résoudre?

Chen M
la source
1
Pourquoi en avez-vous besoin pour être statique pour une «application multilingue»? Je ne comprends pas vraiment.
xil3
3
Ne stockez jamais de ressources de chaîne dans des membres de données statiques. Demandez-les toujours via getString()quand vous en avez besoin. De cette façon, votre application s'adapte correctement aux utilisateurs qui changent la langue choisie.
CommonsWare

Réponses:

143

Puisqu'il getText()n'est pas statique, vous ne pouvez pas l'appeler à partir d'une méthode statique.

Pour comprendre pourquoi, vous devez comprendre la différence entre les deux.

Les méthodes d'instance (non statiques) fonctionnent sur des objets d'un type particulier (la classe). Ceux-ci sont créés avec le nouveau comme ceci:

SomeClass myObject = new SomeClass();

Pour appeler une méthode d'instance, vous l'appelez sur l'instance ( myObject):

myObject.getText(...)

Cependant, une méthode / un champ statique ne peut être appelé directement que sur le type, disons comme ceci: L'instruction précédente n'est pas correcte. On peut également faire référence à des champs statiques avec une référence d'objet comme myObject.staticMethod() mais cela est déconseillé car cela n'indique pas clairement qu'il s'agit de variables de classe.

... = SomeClass.final

Et les deux ne peuvent pas fonctionner ensemble car ils opèrent sur des espaces de données différents (données d'instance et données de classe)

Laissez-moi essayer de vous expliquer. Considérez cette classe (psuedocode):

class Test {
     string somedata = "99";
     string getText() { return somedata; } 
     static string TTT = "0";
}

Maintenant, j'ai le cas d'utilisation suivant:

Test item1 = new Test();
 item1.somedata = "200";

 Test item2 = new Test();

 Test.TTT = "1";

Quelles sont les valeurs?

bien

in item1 TTT = 1 and somedata = 200
in item2 TTT = 1 and somedata = 99

En d'autres termes, TTTest une donnée partagée par toutes les instances du type. Donc ça n'a aucun sens de dire

class Test {
         string somedata = "99";
         string getText() { return somedata; } 
  static string TTT = getText(); // error there is is no somedata at this point 
}

La question est donc de savoir pourquoi TTT est statique ou pourquoi getText () n'est-il pas statique?

Retirez le staticet il devrait dépasser cette erreur - mais sans comprendre ce que fait votre type, ce n'est qu'un plâtre qui colle jusqu'à la prochaine erreur. Quelles sont les exigences getText()qui exigent qu'il soit non statique?

Preet Sangha
la source
il est statique car je l'appelle à partir de plusieurs fichiers de mon projet. quand j'ai supprimé le "statique" le code d'erreur a disparu, mais maintenant j'ai beaucoup d'erreurs dans d'autres fichiers qui utilisent cette variable.
Chen M
Mais c'est mon point. Vous devez comprendre quand les deux peuvent être utilisés.
Preet Sangha
quand j'ajoute la ligne "Constantes notifications_values ​​= new Constants (); à ma classe d'activité principale, il compile OK mais dans l'émulateur il plante lorsque cette activité s'exécute
Chen M
12

Il y a déjà de bonnes réponses avec des explications sur les raisons pour lesquelles le mélange de la Contextméthode non statique getText()ne peut pas être utilisé avec votre static final String.

Une bonne question à poser est: pourquoi voulez-vous faire cela? Vous essayez de charger un à Stringpartir de votre stringsressource et de renseigner sa valeur dans un public staticchamp. Je suppose que c'est pour que certaines de vos autres classes puissent y accéder? Si tel est le cas, il n'est pas nécessaire de le faire. Au lieu de cela, passez un Contextà vos autres classes et appelez à context.getText(R.string.TTT)partir d'eux.

public class NonActivity {

    public static void doStuff(Context context) {
        String TTT = context.getText(R.string.TTT);
        ...
    }
}

Et pour appeler cela depuis votre Activity:

NonActivity.doStuff(this);

Cela vous permettra d'accéder à votre Stringressource sans avoir besoin d'utiliser un public staticchamp.

dave.c
la source
1
merci beaucoup, j'ai changé tous les fichiers selon votre recommandation.
Chen M
J'essayais de le faire, mais pour un tableau de chaînes, et avec String a[] = context.getTextArray(R.array.myStringArray); ; cela, cependant, me donne une erreur The method getTextArray(int) is undefined for the type Context- pourquoi serait-il indéfini alors qu'il fonctionne avec getText?
auspicious99
1
@ auspicious99 simplement parce que a Contextn'a pas de méthode appelée getTextArray, mais a getText. Peut-être pensez-vous à Resourcesqui agetTextArray
dave.c
Ah merci! Passé dans des ressources au lieu d'un contexte (de l'activité à la non-activité), et mon getStringArray a fonctionné.
auspicious99
9

pour les autres qui trouvent cela dans la recherche:

J'obtiens souvent celui-ci lorsque j'appelle accidentellement une fonction en utilisant le nom de classe plutôt que le nom de l'objet. Cela se produit généralement parce que je leur donne des noms trop similaires: P

c'est à dire:

MyClass myclass = new MyClass();

// then later

MyClass.someFunction();

C'est évidemment une méthode statique. (bon pour quelque chose) Mais ce que je voulais vraiment faire (dans la plupart des cas l'était)

myclass.someFunction();

C'est une erreur tellement stupide, mais tous les deux mois, je perds environ 30 minutes à jouer avec les variables dans les définitions de "MyClass" pour déterminer ce que je fais mal alors qu'en réalité, c'est juste une faute de frappe.

Note amusante: le débordement de pile met en évidence la syntaxe pour rendre l'erreur vraiment évidente ici.

SpiRail
la source
Votre IDE ne le souligne-t-il pas aussi? Je suppose que vous pouvez le configurer pour le faire :)
Matthias Meid
2

Vous pouvez soit rendre votre variable non statique

public final String TTT =  (String) getText(R.string.TTT);

ou rendre la méthode "getText" statique (si possible)

Kellindil
la source
2

getText est un membre de votre activité, il doit donc être appelé lorsque "this" existe. Votre variable statique est initialisée lorsque votre classe est chargée avant la création de votre activité.

Puisque vous souhaitez que la variable soit initialisée à partir d'une chaîne Resource, elle ne peut pas être statique. Si vous voulez qu'il soit statique, vous pouvez l'initialiser avec la valeur String.

Robby Pond
la source
2

Vous ne pouvez pas faire référence à une variable statique à partir d'une méthode non statique. Pour comprendre cela, vous devez comprendre la différence entre statique et non statique.

Les variables statiques sont des variables de classe, elles appartiennent à la classe avec leur seule instance, créée à la première seulement. Les variables non statiques sont initialisées chaque fois que vous créez un objet de la classe.

Pour en venir à votre question, lorsque vous utilisez l'opérateur new (), nous créerons une copie de chaque fichier non statique pour chaque objet, mais ce n'est pas le cas pour les champs statiques. C'est pourquoi cela donne une erreur de compilation si vous référencez une variable statique à partir d'une méthode non statique.

Krishna
la source
0

Cette question n'est pas nouvelle et les réponses existantes donnent une bonne base théorique. Je veux juste ajouter une réponse plus pragmatique.

getText est une méthode de la classe abstraite Context et pour l'appeler, il faut une instance de sa sous-classe (Activity, Service, Application ou autre). Le problème est que les variables finales statiques publiques sont initialisées avant la création de toute instance de Context.

Il existe plusieurs façons de résoudre ce problème:

  1. Faire de la variable une variable membre (champ) de l'activité ou d'une autre sous-classe de contexte en supprimant le modificateur statique et en le plaçant dans le corps de la classe;
  2. Gardez-le statique et retardez l'initialisation à un point ultérieur (par exemple dans la méthode onCreate);
  3. Faites-en une variable locale à la place de l'utilisation réelle.
dev.bmax
la source