Вопрос или проблема
Создание многоязычного приложения на Java. Возникает ошибка при вставке значения String из файла ресурсов XML R.string
:
public static final String TTT = (String) getText(R.string.TTT);
Вот сообщение об ошибке:
Ошибка: Невозможно сделать статическую ссылку на нестатический метод getText(int) из типа
Context
Как это произошло и как я могу это решить?
Поскольку getText()
является нестатическим, вы не можете вызывать его из статического метода.
Чтобы понять почему, вы должны понять разницу между ними.
Экземплярные (нестатические) методы работают с объектами, которые являются определенного типа (класса). Эти объекты создаются с помощью new следующим образом:
SomeClass myObject = new SomeClass();
Чтобы вызвать экземплярный метод, вы вызываете его на экземпляре (myObject
):
myObject.getText(...)
Однако статический метод/поле может быть вызван только напрямую по типу, например так:
Предыдущее утверждение неверно. Можно также ссылаться на статические поля с помощью ссылки на объект, например myObject.staticMethod()
, но это не рекомендуется, поскольку это не делает ясным, что они являются переменными класса.
... = SomeClass.final
И эти два не могут работать вместе, так как они работают с разными пространствами данных (данные экземпляра и данные класса)
Позвольте мне попытаться объяснить. Рассмотрим этот класс (псевдокод):
class Test {
string somedata = "99";
string getText() { return somedata; }
static string TTT = "0";
}
Теперь у меня есть следующий случай использования:
Test item1 = new Test();
item1.somedata = "200";
Test item2 = new Test();
Test.TTT = "1";
Каковы значения?
Что ж
в item1 TTT = 1 и somedata = 200
в item2 TTT = 1 и somedata = 99
Другими словами, TTT
— это данные, которые разделяются всеми экземплярами этого типа. Поэтому не имеет смысла говорить
class Test {
string somedata = "99";
string getText() { return somedata; }
static string TTT = getText(); // ошибка, на данный момент нет somedata
}
Итак, вопрос в том, почему TTT статический или почему getText() не статический?
Уберите static
, и это должно устранить ошибку – но без понимания того, что делает ваш тип, это всего лишь временное решение до следующей ошибки. Каковы требования к getText()
, которые требуют, чтобы он был нестатическим?
Уже есть несколько хороших ответов с объяснением, почему нельзя смешивать нестатический метод Context
getText()
с вашей static final String
.
Хороший вопрос, который стоит задать: зачем вы хотите это сделать? Вы пытаетесь загрузить String
из ваших ресурсов strings
и заполнить его значение в public static
поле. Я предполагаю, что это нужно для доступа к нему из других ваших классов? Если да, то в этом нет необходимости. Вместо этого передайте Context
в ваши другие классы и вызовите context.getText(R.string.TTT)
из них.
public class NonActivity {
public static void doStuff(Context context) {
String TTT = context.getText(R.string.TTT);
...
}
}
И чтобы вызвать это из вашего Activity
:
NonActivity.doStuff(this);
Это позволит вам получить доступ к вашему String
ресурсу без необходимости использовать public static
поле.
для других, кто ищет это:
Я часто сталкиваюсь с этой проблемой, когда случайно вызываю функцию, используя имя класса, а не имя объекта. Это обычно происходит, потому что я даю им слишком похожие имена : P
т.е.:
MyClass myclass = new MyClass();
// затем позже
MyClass.someFunction();
Это явно статический метод. (хорошо для некоторых случаев)
Но что я действительно хотел сделать (в большинстве случаев) было
myclass.someFunction();
Это такая глупая ошибка, но каждые пару месяцев я трачу около 30 минут, разбираясь с переменными в определениях “MyClass”, чтобы выяснить, что я делаю не так, когда на самом деле это просто опечатка.
Забавная заметка: stack overflow подчеркивает синтаксис, чтобы сделать ошибку действительно очевидной.
Вы можете сделать вашу переменную нестатической
public final String TTT = (String) getText(R.string.TTT);
или сделать метод “getText” статическим (если это вообще возможно)
getText является членом вашего Activity, поэтому его необходимо вызывать, когда “this” существует. Ваша статическая переменная инициализируется, когда ваш класс загружается, до создания вашего Activity.
Поскольку вы хотите, чтобы переменная была инициализирована из строки ресурса, она не может быть статической. Если вы хотите, чтобы она была статической, вы можете инициализировать ее строковым значением.
Вы не можете ссылаться на статическую переменную из нестатического метода.
Чтобы понять это, вам нужно понять разницу между статическим и нестатическим.
Статические переменные являются переменными класса, они принадлежат классу с единственным экземпляром, созданным только при первом создании.
Нестатические переменные инициализируются каждый раз, когда вы создаете объект класса.
Теперь, возвращаясь к вашему вопросу, когда вы используете оператор new(), мы создаем копию каждой нестатической переменной для каждого объекта, но это не так для статических полей. Вот почему возникает ошибка компиляции, если вы ссылаетесь на статическую переменную из нестатического метода.
Этот вопрос не новый, и существующие ответы дают хорошую теоретическую основу. Я просто хочу добавить более прагматичный ответ.
getText – это метод абстрактного класса Context, и для его вызова необходим экземпляр его подкласса (Activity, Service, Application или другой). Проблема в том, что публичные статические финальные переменные инициализируются до того, как хоть один экземпляр Context будет создан.
Существует несколько способов решения этой проблемы:
- Сделать переменную членом переменной (полем) Activity или другого подкласса Context, удалив модификатор static и поместив его в тело класса;
- Сохранить ее статической и отложить инициализацию на более поздний срок (например, в методе onCreate);
- Сделать ее локальной переменной в месте фактического использования.
Да, вы можете вызвать нестатический метод из статического метода, потому что, как мы должны помнить, сначала мы можем создать объект, на котором мы можем легко вызывать нестатический метод из статического метода.
Ответ или решение
Ошибка "Не удается сделать статическую ссылку на нестатический метод" является распространенной проблемой среди разработчиков Java, особенно в контексте использования ресурсов в Android. Давайте рассмотрим причины появления этой ошибки и способы ее устранения, чтобы вы могли избежать подобной ситуации в будущем.
Причины ошибки
Ошибка возникает потому, что метод getText(int)
является нестатическим методом, который принадлежит объектам класса Context
. Такой метод требует экземпляра класса Context
, чтобы его вызвать. В вашем случае вы пытаетесь вызвать этот метод из статического контекста, то есть из статической переменной. В Java статические методы и поля относятся к классу в целом, а не к его экземплярам.
public static final String TTT = (String) getText(R.string.TTT);
В этом коде вы пытаетесь получить строку из ресурсов, вызывая метод getText()
на уровне класса, что и приводит к ошибке.
Решение проблемы
Существует несколько способов обойти эту ошибку:
-
Изменение области видимости переменной: Сделайте переменную
TTT
нестатической и инициализируйте её в методе, где у вас есть доступ к объектуContext
. Например:public class MyActivity extends AppCompatActivity { public final String TTT; public MyActivity() { this.TTT = getText(R.string.TTT).toString(); } }
-
Инициализация статической переменной в методе жизненного цикла: Если объект
Context
доступен в методах жизненного цикла вашего активити, таких какonCreate()
, вы можете инициализировать переменнуюTTT
там:public class MyActivity extends AppCompatActivity { public static String TTT; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); TTT = getText(R.string.TTT).toString(); } }
-
Передача
Context
в другие компоненты: Лучше всего передавать объектContext
в классы или методы, которые требуют доступ к ресурсам. Например:public class NonActivity { public static void doStuff(Context context) { String TTT = context.getText(R.string.TTT).toString(); // Дальнейшая обработка строки } } // В вашем Activity вы можете вызвать: NonActivity.doStuff(this);
-
Локальная переменная: Если строка будет использоваться только в одном месте, можно определить
TTT
как локальную переменную:String TTT = getText(R.string.TTT).toString();
Заключение
Ошибка "Не удается сделать статическую ссылку на нестатический метод" демонстрирует важность понимания различий между статическими и нестатическими контекстами в Java. Если вы будете следовать предложенным рекомендациям, вы сможете избежать подобных ошибок, а также улучшить архитектуру вашей программы, укрепив использование принципов инкапсуляции и модульности. Понимание этих основ не только поможет вам избежать ошибок, но и улучшит качество вашего кода, что в конечном итоге сведет к минимуму количество потенциальных проблем в процессе разработки.