Le principal objectif du masquage des informations est de les séparer de la configuration du système afin qu'elles puissent être développées, testées, optimisées, comprises et modifiées indépendamment.
L'accessibilité des classes est uniquement publique ou privée du package (pas de modificateur d'accès).
Si une classe privée de package est appelée par une seule classe, vous devriez envisager d'en faire une classe imbriquée statique privée pour réduire ses chances d'être accédée.
A partir de Java9, le système de modules est adopté comme mécanisme de contrôle d'accès.
Point.java etc. dans la classe java.awt a une accessibilité publique des variables de champ, mais il semble que cela soit fait en raison de problèmes de performances.
S'il s'agit d'une variable de champ immuable, il y a peu de mal même si elle est publique, mais il vaut mieux l'arrêter.
Les classes immuables sont plus faciles à concevoir, à utiliser et à implémenter que les classes variables.
Lors de la création d'une classe immuable, suivez les 5 règles ci-dessous.
Ne fournissez pas de méthodes qui modifient l'état des objets
Rendre impossible l'héritage
Rendre tous les champs définitifs
Rendre tous les champs privés
Empêcher l'accès aux classes variables
Les classes immuables sont de nature thread-safe et ne nécessitent pas de synchronisation.
L'inconvénient des classes immuables est qu'elles créent des objets séparés pour différentes valeurs, ce qui est coûteux. La solution à cela est la classe compagnon. Un exemple spécifique est la classe variable StringBuilder correspondant à la classe immuable String.
En tant que méthode pour ne pas hériter de la classe immuable, il existe une méthode de création publique d'une méthode de fabrique avec le constructeur aussi privé qu'une méthode autre que l'ajout du modificateur final à la classe.
Lorsque BigInteger et BigDecimal ont été implémentés, on ne savait pas que les classes immuables ne devraient pas être héritées, donc l'héritage est possible.
En règle générale, le champ doit être privé final pour se rapprocher le plus possible de la classe immuable. (CountDownLatch est un bon exemple)
Il est dangereux d'hériter d'une classe concrète entre les packages. Il y a deux problèmes possibles:
Les implémentations de Superclass peuvent changer d'une version à l'autre. Les sous-classes peuvent devoir apporter des modifications en conséquence.
Il semble que cela puisse devenir une faille de sécurité lorsqu'une nouvelle méthode est ajoutée à la super classe. (** Ça ne vient pas du tout **)
Pour éviter l'héritage, il peut être réalisé en important une classe qui était à l'origine censée être une superclasse en tant que champ final privé (composition) et en référençant la méthode du champ importé dans chaque méthode (transfert).
L'inconvénient de faire ↑ est qu'il ne convient pas au framework de rappel. Les objets encapsulés ne savent pas lesquels sont encapsulés, ils ne peuvent donc pas effectuer d'appels de sous-classes avec des références à eux-mêmes.
B étend A doit être évité à moins que la relation B soit un A vraiment. Cela n'est pas protégé par la bibliothèque de la plate-forme Java et Stack n'est pas un vecteur, donc Stack ne doit pas hériter de Vector, tout comme la relation entre Properties et HashList.
Pour les méthodes remplaçables, vous devez écrire votre propre utilisation. L'annotation Javadoc pour cela est @implSpec.
En général, une bonne API décrit ce qu'il faut faire et non comment le faire, mais elle est décrite parce que des spécifications détaillées sont nécessaires pour un héritage sûr.
La seule façon de tester la conception de la classe héritée est de créer une sous-classe et de la tester. Si vous visez une bibliothèque largement utilisée, une fois que vous publiez une méthode protégée, elle est presque immuable, alors assurez-vous de créer une sous-classe avant de la publier et de la vérifier.
N'appelez pas de méthodes qui peuvent être corrigées dans le constructeur. Cela est dû au fait que le traitement du constructeur de la superclasse s'exécute toujours avant le traitement du constructeur de la sous-classe, mais "Il existe un traitement tel que l'initialisation du champ de la sous-classe dans le constructeur de la sous-classe et la méthode remplacée a utilisé ce champ. Dans le cas de "l'exécution du traitement", pour montrer un comportement non intuitif.
Fondamentalement, Serializable et Clonable ne doivent pas être implémentés dans la classe conçue comme source d'héritage, mais en cas de circonstances inévitables, les méthodes qui peuvent être remplacées dans la méthode readObject et la méthode clone doivent être utilisées. N'appelle pas. Si vous l'appelez, il peut arriver que vous n'ayez pas créé d'objet clone, mais que vous essayez d'y apporter des modifications.
Il est facile de modifier une classe existante pour implémenter une interface nouvellement née.
L'interface est idéale pour définir des mixins.
Qu'est-ce que mixin? Le code qui n'est pas destiné à fonctionner indépendamment (code que vous souhaitez réutiliser) est défini à l'avance, et si nécessaire, il est mélangé dans la classe (implémentations en Java) pour réutiliser le processus. C'est un mécanisme à encourager.
https://ja.wikipedia.org/wiki/Mixin
http://equj65.net/tech/java8mixin/
Qu'est-ce qu'une méthode d'interface non primitive?
Il existe une classe d'implémentation squelettique qui cache les avantages de l'interface et les avantages des classes abstraites. La classe d'implémentation squelette est appelée AbstractInterface et correspond à AbstractCollection et AbstractSet de CollectionsFW. (À l'origine, ils devraient être appelés SkeletalCollection, SkeletalSet, mais on l'appelle habituellement ainsi)
La classe d'implémentation squelette est conçue pour remplacer certaines des méthodes fournies par l'interface implémentée et laisser le reste des méthodes aux substitutions dans les classes qui héritent de la classe d'implémentation squelette. Sans cette classe d'implémentation squelette, l'implémenteur devrait implémenter l'interface directement et redéfinir toutes les méthodes fournies, mais la prise en sandwich de la classe d'implémentation squelette réduit les méthodes que l'implémenteur devrait surcharger (erronée). Le risque de dépassement est également réduit). ** Est-il acceptable de comprendre que c'est un avantage? ** **
Il y a un risque à ajouter une méthode à une interface existante.
À titre d'exemple, removeIf a été ajouté à la collection en tant que méthode par défaut, mais lorsque ce removeIf est appelé sur le SynchronizedCollection de la bibliothèque Apache Commons qui implémente la collection, il est appelé comme une méthode désynchronisée, rompant la convention d'utilisation de SynchronizedCollection. Sera fait. La bibliothèque Java remplace la méthode removeIf dans Collections.synchronizedCollection pour éviter que cela ne se produise.
Vous ne devez pas créer une interface constante qui définit uniquement des constantes. java.io.ObjectStreamConstants le fait, mais il ne devrait pas être imité. La raison ci-dessous.
Vous devez continuer à implémenter pour maintenir la compatibilité binaire, même si vous n'avez plus besoin de constantes. (** Compatibilité binaire ?? **)
Implémente une interface constante pollue l'espace de noms.
Une autre façon rationnelle de définir les constantes est:
Si la valeur que vous définissez est étroitement liée à une classe existante, ajoutez-la ici.
Constante Utilisez Enum s'il est préférable d'énumérer les valeurs définies.
Sinon, utilisez la classe utilitaire.
// Constant utility class
public interface PhysicalConstants {
static final double AVOGADROS_NUMBER = 6.02214199e23;
static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
static final double ELECTRON_MASS = 9.10938188e-31;
}
// Use of static import to avoid qualifying constants
import static com.effectivejava.science.PhysicalConstants.*;
public class Test {
double atoms(double mols) {
return AVOGADROS_NUMBER * mols;
}
...
// Many more uses of PhysicalConstants justify static import
Recommended Posts