Dans les bibliothèques Java, nous voyons souvent des chaînes d'objets de type utilisés comme des ** valeurs ** (ci-après dénommées «clés») pour identifier des objets tels que des clés et des noms de propriétés. Par exemple, la classe java.util.Properties
utilisée pour introduire la liste de propriétés, la classe java.beans.PropertyChangeSupport
utilisée pour envoyer des événements tels que des notifications de changement de propriété, etc. On dit qu'elle est en déclin et qu'elle est toujours comparée à JavaFx ~~ La classe java.awt.CardLayout
, qui est l'un des gestionnaires de mise en page de Swing ...
Dans la méthode utilisant le type String, si la valeur contient une erreur typographique ** ou si le nom de la clé est modifié en raison d'un changement dans l'implémentation **, l'objet ne peut pas être référencé correctement et un problème se produit. Tu peux.
Exemple d'échec d'acquisition de valeur en raison d'une faute de frappe dans le nom de la clé
Map<String, String> entries = new HashMap<>() {{
put("hoge", "Hoge");
put("huga", "Fuga");
put("piyo", "Piyo");
}};
System.out.println(entries.get("hoge")); //Sortie: Hoge
System.out.println(entries.get("hige")); //Sortie: null (acquisition échouée)
Exemple d'échec de l'acquisition de valeur en raison d'un changement d'implémentation
Map<String, String> entries = new HashMap<>() {{
put("foo", "Huh"); //Modifications de la mise en œuvre
put("huga", "Fuga");
put("bar", "Bah"); //Modifications de la mise en œuvre
}};
System.out.println(entries.get("hoge")); //Sortie: null (acquisition échouée)
System.out.println(entries.get("huga")); //Sortie: Fuga
Un tel danger peut être éliminé en introduisant l'interface de marqueur [^ interface de marqueur]. Cette fois, je voudrais expliquer l'utilisation de la classe CardLayout introduite plus tôt à titre d'exemple.
Ensuite, considérez l'écran présenté par le code réduit A.
<détails> <résumé> Code A </ résumé>
python
public class App {
public static void main(String[] args) {
new JFrame("Sample") {{
setSize(350, 300);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
//Génération CardLayout
CardLayout cards = new CardLayout();
//Centre du cadre
JLabel[] labels = {
new JLabel("Card 1"),
new JLabel("Card 2"),
new JLabel("Card 3"),
new JLabel("Card 4")
};
Font fnt = new Font("Meilio", Font.PLAIN, 40);
JPanel center = new JPanel();
center.setLayout(cards);
for (int i = 0; i < labels.length; i++) {
labels[i].setFont(fnt);
labels[i].setVerticalAlignment(JLabel.CENTER);
labels[i].setHorizontalAlignment(JLabel.CENTER);
center.add(labels[i], "Card" + (i + 1));
}
//Bas du cadre
JButton[] buttons = {
new JButton("Card 1"),
new JButton("Card 2"),
new JButton("Card 3"),
new JButton("Card 4")
};
JPanel south = new JPanel();
for (int i = 0; i < buttons.length; i++) {
int l_i = i;
buttons[i].addActionListener(e -> cards.show(center, "Card" + (l_i + 1)));
south.add(buttons[i]);
}
//Ajout d'un panneau au cadre
add(center, BorderLayout.CENTER);
add(south, BorderLayout.SOUTH);
}};
}
}
En exécutant ce code et en cliquant sur chaque bouton, vous pouvez basculer entre les quatre étiquettes comme indiqué ci-dessous.
Où il est dans le code A
python
buttons[i].addActionListener(e -> cards.show(center, "Card" + (l_i + 1)));
Au moment où vous confondez «Carte» avec ** «Cerd» «**, la commutation ne fonctionnera pas correctement comme suit.
En effet, la méthode show ne peut plus faire référence à chaque étiquette associée au panneau au centre du cadre par la méthode add qui spécifie les identificateurs des quatre étiquettes dans le deuxième argument.
python
center.add(labels[i], "Card" + (i + 1));
buttons[i].addActionListener(e -> cards.show(center, "Cerd" + (l_i + 1))); // "Card"ne pas!
Cela ne cause pas d'erreur de compilation, donc à moins que vous ne le remarquiez ou que vous ne demandiez à quelqu'un de vous le dire, ce n'est pas grave si vous ne connaissez pas la cause du problème.
Donc, nous allons introduire une interface de marqueurs.
Cela n'a pas de sens d'introduire simplement une interface de marqueur, alors préparez une énumération, définissez les clés et demandez à cette énumération d'implémenter l'interface de marqueur.
python
//Interface de marqueur
interface CardKey {}
//Énumérateur qui implémente l'interface de marqueur
enum Card implements CardKey {
CARD1, CARD2, CARD3, CARD4;
}
De plus, étant donné que la clé ajoutée et la méthode show apparues précédemment ne peuvent pas spécifier la clé définie comme argument en l'état, définissez la classe d'utilitaire réduite suivante afin que le composant à afficher en basculant avec la clé puisse être associé. ..
<détails> Étant donné que le gestionnaire de disposition du panneau associé à la classe utilitaire n'est pas CardLayout et que le comportement censé être nul pour les clés et les composants pris comme arguments de chaque méthode ne peut pas être réalisé, la gestion des exceptions est effectuée. Créez un objet de cette classe d'utilitaire et préparez un tableau de chaque clé afin que vous puissiez le transformer en boucle. Le reste est en code A Partie de Si vous le remplacez par, vous n'avez pas à vous soucier des fautes de frappe ou des changements d'implémentation qui causent les problèmes ci-dessus. Cette méthode est réalisée en utilisant la représentation sous forme de chaîne de caractères de la clé (énumérateur) obtenue par Cependant, comme il s'agit d'un phénomène qui se produit car la clé n'est identifiée que par le nom de l'énumérateur, elle se trouve dans la classe utilitaire. Partie de En réécrivant comme, l'identification de la clé sera faite avec ** nom de classe pleinement qualifié [^ nom de classe complet] + nom de l'énumération ** de l'énumération, et cela fonctionnera normalement. Il lance également ʻArrayIndexOutOfBoundsException` lors de la boucle si le nombre de clés et de composants ne correspondent pas. Ce domaine peut être amélioré en rendant la classe utilitaire un peu plus désordonnée. [^ Interface marqueur]: Une interface marqueur est une interface qui n'implémente rien à l'intérieur. Il est souvent utilisé pour donner du sens à la classe à implémenter. [^ toString]: Même si vous remplacez [^ Nom de classe complet]: le nom de la classe, y compris le nom du package utilisé dans l'instruction d'importation.python
class CardLayoutUtil {
private CardLayout cards = new CardLayout();
private JPanel panel = new JPanel();
private CardLayoutUtil(JPanel panel) {
this.panel = panel;
cards = (CardLayout) panel.getLayout();
}
/**
*Créez une instance de cette classe en fonction du panneau qu'elle prend comme argument.
*
* @panneau param Panneau associé à l'instance
* @return Instance de cette classe
* @jette NullPointerException Si l'argument est nul
* @jette IllegalArgumentException lorsque CardLayout n'est pas défini dans le panneau pour l'argument
*/
static CardLayoutUtil of(JPanel panel) {
Objects.requireNonNull(panel);
if (!(panel.getLayout() instanceof CardLayout))
throw new IllegalArgumentException("CardLayout n'est pas défini dans le panneau qui prend l'argument.");
return new CardLayoutUtil(panel);
}
/**
*Enregistrez le composant dans le panneau associé à l'instance.
*
* @param comp Composant à enregistrer
* @clé param La clé associée au composant
* @jette NullPointerException Si un argument est nul
*/
void addCard(Component comp, CardKey key) {
Objects.requireNonNull(comp);
Objects.requireNonNull(key);
panel.add(comp, key.toString());
}
/**
*Affichez le composant associé à la clé prise comme argument.
*
* @clé param La clé associée au composant
* @jette NullPointerException Si l'argument est nul
*/
void showCard(CardKey key) {
Objects.requireNonNull(key);
cards.show(panel, key.toString());
}
}
python
//Création d'un objet CardLayoutUtil
CardLayoutUtil util = CardLayoutUtil.of(center);
Card[] cardKeys = Card.class.getEnumConstants();
python
center.add(labels[i], "Card" + (i + 1));
buttons[i].addActionListener(e -> cards.show(center, "Cerd" + (l_i + 1))); // "Card"ne pas!
python
util.addCard(labels[i], cardKeys[i]);
buttons[i].addActionListener(e -> util.showCard(cardKeys[l_i]));
point important
toString ()
. Par conséquent, ** si la même clé est associée à un autre composant et réutilisée **, ou ** un énumérateur du même nom est défini entre différents énumérateurs **, cela ne fonctionnera pas bien [^] toString].Un exemple de définition d'un énumérateur avec le même nom entre des énumérateurs
enum CardsA implements CardKey {
CARD1, CARD2, CARD3, CARD4;
}
enum CardsB implements CardKey {
CARD1, CARD2, CARD3, CARD4;
}
Exemple de code qui ne fonctionne pas correctement summary>
python
//Centre du cadre
JLabel[] labelsA = {
new JLabel("Card 1"),
new JLabel("Card 2"),
new JLabel("Card 3"),
new JLabel("Card 4")
};
JLabel[] labelsB = {
new JLabel("Card 5"),
new JLabel("Card 6"),
new JLabel("Card 7"),
new JLabel("Card 8")
};
... //réduction
//Création d'un objet CardLayoutUtil
CardLayoutUtil util = CardLayoutUtil.of(center);
CardsA[] cardKeysA = CardsA.class.getEnumConstants();
CardsB[] cardKeysB = CardsB.class.getEnumConstants();
for (int i = 0; i < labelsA.length; i++) {
... //réduction
util.addCard(labelsA[i], cardKeysA[i]);
}
for (int i = 0; i < labelsB.length; i++) {
... //réduction
util.addCard(labelsB[i], cardKeysB[i]);
}
//Bas du cadre
JButton[] buttonsA = {
new JButton("Card 1"),
new JButton("Card 2"),
new JButton("Card 3"),
new JButton("Card 4")
};
JButton[] buttonsB = {
new JButton("Card 5"),
new JButton("Card 6"),
new JButton("Card 7"),
new JButton("Card 8")
};
JPanel south = new JPanel();
for (int i = 0; i < buttonsA.length; i++) {
... //réduction
south.add(buttonsA[i]);
}
for (int i = 0; i < buttonsB.length; i++) {
... //réduction
south.add(buttonsB[i]);
}
python
cards.show(panel, key.toString());
panel.add(comp, key.toString());
python
cards.show(panel, key.getClass().getName() + "." + key.toString());
panel.add(comp, key.getClass().getName() + "." + key.toString());
toString ()
pour que toutes les mêmes représentations sous forme de chaîne soient renvoyées, cela ne sert à rien car la clé ne peut pas être déterminée.