Java: Definicja metod i zmiennych wewnątrz stałej enum
Robiłem eksperymenty i przypadkowo napisałem kod, który jest bardzo dziwny i nie rozumiem wszystkiego. Byłem nawet zaskoczony, że mogę go skompilować. To wygląda tak:
enum Foo {
VALUE_1 {
public int myVariable = 1;
},
VALUE_2 {
public void myMethod() {
//
}
},
VALUE_3;
}
Zgodnie z oczekiwaniami, dostęp do takiego elementu nie jest możliwy w następujący sposób:
Foo.VALUE_2.myMethod();
Powodem jest to, że kompilator będzie szukał tej metody w samym wyliczeniu.
Przypuszczałem, że nie można uzyskać dostępu do tych metod i zmiennych spoza wyliczenia. Z tego powodu próbowałem utworzyć konstruktor parametryczny i nazwać go zmienną wewnętrzną:
enum Foo {
VALUE(internalVariable) {
int internalVariable = 1;
};
private Foo(int param) {
//
}
}
Nie było możliwe skompilowanie takiej konstrukcji. Teraz zastanawiałem się, jaki jest sens definiowania czegoś wewnątrz stałej, jeśli nie ma możliwości uzyskania do niej dostępu.
Próbowałem utworzyć metody o tej samej nazwie w stałej, jak również w samym wyliczeniu, aby sprawdzić, czy w jakiś sposób koliduje. Nie!
enum Foo {
VALUE_1 {
int myVariable = 1;
public int myMethod() {
return myVariable;
}
},
VALUE_2 {
//
};
public int myMethod() {
return 0;
}
}
I oto nadchodzi zabawny moment! Próbowałem kontynuować wywołanie metody myMethod () wewnątrz wyliczenia i właściwie zorientowałem się, jak działa ta magia Java. Metody, które są zdefiniowane wewnątrz stałej, zastępują metody zdefiniowane wewnątrz wyliczenia.
Foo.VALUE_1.myMethod(); // Returns 1
Foo.VALUE_2.myMethod(); // Returns 0
Nie możemy jednak przesłonić zmiennej, prawda? Byłem więc ciekawy, jak działa tylko ze zmiennymi.
enum Foo {
VALUE_1 {
public int myVariable = 1;
},
VALUE_2 {
//
};
public int myVariable = 0;
}
....
System.out.println(Foo.VALUE_1.myVariable); // Returns 0
System.out.println(Foo.VALUE_2.myVariable); // Returns 0
Teraz w końcu mam pytania:
Dlaczego nie otrzymuję żadnego błędu, jeśli tworzęmetoda publiczna wewnątrz stałej i lewe wyliczenie puste bez tej metody? W takim przypadku metoda, którą właśnie zdefiniowałemnie można zadzwonić w ogóle. Czy się mylę?
Aktualizacja: Wiem, że wyliczenie może implementować interfejs. Jeśli jednak nie powiedziałem tego konkretnie, cały kod jest bezcelowy.
Ktoś zauważył, że nawet jeśli nie można uzyskać dostępu do metody z języka w normalny sposób, nadal można użyć odbicia. Cóż ... Dlaczego nie zaprojektujemyniedostępny słowo kluczowe?
inaccessible void magicalMethod() {
//
}
Taka metoda zostanie wkompilowana w plik * .class. Kiedy chcesz go użyć, musisz samodzielnie wczytać kod bajtowy i zinterpretować go.
Po prostu nie mogę zrozumieć, dlaczego można zdefiniować nieosiągalną metodę. Jedynym powodem, dla którego myślę, że programista działa i nie ma jeszcze definicji interfejsu. Przygotowuje więc kod pojedynczych metod i później doda słowo kluczowe „implements”. Poza tym jest to nielogiczne, nadal wymagałoby takiej metody we wszystkich stałych.
Myślę, że powinno to zakończyć się błędem, a nie tylko ostrzeżeniem o nieużywanej metodzie. Możesz zapomnieć dodać klauzulę „implement” lub zdefiniować metodę w wyliczeniu (która zostałaby przesłonięta) i zrealizuje to tuż po pierwszym użyciu. Java jest bardzo surowym językiem, więc spodziewałbym się tego zachowania.
Dlaczego nie otrzymuję żadnego błędu, jeśli tworzęzmienna publiczna (lub pole, a dokładniej) wewnątrz stałej? W żadnym wypadku nie można uzyskać do niego dostępu (z zewnątrz). Dlatego modyfikator „public” nie ma tutaj sensu.
Aktualizacja: To mniej więcej to samo, co w poprzednim punkcie, z wyjątkiem tego, że modyfikator widoczności jest tutaj całkowicie bezużyteczny. To naprawdę nie ma znaczenia, czy jest publiczne, chronione czy prywatne, ponieważ i tak nie będziesz mieć do niego dostępu. Myślę, że to błąd.
Dlaczego jest to możliwezdefiniuj klasę (bez modyfikatorów widoczności), alenie interfejs? Tak, prawdopodobnie nie chciałbyś pisać tak brutalnego wyliczenia, że musiałbyś zdefiniować klasy wewnątrz stałej, a nawet użyć dziedziczenia. Ale jeśli jest możliwe zdefiniowanie klas i klas abstrakcyjnych, wydaje się to trochę dziwne.
Aktualizacja: Z pewnością nie jest to coś, czego potrzebujesz regularnie, ale rozumiem, że może być przydatne. Ale dlaczego ogranicza się tylko do klas i nie można zdefiniować interfejsów?
enum Foo {
VALUE {
class MyClass {
// OK
}
abstract class MyAbstractClass {
// OK
}
interface MyInterface {
// FAIL. It won't compile.
}
}
}
Czy korzystałeś gdzieś z takiej funkcjonalności? Mogę sobie wyobrazić, że może to być przydatne, ale jest trochę mylące. Poza tym, gdy szukałem zasobów na ten temat, niczego nie znalazłem.
Aktualizacja: Chciałbym zobaczyć jakiś praktyczny przykład z metodami nadpisanymi w enum stałej treści klasy. Czy widziałeś to w jakimś projekcie open source?
Środowisko:
$ java -version
java version "1.7.0_21"
OpenJDK Runtime Environment (IcedTea 2.3.9) (7u21-2.3.9-0ubuntu0.12.10.1)
OpenJDK 64-Bit Server VM (build 23.7-b01, mixed mode)
Dziękujemy za poświęcony czas i odpowiedzi!