Nie można utworzyć statycznego odwołania do metody niestatycznej

102

Budowanie aplikacji wielojęzycznej w Javie. Pojawia się błąd podczas wstawiania wartości ciągu z R.stringpliku XML zasobu:

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

Oto komunikat o błędzie:

Błąd: nie można utworzyć statycznego odwołania do niestatycznej metody getText (int) z typu Context

Jak to się dzieje i jak mogę to rozwiązać?

Chen M
źródło
1
Dlaczego ma być statyczny dla „aplikacji wielojęzycznej”? Naprawdę nie rozumiem.
xil3
3
Nigdy nie przechowuj zasobów ciągów w statycznych elementach członkowskich danych. Zawsze poproś o nie, getString()gdy ich potrzebujesz. W ten sposób Twoja aplikacja odpowiednio dostosuje się do użytkowników zmieniających wybrany język.
CommonsWare

Odpowiedzi:

143

Ponieważ getText()nie jest statyczny, nie można go wywołać z metody statycznej.

Aby zrozumieć dlaczego, musisz zrozumieć różnicę między nimi.

Metody instancji (niestatyczne) działają na obiektach określonego typu (klasy). Są one tworzone za pomocą nowego w następujący sposób:

SomeClass myObject = new SomeClass();

Aby wywołać metodę instancji, należy wywołać ją na instancji ( myObject):

myObject.getText(...)

Jednak statyczną metodę / pole można wywołać tylko bezpośrednio na typie, powiedzmy w ten sposób: Poprzednie stwierdzenie nie jest poprawne. Można również odwoływać się do pól statycznych z odniesieniem do obiektu, myObject.staticMethod() ale jest to odradzane, ponieważ nie wyjaśnia, że ​​są to zmienne klasowe.

... = SomeClass.final

Nie mogą ze sobą współpracować, ponieważ działają w różnych przestrzeniach danych (dane instancji i dane klas)

Spróbuję to wyjaśnić. Rozważ tę klasę (psuedocode):

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

Teraz mam następujący przypadek użycia:

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

 Test item2 = new Test();

 Test.TTT = "1";

Jakie są wartości?

Dobrze

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

Innymi słowy, TTTjest to odniesienie, które jest wspólne dla wszystkich wystąpień typu. Więc nie ma sensu mówić

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

Zatem pytanie brzmi: dlaczego TTT jest statyczne lub dlaczego getText () nie jest statyczne?

Usuń staticten błąd i powinien minąć ten błąd - ale bez zrozumienia, co robi twój typ, to tylko przylepny plaster do następnego błędu. Jakie są wymagania getText(), aby był on niestatyczny?

Preet Sangha
źródło
jest statyczny, ponieważ nazywam go z kilku plików w moim projekcie. kiedy usunąłem „statyczny” kod błędu zniknął, ale teraz mam wiele błędów w innych plikach, które używają tej zmiennej.
Chen M
Ale o to mi chodzi. Musisz zrozumieć, kiedy można użyć tych dwóch.
Preet Sangha
kiedy dodam wiersz "Constants notifications_values ​​= new Constants (); do mojej głównej klasy działania kompiluje się OK, ale w emulatorze ulega awarii, gdy jest uruchomiona
Chen M
12

Istnieje już kilka dobrych odpowiedzi wraz z wyjaśnieniami, dlaczego nie można zastosować mieszanki Contextmetody niestatycznej getText()z Twoim static final String.

Dobre pytanie, które warto zadać, brzmi: dlaczego chcesz to zrobić? Próbujesz załadować a Stringze swojego stringszasobu i wypełnić jego wartość w public staticpolu. Zakładam, że to jest tak, że niektóre z twoich innych klas mają do niego dostęp? Jeśli tak, nie ma takiej potrzeby. Zamiast tego przejdź Contextdo innych klas i zadzwoń context.getText(R.string.TTT)z ich wnętrza.

public class NonActivity {

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

I zadzwonić do tego z twojego Activity:

NonActivity.doStuff(this);

Umożliwi to dostęp do Stringzasobów bez konieczności korzystania z public staticpola.

dave.c
źródło
1
bardzo dziękuję, zmieniłem wszystkie pliki zgodnie z twoją rekomendacją.
Chen M,
Próbowałem to zrobić, ale dla tablicy łańcuchowej iz String a[] = context.getTextArray(R.array.myStringArray); ; daje mi jednak błąd The method getTextArray(int) is undefined for the type Context- dlaczego miałby być niezdefiniowany, skoro działa z getText?
pomyślny
1
@ auspicious99 po prostu dlatego, że a Contextnie ma wywoływanej metody getTextArray, ale ją ma getText. Być może myślisz o tym, Resourcesco magetTextArray
dave.c
Ach, dzięki! Przekazano zasoby zamiast kontekstu (od działania do nieaktywności), a moja getStringArray zadziałała.
pomyślny 99
9

dla innych, którzy znajdą to w wyszukiwaniu:

Często otrzymuję ten komunikat, gdy przypadkowo wywołuję funkcję przy użyciu nazwy klasy, a nie nazwy obiektu. Zwykle dzieje się tak, ponieważ nadaję im zbyt podobne nazwy: P

to znaczy:

MyClass myclass = new MyClass();

// then later

MyClass.someFunction();

Jest to oczywiście metoda statyczna. (dobre dla niektórych) Ale to, co naprawdę chciałem zrobić (w większości przypadków było)

myclass.someFunction();

To taki głupi błąd, ale co kilka miesięcy marnuję około 30 minut na majstrowanie przy zmiennych w definicjach „MyClass”, aby dowiedzieć się, co robię źle, kiedy naprawdę, to tylko literówka.

Zabawna uwaga: przepełnienie stosu podkreśla składnię, aby błąd był tutaj naprawdę oczywisty.

SpiRail
źródło
Czy twoje IDE też tego nie podkreśla? Myślę, że możesz to tak skonfigurować :)
Matthias Meid
2

Możesz ustawić zmienną jako niestatyczną

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

lub uczyń metodę „getText” statyczną (jeśli to w ogóle możliwe)

Kellindil
źródło
2

getText jest członkiem twojego działania, więc musi zostać wywołane, gdy istnieje „this”. Zmienna statyczna jest inicjowana, gdy klasa jest ładowana przed utworzeniem działania.

Ponieważ chcesz, aby zmienna była inicjowana z ciągu zasobów, nie może być statyczna. Jeśli chcesz, aby był statyczny, możesz zainicjować go wartością String.

Robby Pond
źródło
2

Nie można odwołać się do zmiennej statycznej z metody niestatycznej. Aby to zrozumieć, musisz zrozumieć różnicę między statycznymi i niestatycznymi.

Zmienne statyczne są zmiennymi klasowymi, należą do klasy, która ma tylko jedną instancję, utworzoną tylko w pierwszej. Zmienne niestatyczne są inicjowane za każdym razem, gdy tworzysz obiekt klasy.

Przechodząc do twojego pytania, kiedy użyjesz operatora new (), utworzymy kopię każdego pola niestatycznego dla każdego obiektu, ale tak nie jest w przypadku pól statycznych. Dlatego daje błąd czasu kompilacji, jeśli odwołujesz się do zmiennej statycznej z metody niestatycznej.

Kryszna
źródło
0

To pytanie nie jest nowe, a istniejące odpowiedzi dają dobre podstawy teoretyczne. Chcę tylko dodać bardziej pragmatyczną odpowiedź.

getText jest metodą klasy abstrakcyjnej Context i aby ją wywołać, potrzebna jest instancja jej podklasy (Activity, Service, Application lub inna). Problem polega na tym, że publiczne statyczne zmienne końcowe są inicjowane przed utworzeniem jakiejkolwiek instancji Context.

Istnieje kilka sposobów rozwiązania tego problemu:

  1. Ustaw zmienną jako zmienną składową (pole) działania lub innej podklasy klasy Context, usuwając modyfikator statyczny i umieszczając go w treści klasy;
  2. Zachowaj statyczność i opóźnij inicjalizację do późniejszego punktu (np. W metodzie onCreate);
  3. Ustaw ją jako zmienną lokalną w miejscu faktycznego użycia.
dev.bmax
źródło