Quel est le niveau d’access des variables dans les énumérations par défaut

Récemment, je suis tombé sur le code suivant:

enum Animals { DOG("woof"), CAT("meow"), FISH("burble"); Ssortingng sound; Animals(Ssortingng s) { sound = s; } } class TestEnum { static Animals a; public static void main(Ssortingng[] args) { System.out.println(a.DOG.sound + " " + a.FISH.sound);//Expected compilation failure } } 

Je m’attendrais à ce que le code ne comstack pas à cause de cette partie a.DOG.sound . Mais à ma grande surprise, ce n’est pas le cas. J’ai parcouru tout autour, y compris la documentation officielle, pour connaître le niveau d’access, mais je n’ai rien trouvé. Est-ce public ou par défaut ?

Le niveau d’access implicite d’un champ déclaré manuellement dans une énumération est package-private , exactement le même que dans les classes normales. Ainsi, votre champ sound sera accessible si et seulement si Animals et TestEnum sont dans le même package.


J’ai essayé de trouver une citation solide à ce sujet dans le JLS mais les règles d’énumération sont malheureusement dispersées un peu partout, spécifiées comme des exceptions aux règles pour les classes normales, et les règles doivent donc être assemblées à partir de pièces. JLS §6.6.1 Détermination de l’accessibilité dit:

Un membre (classe, interface, champ ou méthode) d’un type de référence ou un constructeur d’un type de classe n’est accessible que si le type est accessible et que le membre ou le constructeur est déclaré pour autoriser l’access:

  • Si le membre ou le constructeur est déclaré public , l’access est autorisé.

    Tous les membres d’interfaces dépourvues de modificateurs d’access sont implicitement public .

  • Sinon, si le membre ou le constructeur est déclaré protected , l’access n’est autorisé que si l’une des conditions suivantes est remplie:

    • L’access au membre ou au constructeur se fait depuis le package contenant la classe dans laquelle le membre ou le constructeur protected est déclaré.

    • L’access est correct comme décrit au § 6.6.2.

  • Sinon, si le membre ou le constructeur est déclaré avec un access à un package, l’access n’est autorisé que s’il est accessible depuis le package dans lequel le type est déclaré.

    Un membre de la classe ou un constructeur déclaré sans modificateur d’access a implicitement access au package.

  • Sinon, le membre ou le constructeur est déclaré privé et l’access est autorisé si, et seulement si, il se produit dans le corps de la classe de niveau supérieur (§7.6) qui inclut la déclaration du membre ou du constructeur.

Cela signifie que les types de classe ( class et enum ) obtiennent la règle selon laquelle les membres ont implicitement access au package, tandis que les types d’ interface ( interface et @interface ) obtiennent la règle selon laquelle les membres sont implicitement publics.

D’après ce qui précède, il n’est pas immédiatement évident que “membre de la classe” inclut les énumérations dans sa définition de “classe”, mais c’est le cas. En raison de leur large chevauchement, les groupes JLS énumèrent des classes à de nombreux endroits (et les types d’annotation sont également groupés avec des interfaces). JLS §8.9 Enum Types dit “Une déclaration enum spécifie un nouveau type enum, un type spécial de type de classe”; et JLS §8.2 Membres du groupe indique clairement que le terme “membres du groupe” désigne les membres d’un “type de classe”.

Cependant, les énumérations ont deux règles spéciales concernant l’accessibilité pour les membres qui ne figurent pas dans la section citée ci-dessus:

  1. Les constantes enum elles-mêmes (dans votre exemple, elles sont DOG , CAT et FISH ) peuvent ne pas avoir de modificateurs d’access explicites ( JLS §8.9.1 ) et sont toujours public static final champs public static final du type enum ( JLS §8.9.3 ). .

  2. Les constructeurs d’énumération doivent être privés (pour empêcher les utilisateurs de créer des constantes supplémentaires) et sont implicitement privés ( JLS §8.9.2 ).

En dehors de ces deux exceptions, les règles d’access des classes normales s’appliquent aux énumérations. Si votre enum Animals est rendu public , toutes ses constantes sont accessibles en dehors du package, mais le champ sound est package-private et n’est accessible en dehors du package que si vous le déclarez explicitement public .

Si vous pouvez importer enum vous pouvez accéder aux constantes enum

Si enum est accessible (spécifiquement déclaré public ) en dehors du package , ses éléments le sont également et si aucun modificateur n’est spécifié, il ne sera accessible que dans le package . Par défaut, les constantes enum sont accessibles si enum est accessible signifie que celles-ci sont public static final par défaut.

Je m’attendrais à ce que le code ne comstack pas à cause de cette partie a.DOG.sound. Mais à ma grande surprise, ce n’est pas le cas.

Ce sera la même chose que n’importe quelle autre variable peut se comporter dans n’importe quelle classe si aucun modificateur par défaut n’est accessible dans le paquet uniquement.