Bonjour,
J'ai une question surement très simple pour vous, comment peut-on représenter un intervalle au moyen d'un tableau?
Voila, c'est tout!
Merci d'avance
Bonjour,
J'ai une question surement très simple pour vous, comment peut-on représenter un intervalle au moyen d'un tableau?
Voila, c'est tout!
Merci d'avance
Hello,
Eh bien, un intervalle est défini avec deux données : sa borne inférieure et sa borne supérieure.
Du coup, avec un tableau, il suffit d'un tableau à deux entrées qui contient ces deux nombres.
Mais il serait plus propre de créer une classe Intervalle que d'utiliser un tableau.
D'accord, merci!
Mais quelle serait la syntaxe employée?
int tableauEntier[] = {0,1} par exemple, pour l'intervalle [0,1]?
Salut,
thelvin te propose de créer une classe.
Perso, j'ai tenté un classe Intervalle à ma manière, je ne sais pas si cela conviendra à tes besoins et surement que Thelvin va faire mieux .
Merci aux pros de corriger si j'écris des bêtises
j'ai créé une classe ayant trois constructeurs qui sont protégés d'une borneMin plus grande qu'une borneMax.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 import java.util.HashSet; import java.util.Set; public class Intervalle { //DECLARATIONS private int borneMin; private int borneMax; private Integer[] tableau; //CONSTRUCTEURS public Intervalle(int borneMin, int borneMax) { if(borneMin < borneMax){ setBorneMin(borneMin); setBorneMax(borneMax); } } public Intervalle(int longueurTableau, int borneMin, int borneMax) { if(borneMin < borneMax){ setBorneMin(borneMin); setBorneMax(borneMax); setTableau(new Integer[longueurTableau]); } } public Intervalle(Integer[] tableau, int borneMin, int borneMax) { if(borneMin < borneMax){ setBorneMin(borneMin); setBorneMax(borneMax); setTableau(tableau); } } //METHODES public Integer[] getIntervalle(int borneMin, int borneMax){ if(tableau != null){ Set<Integer> tableSet = new HashSet<Integer>(); Integer[] tableauRestreint; for(int rank = borneMin; rank < borneMax; rank++){ tableSet.add(getTableau()[rank]); } tableauRestreint = (Integer[]) tableSet.toArray(); return tableauRestreint; } else { return null; } } //ACCESSEURS public int getBorneMin() {return borneMin;} public void setBorneMin(int borneMin) {this.borneMin = borneMin;} public int getBorneMax() {return borneMax;} public void setBorneMax(int borneMax) {this.borneMax = borneMax;} public Integer[] getTableau() {return tableau;} public void setTableau(Integer[] tableau) {this.tableau = tableau;} }
- Un premier constructeur ne prenant en paramètres que les bornes. Ce constructeur ne créé pas de tableau et tu devras donc faire un setTableau() avant d'appeler la méthode getIntervalle().
- un constructeur prenant en paramètres une longueur de tableau et les bornes. Ce constructeur créera le tableau tout seul.
- Un troisième constructeur prenant en paramètres un tableau que tu aurais déjà créé.
Ensuite, j'ai ajouté une méthode qui te renvoie un tableau en fonction de bornes que tu auras entrées en paramètres à cette
te fonction. Pour cette méthode getIntervalle(), j'ai essayé de la protéger d'un appel de tableau dans le cas où le tableau n'aurait pas encore été instancié mais je ne sais pas quoi retourner à part un return null dans le cas où on passe par le else (ce qui finalement reviens à ne pas sécuriser mais c'est à toi de savoir ce que tu veux renvoyer dans ce cas là) mais tu peux aussi choisir de renvoyer un tableau vide en le créant à la volée.
Par contre, le tableau est un tableau d'objets (Integer) et non pas un tableau du type primitif (int).
J'ai aussi créé des accesseurs qui te permettrons de manier les attributs de la classe.
Je pense que si cette classe te plaît et que tu souhaites l'utiliser, tu peux transformer tes anciens tableaux d'int en tableaux d'Integers !
plus de précisions entre int et Integer ici ou là
Salut,
@Francky74, quelques remarques :
- Une classe qui représente un intervalle doit représenter un intervalle, ni plus, ni moins. Un intervalle, c'est un minimum et un maximum. Il n'y a aucune notion de tableau. Eventuellement, on pourrait avoir des notions d'inclusion ou exclusion de bornes.
On peut bien sûr fournir une méthode utilitaire qui produit l'ensemble des valeurs comprises entre les 2 bornes, mais pas besoin de tableau en entrée (et encore moins de le stocker en attribut — si on a besoin d'une telle méthode, passer le tableau en paramètre de la méthode).
Mais il me semble plus utile par ailleurs d'avoir des méthodes qui permettent de tester si des valeurs sont dans l'intervalle ou pas, ou si un intervalle est inclus dans un autre, ou s'il y a intersection, etc.- tant qu'à faire, autant avoir les bornes déclarées final, coder hashCode() et equals() (et accessoirement toString()), ce qui permettrait d'utiliser la classe comme clef dans une Map, d'autant que l'intérêt de modifier les bornes est très limité (et on peut toujours créer une nouvelle instance au besoin)
- Attention : un Set ne garantit pas l'ordre des éléments qui s'y trouvent. Construire le tableau comme tu le fais en passant par un Set intermédiaire va avoir comme conséquence que le tableau obtenu sera "mélangé" par rapport au tableau source : c'est plutôt génant.
- tableauRestreint = (Integer[]) tableSet.toArray(); va planter (ClassCastException) : un Object[] n'est pas castable en Integer[] !
- Déclare toujours tes variables au plus près de leur usage :
Pourquoi déclarer tableauRestreint avant le for ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 Integer[] tableauRestreint; for(int rank = borneMin; rank < borneMax; rank++){ tableSet.add(getTableau()[rank]); } tableauRestreint = (Integer[]) tableSet.toArray();- Attention à ce genre de constructeur :
Si les bornes ne respectent pas la condition, on créé une instance "inconsistante", silencieusement, qui ne correspond pas aux paramètrex. C'est plutôt déroutant pour celui qui va utiliser la classe, pour peu qu'il n'est pas accès au source (rare sont ceux qui le regarde d'ailleurs). Il vaudrait mieux soulever une exception que de rien faire (une IllegalArgumentException par exemple).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 public Intervalle(int borneMin, int borneMax) { if(borneMin < borneMax){ setBorneMin(borneMin); setBorneMax(borneMax); } }- A noter, par ailleurs, que pour extraire un intervalle
- d'un tableau, on peut utiliser Arrays.copyOfRange(tab, from, to), ce qui permet en plus de pouvoir le faire sur un int[] (sans faire de manipulation diverses) ;
- d'une List, on peut utiliser List.sublist(from, to).
Bonjour Joel et merci pour ces précieux conseils
En suivant vos conseils, voici ce que j'ai créé :
Une classe Intervalle suivie d'une classe InterMain qui m'a permi de tester la classe Intervalle :
classe de test InterMain :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77 import java.util.Arrays; public class Intervalle { //**************************DECLARATIONS private int borneMin; private int borneMax; private boolean isMinIncluded, isMaxIncluded; //**************************CONSTRUCTEURS //constructeur dont les bornes sont toutes incluses par défaut public Intervalle(int borneMin, int borneMax){ this(borneMin, true, borneMax, true); } //constructeur permettant d'inclure ou exclure les deux bornes en même temps public Intervalle(int borneMin, int borneMax, boolean isAllIncluded) { this(borneMin, isAllIncluded, borneMax, isAllIncluded); } //constructeur permettant d'inclure ou exclure chaque borne séparément public Intervalle(int borneMin, boolean isMinIncluded, int borneMax, boolean isMaxIncluded){ if(borneMin > borneMax){ throw new IllegalArgumentException(" borneMin > borneMax "); } setBorneMin(borneMin); setBorneMax(borneMax); setMinIncluded(isMinIncluded); setMaxIncluded(isMaxIncluded); } //**************************METHODES public int[] rangeTabInt(int[] tableau){ int[] tab; int min = 0, max = 0; //on définit la longueur du tableau selon si les bornes sont inclues ou exclues //on en profite pour initialiser le bornes if(isMinIncluded == true && isMaxIncluded == true){ tab = new int[(borneMax - borneMin)]; min = borneMin; max = borneMax; } else if (isMinIncluded == false && isMaxIncluded == false){ tab = new int[(borneMax - borneMin - 2)]; min = ++borneMin; max = --borneMax; } else if (isMinIncluded == false && isMaxIncluded == true){ tab = new int[(borneMax - borneMin - 1)]; min = ++borneMin; max = borneMax; } else if (isMinIncluded == true && isMaxIncluded == false){ tab = new int[(borneMax - borneMin - 1)]; min = borneMin; max = --borneMax; } else { throw new IllegalArgumentException(" problème d'inclusion exclusion des bornes "); } tab = Arrays.copyOfRange(tableau, min, max); return tab; } //**************************ACCESSEURS public int getBorneMin() {return borneMin;} public void setBorneMin(int borneMin) {this.borneMin = borneMin;} public int getBorneMax() {return borneMax;} public void setBorneMax(int borneMax) {this.borneMax = borneMax;} public boolean isMinIncluded() {return isMinIncluded;} public void setMinIncluded(boolean isMinIncluded) {this.isMinIncluded = isMinIncluded;} public boolean isMaxIncluded() {return isMaxIncluded;} public void setMaxIncluded(boolean isMaxIncluded) {this.isMaxIncluded = isMaxIncluded;} }
Voilà, j'ai essayé de suivre vos conseils au mieux !
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public class InterMain { public static void main(String[] args) { //définitions des intervalles int interMin = 3, interMax = 7; Intervalle intervalleTT = new Intervalle(interMin, interMax); Intervalle intervalleFF = new Intervalle(interMin, interMax, false); Intervalle intervalleTF = new Intervalle(interMin, false, interMax, true); Intervalle intervalleFT = new Intervalle(interMin, true, interMax, false); System.out.println("borne max : " + intervalleTT.getBorneMax() + " / borne min : " + intervalleTT.getBorneMin() + "\n"); //création d'un tableau de test int[] tab = {1,2,3,4,5,6,7,8}; System.out.println("*********************************\n"); int[] tabRangedtt = intervalleTT.rangeTabInt(tab); System.out.println("\ttoutes bornes incluses : "); for(int rank = 0; rank < tabRangedtt.length; rank++){ System.out.println(tabRangedtt[rank]); } System.out.println("*********************************\n"); int[] tabRangedff = intervalleFF.rangeTabInt(tab); System.out.println("\ttoutes bornes exluses : "); for(int rank = 0; rank < tabRangedff.length; rank++){ System.out.println(tabRangedff[rank]); } System.out.println("*********************************\n"); int[] tabRangedtf = intervalleFT.rangeTabInt(tab); System.out.println("\t borne min inclue, borne max exclue : "); for(int rank = 0; rank < tabRangedtf.length; rank++){ System.out.println(tabRangedtf[rank]); } System.out.println("*********************************\n"); int[] tabRangedft = intervalleTF.rangeTabInt(tab); System.out.println("\t borne min exclue, borne max inclue : "); for(int rank = 0; rank < tabRangedft.length; rank++){ System.out.println(tabRangedft[rank]); } System.out.println("*********************************\n"); } }
Voici le résultat d la console :
Par contre, je n'ai pas compris ceci :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 borne max : 7 / borne min : 3 ********************************* toutes bornes incluses : 4 5 6 7 ********************************* toutes bornes exluses : 5 6 ********************************* borne min inclue, borne max exclue : 4 5 6 ********************************* borne min exclue, borne max inclue : 5 6 7 *********************************
tant qu'à faire, autant avoir les bornes déclarées final, coder hashCode() et equals() (et accessoirement toString()), ce qui permettrait d'utiliser la classe comme clef dans une Map, d'autant que l'intérêt de modifier les bornes est très limité (et on peut toujours créer une nouvelle instance au besoin)
Merci
Bah, tiens, justement, modifie ton code comme çà :
Et tu vas voir ce qu'il se passe.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 public class Intervalle { private final int borneMin; private final int borneMax; private final boolean isMinIncluded; private final boolean isMaxIncluded; /* ... le reste demeure inchangé ... */
Je te donnerai des explications plus complètes plus tard.
Des erreurs de partout !!!!
Il m'est demandé d'initialiser mes final et ensuite, il m'est demandé d'enlever le mot clé final dans les setters et dans les endroits ou j'incrémente puisqu'il ne faut pas modifier les final.
En fait je ne peux tout simplement pas instancier mes variables dans le constructeur !
Si quelqu'un m'avais demandé de passer ces variables en final, ma réponse aurait été qu'il ne faut surtout pas ! Mais comme comme vous êtes bien plus expérimenté que moi, je tape en touche et je vous demande des explications car je ne comprends pas l'utilité
Merci
ça c'est juste parce que tu as mis des setters : l'idée quand on met ses attributs final, c'est justement de ne pas mettre de setters, parce qu'on ne veut pas qu'on puisse modifier les valeurs.
tu peux très bien écrire :
En plus dans ton cas, si on appelle les setters après la construction, on peut faire n'importe quoi (faire des intervalles avec un min>max).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 public class Intervalle { private final int max; private final int min; public Intervalle(int min, int max) { if ( min>max ) throw new IllegalArgumentException("min must be lesser and equals than max: "+mix+">"+max); this.min=min; this.max=max; } /*...*/ }
Il peut y avoir des raisons fonctionnelles de modifier un intervalle après sa création, mais je pense que le cas général fonctionnel, c'est plutôt l'inverse : si je définis un intervalle, en théorie, ses bornes ne doivent pas changer n'importe quand. Si elles devaient quand même changer, il serait préférable, à mon avis, de récréer un nouvel intervalle avec les nouvelles bornes. L'avantage, déjà, c'est que tu es sûr que ton intervalle reste cohérent (si l'instance existe, l'intervalle est valide et reste toujours le même), donc le code qui l'utilise l'est (du moins vis-à-vis de l'intervalle), y compris en multi-thread (une même instance d'intervalle peut être utilisée par plusieurs threads sans risque).
Ensuite, le fait que la classe soit immutable la rend candidate pour servir de clef pour une map (aussi faut-il implémenter hashCode() et equals()) : c'est très intéressant de pouvoir faire une map, ou l'on associe à des intervalles, quelque chose (par exemple, une fonction).
Et oui : justement, là, ça te permet de voir que tu as fait une grossière erreur : tu modifies tes bornes à chaque fois que tu extrais une partie d'un tableau, donc tu dégrades ton intervalle.
Personnellement, si on utilise une API qui propose une classe de gestion d'intervalle et que quand on créé un intervalle [0, 100[ par exemple, et qu'il suffit que on appelle rangeTabInt() une première fois et que ça renvoie les valeurs de 0 à 99, puis lors d'un second appel sur le même tableau et ça renvoie les valeurs de 0 à 98, avoue qu'il y a de quoi être décontenancé. Le but d'une telle méthode est de se comporter de manière cohérente : si je créé un intervalle [0, 100[, il n'y aucune raison qu'il devienne [0,99[ parce que j'ai extrait des données d'un tableau.
Il y a un autre avantage à rendre des variables final : c'est une indication que le compilateur utilise pour faire certaine optimisation. Ce type d'optimisation est d'autant plus intéressant que la classe est une classe de base, fonctionnellement parlant : je veux dire dont on peut gérer des dizaines, voire des centaines d'instances. C'est le cas d'ailleurs pour Integer, Double ou String.
NB. pour l'implémentation de hashCode et equals() il suffit de
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 public int hashCode() { return Objects.hash(min, max); } public boolean equals(Object obj) { if ( obj!=null && Intervalle.class.equals(obj.getClass()) ) { return equals((Intervalle)obj); } else { return false; } } protected final boolean equals(Intervalle intervalle) { return intervalle.min == min && intervalle.max == max; }
C'est vrai que ce n'est pas très sécurisé ....En plus dans ton cas, si on appelle les setters après la construction, on peut faire n'importe quoi
Intéressant à connaitre pour coder dans ce sens !c'est une indication que le compilateur utilise pour faire certaine optimisation
Bonsoir,
Donc, suivant les conseils de Joel, je poste la classe Intervalle remaniée avec des finals et méthodes hashCode puis equals qui sont effectivement intéressantes.
Je n'ai pas compris la méthode hashCode, elle renvoie toujours 1061 dans mon exemple, et ce quelque soit l'intervalle ...
Toutefois, Joel, j'ai l'impression que dans votre dernier code, il y a un dead code. Je m'explique et vous me contredirez si j'ai tort :
En fait, nous ne rentrons jamais dans le premier "if" if ( obj!=null && Intervalle.class.equals(obj.getClass()) de la première méthode equals puisque si les deux objets sont de classe Intervalle ont rentre dans l'autre méthode equals.NB. pour l'implémentation de hashCode et equals() il suffit de
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 public boolean equals(Object obj) { if ( obj!=null && Intervalle.class.equals(obj.getClass()) ) { return equals((Intervalle)obj); } else { return false; } } protected final boolean equals(Intervalle intervalle) { return intervalle.min == min && intervalle.max == max; }
Bon, ceci mis à part, voilà la classe Intervalle que j'ai écrite (remarquez que la méthode equals prend en compte l'inclusion ou l'exclusion des bornes
puis une classe contenant le main qui permet de tester les méthodes de la classe Intervalle :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 import java.util.Arrays; import java.util.Objects; public class Intervalle { //**************************DECLARATIONS private final int BORNE_MIN; private final int BORNE_MAX; private final boolean IS_MIN_INCLUDED, IS_MAX_INCLUDED; //**************************CONSTRUCTEURS //constructeur dont les bornes sont toutes incluses par défaut public Intervalle(int borneMin, int borneMax){ this(borneMin, true, borneMax, true); } //constructeur permettant d'inclure ou exclure les deux bornes en même temps public Intervalle(int borneMin, int borneMax, boolean isAllIncluded) { this(borneMin, isAllIncluded, borneMax, isAllIncluded); } //constructeur permettant d'inclure ou exclure chaque borne séparément public Intervalle(int borneMin, boolean isMinIncluded, int borneMax, boolean isMaxIncluded){ if(borneMin > borneMax){throw new IllegalArgumentException(" borneMin > borneMax ");} this.BORNE_MIN = borneMin; this.BORNE_MAX = borneMax; this.IS_MIN_INCLUDED = isMinIncluded; this.IS_MAX_INCLUDED = isMaxIncluded; } //**************************METHODES public int hashCode() { return Objects.hash(BORNE_MIN, BORNE_MAX); } public boolean equals(Object obj) { if ( obj!=null && Intervalle.class.equals(obj.getClass()) ) { return equals((Intervalle)obj); } else { return false; } } protected final boolean equals(Intervalle intervalle) { return intervalle.BORNE_MIN == this.BORNE_MIN && intervalle.BORNE_MAX == this.BORNE_MAX && intervalle.IS_MIN_INCLUDED == this.IS_MIN_INCLUDED && intervalle.IS_MAX_INCLUDED == this.IS_MAX_INCLUDED; } public int[] rangeTabInt(int[] tableau){ int[] tab; //on définit la longueur du tableau selon si les bornes sont inclues ou exclues if(IS_MIN_INCLUDED == true && IS_MAX_INCLUDED == true){ tab = new int[(BORNE_MAX - BORNE_MIN)]; tab = Arrays.copyOfRange(tableau, BORNE_MIN, BORNE_MAX); } else if (IS_MIN_INCLUDED == false && IS_MAX_INCLUDED == false){ tab = new int[(BORNE_MAX - BORNE_MIN - 2)]; tab = Arrays.copyOfRange(tableau, BORNE_MIN + 1, BORNE_MAX - 1); } else if (IS_MIN_INCLUDED == false && IS_MAX_INCLUDED == true){ tab = new int[(BORNE_MAX - BORNE_MIN - 1)]; tab = Arrays.copyOfRange(tableau, BORNE_MIN + 1, BORNE_MAX); } else if (IS_MIN_INCLUDED == true && IS_MAX_INCLUDED == false){ tab = new int[(BORNE_MAX - BORNE_MIN - 1)]; tab = Arrays.copyOfRange(tableau, BORNE_MIN, BORNE_MAX - 1); } else { throw new IllegalArgumentException(" problème d'inclusion exclusion des bornes "); } return tab; } //**************************GETTERS public int getBorneMin() {return BORNE_MIN;} public int getBorneMax() {return BORNE_MAX;} public boolean isMinIncluded() {return IS_MIN_INCLUDED;} public boolean isMaxIncluded() {return IS_MAX_INCLUDED;} }
et le résultat issu de la console :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class InterMain { public static void main(String[] args) { //définitions des intervalles int interMin = 3, interMax = 7; Intervalle intervalleTT = new Intervalle(interMin, interMax); Intervalle intervalleFF = new Intervalle(interMin, interMax, false); Intervalle intervalleTF = new Intervalle(interMin, false, interMax, true); Intervalle intervalleFT = new Intervalle(interMin, true, interMax, false); System.out.println("borne max : " + intervalleTT.getBorneMax() + " / borne min : " + intervalleTT.getBorneMin() + "\n"); //création d'un tableau de test int[] tab = {1,2,3,4,5,6,7,8}; System.out.println("*********************************\n"); int[] tabRangedtt = intervalleTT.rangeTabInt(tab); System.out.println("\ttoutes bornes incluses : "); for(int rank = 0; rank < tabRangedtt.length; rank++){ System.out.println(tabRangedtt[rank]); } System.out.println("*********************************\n"); int[] tabRangedff = intervalleFF.rangeTabInt(tab); System.out.println("\ttoutes bornes exluses : "); for(int rank = 0; rank < tabRangedff.length; rank++){ System.out.println(tabRangedff[rank]); } System.out.println("*********************************\n"); int[] tabRangedtf = intervalleFT.rangeTabInt(tab); System.out.println("\t borne min inclue, borne max exclue : "); for(int rank = 0; rank < tabRangedtf.length; rank++){ System.out.println(tabRangedtf[rank]); } System.out.println("*********************************\n"); int[] tabRangedft = intervalleTF.rangeTabInt(tab); System.out.println("\t borne min exclue, borne max inclue : "); for(int rank = 0; rank < tabRangedft.length; rank++){ System.out.println(tabRangedft[rank]); } System.out.println("*********************************\n"); System.out.println("hashCode TT : " + intervalleTT.hashCode()); System.out.println("hashCode FF : " + intervalleFF.hashCode()); System.out.println("hashCode TF : " + intervalleTF.hashCode()); System.out.println("hashCode FT : " + intervalleFT.hashCode() + "\n"); System.out.println("FT equals TF : " + intervalleTF.equals(intervalleFT)); System.out.println("TT equals TT : " + intervalleTT.equals(intervalleTT)); System.out.println("TT equals String : " + intervalleTT.equals("blabla") + "\n"); System.out.println("FT equals TF : " + intervalleTF.equals(intervalleFT)); System.out.println("TT equals TT : " + intervalleTT.equals(intervalleTT)); } }
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 borne max : 7 / borne min : 3 ********************************* toutes bornes incluses : 4 5 6 7 ********************************* toutes bornes exluses : 5 6 ********************************* borne min inclue, borne max exclue : 4 5 6 ********************************* borne min exclue, borne max inclue : 5 6 7 ********************************* hashCode TT : 1061 hashCode FF : 1061 hashCode TF : 1061 hashCode FT : 1061 FT equals TF : false TT equals TT : true TT equals String : false FT equals TF : false TT equals TT : true
Attention : il est important de connaitre les mécanismes de sélection de méthodes.
1) Déjà, essaye :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package p1; public class Demo { private final int value; public Demo(int value) { this.value=value; } @Override public int hashCode() { return value; } @Override public boolean equals(Object obj) { System.out.println("equals(Object)"); if ( obj!=null && Demo.class.equals(obj.getClass()) ) { return equals((Demo)obj); } return super.equals(obj); } protected boolean equals(Demo demo) { System.out.println("equals(Demo)"); return value==demo.value; } }
Que voit-on dans la console ? Pourquoi, à ton avis ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package p2; import p1.Demo; public class Test { public static void main(String[] args) { Demo demo1 = new Demo(42); Demo demo2 = new Demo(42); System.out.println(demo1.equals(demo2)); } }
2) Et maintenant, remplace Demo par
Et exécute là. Qu'est-ce qui s'affiche ? Pourquoi à ton avis ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 package p1; import java.util.ArrayList; import java.util.List; public class Demo { private final int value; public Demo(int value) { this.value=value; } @Override public int hashCode() { return value; } @Override public boolean equals(Object obj) { System.out.println("equals(Object)"); if ( obj!=null && Demo.class.equals(obj.getClass()) ) { return equals((Demo)obj); } return super.equals(obj); } protected boolean equals(Demo demo) { System.out.println("equals(Demo)"); return value==demo.value; } public static void main(String[] args) { List<Demo> demos = new ArrayList<>(); demos.add(new Demo(42)); System.out.println(demos.contains(new Demo(42))); } }
Bonsoir,
Merci pour cette énigme instructrice
En fait, je n'avais même pas remarqué () que la méthode equals(Object obj) appelait la méthode equals(Demo demo) si obj est différent de null et si les noms des classes sont identiques !!!
Ce qui me parait étrange et que je n'arrive pas à m'expliquer, c'est que lorsque je commente la méthode suivante :
je vois que l'on ne passe jamais dans la méthode equals(Demo demo) alors que pourtant on lui donne un attribut de type Demo !?!
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 @Override public boolean equals(Object obj) { System.out.println("equals(Object)"); if ( obj!=null && Demo.class.equals(obj.getClass()) ) { return equals((Demo)obj); } return super.equals(obj); }
System.out.println(demo1.equals(demo2));
Si on m'avais posé la question avant de debugger j'aurais dit que 'bien sûr' elle passera forcément dedans ... mais non !!!
Et oui, mais la méthode equals(Demo) est protected, elle ne peut donc être appelée que par les classes filles ou les classes du même package.
Ça ne sert à rien de commenter equals(Object). equals(Demo) est déjà la plus spécifique des deux, donc si elle pouvait être appelée, c'est elle qui le serait.
c'est quand même dingue ça ! je sais ce que signifie protected mais je ne me suis même pas inquiété de cela !
Vraiment merci !!!
Et maintenant, tu peux faire un dernier essai : dans la dernière version de Demo, tu rends plublic la méthode equals(Demo).
Qu'affiche le programme ? Pourquoi à ton avis ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 public class Demo { private final int value; public Demo(int value) { this.value=value; } @Override public int hashCode() { return value; } @Override public boolean equals(Object obj) { System.out.println("equals(Object)"); if ( obj!=null && Demo.class.equals(obj.getClass()) ) { return equals((Demo)obj); } return super.equals(obj); } public boolean equals(Demo demo) { System.out.println("equals(Demo)"); return value==demo.value; } public static void main(String[] args) { List<Demo> demos = new ArrayList<>(); demos.add(new Demo(42)); System.out.println(demos.contains(new Demo(42))); } }
Bonjour,
j'ai passé en public la méthode equals(Demo).
Il s'avère que lorsque je fait tourner depuis le main contenu dans Test, on ne passe plus dans la méthode equals(Object) mais directement dans equals(Demo).
Logique ! car maintenant, cette dernière méthode est vue depuis la classe Test et possède une signature appropriée à l'appel fait depuis la classe Test -> p1.Demo.equals(Demo demo)
.
Lorsque je fait tourner depuis le main contenu dans la classe Demo, là par contre, on passe dans la méthode equal(Object). Ceci parait illogique à priori (pour moi bien sur ....) mais je me l'explique par la fait que l'appel suivant demos.contains(new Demo(42)) est un appel de la méthode java.util.List.contains(Object o) qui fournit donc en paramètre un objet. Et donc le new Demo(42) est considéré comme appartenant à la classe Object et non à la classe Demo.
Am I right ?
C'est ça, oui;
C'est le type (par lequel on manipule l'instance) plus que la classe réelle de l'instance qui est utilisé pour la sélection de méthode : en effet, dans l'ArrayList, l'instance de Demo n'est connue qu'en tant qu'Object, donc, la méthode equals(Object) est sélectionnée lors de l'invocation de equals(), malgré le fait qu'on ait une méthode accessible plus adaptée à la classe de l'instance.
Merci Joel ! Ce sont des choses qui ne se voient pas du premier coup d'oeuil et c'était très intéressant pour moi et le sera aussi surement pour d'autres !
Donc voici au final, la classe Intervalle :
@uqerfromfrance : est-ce que cela répond à ton problème ? tu ne nous a pas trop guidés pour résoudre ton problème, il serait intéressant de savoir si la résolution est bien adaptée à tes besoins.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 import java.util.Arrays; import java.util.Objects; public class Intervalle { //**************************DECLARATIONS private final int BORNE_MIN; private final int BORNE_MAX; private final boolean IS_MIN_INCLUDED, IS_MAX_INCLUDED; //**************************CONSTRUCTEURS //constructeur dont les bornes sont toutes incluses par défaut public Intervalle(int borneMin, int borneMax){ this(borneMin, true, borneMax, true); } //constructeur permettant d'inclure ou exclure les deux bornes en même temps public Intervalle(int borneMin, int borneMax, boolean isAllIncluded) { this(borneMin, isAllIncluded, borneMax, isAllIncluded); } //constructeur permettant d'inclure ou exclure chaque borne séparément public Intervalle(int borneMin, boolean isMinIncluded, int borneMax, boolean isMaxIncluded){ if(borneMin > borneMax){throw new IllegalArgumentException(" borneMin > borneMax ");} this.BORNE_MIN = borneMin; this.BORNE_MAX = borneMax; this.IS_MIN_INCLUDED = isMinIncluded; this.IS_MAX_INCLUDED = isMaxIncluded; } //**************************METHODES public int hashCode() { return Objects.hash(BORNE_MIN, BORNE_MAX); } public boolean equals(Object obj) { if ( obj!=null && Intervalle.class.equals(obj.getClass()) ) { return equals((Intervalle)obj); } else { return false; } } protected final boolean equals(Intervalle intervalle) { return intervalle.BORNE_MIN == this.BORNE_MIN && intervalle.BORNE_MAX == this.BORNE_MAX && intervalle.IS_MIN_INCLUDED == this.IS_MIN_INCLUDED && intervalle.IS_MAX_INCLUDED == this.IS_MAX_INCLUDED; } public int[] rangeTabInt(int[] tableau){ int[] tab; //on définit la longueur du tableau selon si les bornes sont inclues ou exclues if(IS_MIN_INCLUDED == true && IS_MAX_INCLUDED == true){ tab = new int[(BORNE_MAX - BORNE_MIN)]; tab = Arrays.copyOfRange(tableau, BORNE_MIN, BORNE_MAX); } else if (IS_MIN_INCLUDED == false && IS_MAX_INCLUDED == false){ tab = new int[(BORNE_MAX - BORNE_MIN - 2)]; tab = Arrays.copyOfRange(tableau, BORNE_MIN + 1, BORNE_MAX - 1); } else if (IS_MIN_INCLUDED == false && IS_MAX_INCLUDED == true){ tab = new int[(BORNE_MAX - BORNE_MIN - 1)]; tab = Arrays.copyOfRange(tableau, BORNE_MIN + 1, BORNE_MAX); } else if (IS_MIN_INCLUDED == true && IS_MAX_INCLUDED == false){ tab = new int[(BORNE_MAX - BORNE_MIN - 1)]; tab = Arrays.copyOfRange(tableau, BORNE_MIN, BORNE_MAX - 1); } else { throw new IllegalArgumentException(" problème d'inclusion exclusion des bornes "); } return tab; } //**************************GETTERS public int getBorneMin() {return BORNE_MIN;} public int getBorneMax() {return BORNE_MAX;} public boolean isMinIncluded() {return IS_MIN_INCLUDED;} public boolean isMaxIncluded() {return IS_MAX_INCLUDED;} }
Juste 2 dernières remarques :
- hashcode devrait prendre en compte les booléens également. Ce n'est pas que ça ne fonctionne pas, mais l'intérêt est de rendre plus efficace les traitements qui utilisent le hash (en ayant un hash suffisamment discréminant).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 public int hashCode() { return Objects.hash(BORNE_MIN, BORNE_MAX, IS_MIN_INCLUDED, IS_MAX_INCLUDED); }- Il y a des conventions en java : les noms de variables en lowerCamelCase (là, tu as utilisé la convention pour les "constantes", soit les static final)
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager