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!

questionAnswers(4)

yourAnswerToTheQuestion