Bonjour à tous,
Je précise que je suis débutant en Java.
Pouvez vous m'expliquer pourquoi ce code se compile correctement. En
fait, je ne comprends pas pourquoi l'erreur manifeste de ce code
(provenant de l'opération de cast illégale il me semble) n'est pas
détectée dès la compilation, mais seulement au moment de l'exécution ?
Merci d'avance.
Bonjour à tous,
Je précise que je suis débutant en Java.
Pouvez vous m'expliquer pourquoi ce code se compile correctement. En
fait, je ne comprends pas pourquoi l'erreur manifeste de ce code
(provenant de l'opération de cast illégale il me semble) n'est pas
détectée dès la compilation, mais seulement au moment de l'exécution ?
Merci d'avance.
Bonjour à tous,
Je précise que je suis débutant en Java.
Pouvez vous m'expliquer pourquoi ce code se compile correctement. En
fait, je ne comprends pas pourquoi l'erreur manifeste de ce code
(provenant de l'opération de cast illégale il me semble) n'est pas
détectée dès la compilation, mais seulement au moment de l'exécution ?
Merci d'avance.
Disons que le compilateur Java n'est pas assez "malin" pour détecter les
erreurs de cast évidentes. Ça ne me semble pas bien grave, car dans la
plupart des cas les erreurs de cast ne sont pas évidentes, ni même
détectables avant l'exécution.
Disons que le compilateur Java n'est pas assez "malin" pour détecter les
erreurs de cast évidentes. Ça ne me semble pas bien grave, car dans la
plupart des cas les erreurs de cast ne sont pas évidentes, ni même
détectables avant l'exécution.
Disons que le compilateur Java n'est pas assez "malin" pour détecter les
erreurs de cast évidentes. Ça ne me semble pas bien grave, car dans la
plupart des cas les erreurs de cast ne sont pas évidentes, ni même
détectables avant l'exécution.
Disons que le compilateur Java n'est pas assez "malin" pour détecter
les erreurs de cast évidentes. Ça ne me semble pas bien grave, car
dans la plupart des cas les erreurs de cast ne sont pas évidentes,
ni même détectables avant l'exécution.
Il semble bien que, pour les cast, Java ne regarde absolument pas
les types des objets mais seulement ceux des variables.
Disons que le compilateur Java n'est pas assez "malin" pour détecter
les erreurs de cast évidentes. Ça ne me semble pas bien grave, car
dans la plupart des cas les erreurs de cast ne sont pas évidentes,
ni même détectables avant l'exécution.
Il semble bien que, pour les cast, Java ne regarde absolument pas
les types des objets mais seulement ceux des variables.
Disons que le compilateur Java n'est pas assez "malin" pour détecter
les erreurs de cast évidentes. Ça ne me semble pas bien grave, car
dans la plupart des cas les erreurs de cast ne sont pas évidentes,
ni même détectables avant l'exécution.
Il semble bien que, pour les cast, Java ne regarde absolument pas
les types des objets mais seulement ceux des variables.
il ne s'agit pas d'ingéniosité mais de déterminisme.
le compilo ne peut pas savoir si le cast est valide ou non.
Il semble bien que, pour les cast, Java ne regarde absolument pas
les types des objets mais seulement ceux des variables.
on va supposer que "variables" signifie "variables de type primitif"
comme un byte, un int, etc... et "objets" signifie "instances de
classe".
si tu parles de cela, le compilo verifie les 2 "familles" et applique
des casts implicites si et seulement si il sont valides (ie conversion
non destructrice de type primitif ou upcast d'une référence).
dans ton code:
class A {}
class B extends A {}
le compilo vérifie et valide:
B b = new B();
A a = b;
comme il vérifie et refuse:
A a = new A();
B b = a;
le cast que tu fasses un cast explicite invalide accepté par le
compilo et générant une CastClassException au runtime (ce n'est
pas "c.faireDuBruit()" qui bombe dans ton code mais bien le cast)
n'est pas un défaut du compilo, ce n'est que un bug (volontaire)
de codage.
le compilo doit en effet évidemment accepter les downcast (cast
d'une classe de base vers une classe dérivée) pour accepter les
cas où une instance dérivée n'est pas fournie par un conteneur
de cette classe mais par celui de la classe de base, ex:
Animal getPet(){
return new Chien();
}
Chien chien = (Chien) getPet();
ceci est valide (même si tordu car inventé pour l'exemple).
plus génériquement on ferait plutôt:
Animal getPet(){
return new Chien();
}
Animal animal = getPet();
if (animal instanceof Chien){
Chien c = (Chien) animal;
c.faitQlqChose();
}
il ne s'agit pas d'ingéniosité mais de déterminisme.
le compilo ne peut pas savoir si le cast est valide ou non.
Il semble bien que, pour les cast, Java ne regarde absolument pas
les types des objets mais seulement ceux des variables.
on va supposer que "variables" signifie "variables de type primitif"
comme un byte, un int, etc... et "objets" signifie "instances de
classe".
si tu parles de cela, le compilo verifie les 2 "familles" et applique
des casts implicites si et seulement si il sont valides (ie conversion
non destructrice de type primitif ou upcast d'une référence).
dans ton code:
class A {}
class B extends A {}
le compilo vérifie et valide:
B b = new B();
A a = b;
comme il vérifie et refuse:
A a = new A();
B b = a;
le cast que tu fasses un cast explicite invalide accepté par le
compilo et générant une CastClassException au runtime (ce n'est
pas "c.faireDuBruit()" qui bombe dans ton code mais bien le cast)
n'est pas un défaut du compilo, ce n'est que un bug (volontaire)
de codage.
le compilo doit en effet évidemment accepter les downcast (cast
d'une classe de base vers une classe dérivée) pour accepter les
cas où une instance dérivée n'est pas fournie par un conteneur
de cette classe mais par celui de la classe de base, ex:
Animal getPet(){
return new Chien();
}
Chien chien = (Chien) getPet();
ceci est valide (même si tordu car inventé pour l'exemple).
plus génériquement on ferait plutôt:
Animal getPet(){
return new Chien();
}
Animal animal = getPet();
if (animal instanceof Chien){
Chien c = (Chien) animal;
c.faitQlqChose();
}
il ne s'agit pas d'ingéniosité mais de déterminisme.
le compilo ne peut pas savoir si le cast est valide ou non.
Il semble bien que, pour les cast, Java ne regarde absolument pas
les types des objets mais seulement ceux des variables.
on va supposer que "variables" signifie "variables de type primitif"
comme un byte, un int, etc... et "objets" signifie "instances de
classe".
si tu parles de cela, le compilo verifie les 2 "familles" et applique
des casts implicites si et seulement si il sont valides (ie conversion
non destructrice de type primitif ou upcast d'une référence).
dans ton code:
class A {}
class B extends A {}
le compilo vérifie et valide:
B b = new B();
A a = b;
comme il vérifie et refuse:
A a = new A();
B b = a;
le cast que tu fasses un cast explicite invalide accepté par le
compilo et générant une CastClassException au runtime (ce n'est
pas "c.faireDuBruit()" qui bombe dans ton code mais bien le cast)
n'est pas un défaut du compilo, ce n'est que un bug (volontaire)
de codage.
le compilo doit en effet évidemment accepter les downcast (cast
d'une classe de base vers une classe dérivée) pour accepter les
cas où une instance dérivée n'est pas fournie par un conteneur
de cette classe mais par celui de la classe de base, ex:
Animal getPet(){
return new Chien();
}
Chien chien = (Chien) getPet();
ceci est valide (même si tordu car inventé pour l'exemple).
plus génériquement on ferait plutôt:
Animal getPet(){
return new Chien();
}
Animal animal = getPet();
if (animal instanceof Chien){
Chien c = (Chien) animal;
c.faitQlqChose();
}
Pour moi, "variables" signifie "variables de type primitif" c'est-à-dire
celles contenant un byte, un int etc... et celles contenant une
référence à une classe donnée d'objet.
Pour moi, "variables" signifie "variables de type primitif" c'est-à-dire
celles contenant un byte, un int etc... et celles contenant une
référence à une classe donnée d'objet.
Pour moi, "variables" signifie "variables de type primitif" c'est-à-dire
celles contenant un byte, un int etc... et celles contenant une
référence à une classe donnée d'objet.
dans:
class A {}
class B extends A {}
le compilo vérifie et valide:
B b = new B();
A a = b;
comme il vérifie et refuse:
A a = new A();
B b = a;
Oui et pour moi, c'est sur les variables a et b que le compilateur fait
les vérifications et pas sur les objets créés sur le tas. Le compilateur
dit : "hors de question de mettre le contenu de la variable a de type A
dans la variable b de type B". Peu importe le type de l'objet référencé
par a, ça pourrait être un objet de type B que le compilateur n'en
voudrait pas non plus.
Ok, mais le compilateur ne peut pas avant vérifier si le cast est
compatible avec le type de l'objet référencé ?
Animal animal = getPet();
if (animal instanceof Chien){
Chien c = (Chien) animal;
c.faitQlqChose();
}
C'est là où je butte un peu (désolé). Je pensais que le test "if (animal
instanceof Chien){...}" pouvait être fait par le compilateur justement ?
dans:
class A {}
class B extends A {}
le compilo vérifie et valide:
B b = new B();
A a = b;
comme il vérifie et refuse:
A a = new A();
B b = a;
Oui et pour moi, c'est sur les variables a et b que le compilateur fait
les vérifications et pas sur les objets créés sur le tas. Le compilateur
dit : "hors de question de mettre le contenu de la variable a de type A
dans la variable b de type B". Peu importe le type de l'objet référencé
par a, ça pourrait être un objet de type B que le compilateur n'en
voudrait pas non plus.
Ok, mais le compilateur ne peut pas avant vérifier si le cast est
compatible avec le type de l'objet référencé ?
Animal animal = getPet();
if (animal instanceof Chien){
Chien c = (Chien) animal;
c.faitQlqChose();
}
C'est là où je butte un peu (désolé). Je pensais que le test "if (animal
instanceof Chien){...}" pouvait être fait par le compilateur justement ?
dans:
class A {}
class B extends A {}
le compilo vérifie et valide:
B b = new B();
A a = b;
comme il vérifie et refuse:
A a = new A();
B b = a;
Oui et pour moi, c'est sur les variables a et b que le compilateur fait
les vérifications et pas sur les objets créés sur le tas. Le compilateur
dit : "hors de question de mettre le contenu de la variable a de type A
dans la variable b de type B". Peu importe le type de l'objet référencé
par a, ça pourrait être un objet de type B que le compilateur n'en
voudrait pas non plus.
Ok, mais le compilateur ne peut pas avant vérifier si le cast est
compatible avec le type de l'objet référencé ?
Animal animal = getPet();
if (animal instanceof Chien){
Chien c = (Chien) animal;
c.faitQlqChose();
}
C'est là où je butte un peu (désolé). Je pensais que le test "if (animal
instanceof Chien){...}" pouvait être fait par le compilateur justement ?
les "objets du tas" ??? c'est quoi ça, oublie la notion de pile et tas,
non applicable à Java.
le compilo refuse de mettre un a (qu'il sait être un A à ce moment)
dans une var. b de type B car un tel cast est invalide; tes classes
ne sont peut être pas assez "remplies" pour que cela soit évident
mais imagine:
class Animal {
public void faitDuBruit() {}
}
class Chien extends Animal {
public void faitDuBruit() {}
public void aboie() {}
public void mord() {}
}
dans ce cas le compilo "voit" bien que mettre un a dans un B,
ce qui te permettrait d'invoquer A.aboie() ou A.mord() est
invalide puisque ces méthodes n'existent pas.
Ok, mais le compilateur ne peut pas avant vérifier si le cast est
compatible avec le type de l'objet référencé ?
non, il ne le peut pas avec les moyens d'un compilo, il le pourrait
seulement s'il faisait une analyse de code et/ou une évaluation
dynamique mais ce serait alors un analyseur de code ou un interpréteur
de code, plus un compilo.
pour cela il aurait besoin de compiler entièrement "animal = getPet()"
et de pouvoir l'exécuter pour évaluer la référence retournée avant de
compiler la ligne suivante; c'est dans 99% des cas impossible.
imagine:
Animal getPet(int type){
switch (type){
case kDOG:
return new Chien();
....
}
}
sauf (à nouveau) à analyser le code et/ou l'éxecuter, le compilo
ne peux rien savoir de plus que le fait qu'un Animal sera retourné,
tout downcast est sous la seule responsabilité du codeur.
les "objets du tas" ??? c'est quoi ça, oublie la notion de pile et tas,
non applicable à Java.
le compilo refuse de mettre un a (qu'il sait être un A à ce moment)
dans une var. b de type B car un tel cast est invalide; tes classes
ne sont peut être pas assez "remplies" pour que cela soit évident
mais imagine:
class Animal {
public void faitDuBruit() {}
}
class Chien extends Animal {
public void faitDuBruit() {}
public void aboie() {}
public void mord() {}
}
dans ce cas le compilo "voit" bien que mettre un a dans un B,
ce qui te permettrait d'invoquer A.aboie() ou A.mord() est
invalide puisque ces méthodes n'existent pas.
Ok, mais le compilateur ne peut pas avant vérifier si le cast est
compatible avec le type de l'objet référencé ?
non, il ne le peut pas avec les moyens d'un compilo, il le pourrait
seulement s'il faisait une analyse de code et/ou une évaluation
dynamique mais ce serait alors un analyseur de code ou un interpréteur
de code, plus un compilo.
pour cela il aurait besoin de compiler entièrement "animal = getPet()"
et de pouvoir l'exécuter pour évaluer la référence retournée avant de
compiler la ligne suivante; c'est dans 99% des cas impossible.
imagine:
Animal getPet(int type){
switch (type){
case kDOG:
return new Chien();
....
}
}
sauf (à nouveau) à analyser le code et/ou l'éxecuter, le compilo
ne peux rien savoir de plus que le fait qu'un Animal sera retourné,
tout downcast est sous la seule responsabilité du codeur.
les "objets du tas" ??? c'est quoi ça, oublie la notion de pile et tas,
non applicable à Java.
le compilo refuse de mettre un a (qu'il sait être un A à ce moment)
dans une var. b de type B car un tel cast est invalide; tes classes
ne sont peut être pas assez "remplies" pour que cela soit évident
mais imagine:
class Animal {
public void faitDuBruit() {}
}
class Chien extends Animal {
public void faitDuBruit() {}
public void aboie() {}
public void mord() {}
}
dans ce cas le compilo "voit" bien que mettre un a dans un B,
ce qui te permettrait d'invoquer A.aboie() ou A.mord() est
invalide puisque ces méthodes n'existent pas.
Ok, mais le compilateur ne peut pas avant vérifier si le cast est
compatible avec le type de l'objet référencé ?
non, il ne le peut pas avec les moyens d'un compilo, il le pourrait
seulement s'il faisait une analyse de code et/ou une évaluation
dynamique mais ce serait alors un analyseur de code ou un interpréteur
de code, plus un compilo.
pour cela il aurait besoin de compiler entièrement "animal = getPet()"
et de pouvoir l'exécuter pour évaluer la référence retournée avant de
compiler la ligne suivante; c'est dans 99% des cas impossible.
imagine:
Animal getPet(int type){
switch (type){
case kDOG:
return new Chien();
....
}
}
sauf (à nouveau) à analyser le code et/ou l'éxecuter, le compilo
ne peux rien savoir de plus que le fait qu'un Animal sera retourné,
tout downcast est sous la seule responsabilité du codeur.
Ah... Une fois de plus j'ai dû lire de mauvaises références. J'ai lu
quelque part que les variables du type "référence à un objet" ne
contenaient pas l'objet lui-même, mais justement une référence sur
l'objet en question (une sorte de "pointeur" [avec des méga guillemets]
vers l'objet)
que l'objet lui (son code en binaire) se trouvait dans une zone de la
mémoire appelée le tas. Je n'en sais pas plus et c'est peut-être des
bêtises alors.
tout downcast est sous la seule responsabilité du codeur.
... exactement ! Ça doit être une des fonctions du cast : dire au
compilateur "là cher compilateur, tu me laisses gérer moi le codeur,
je prends la main !". Mais ce n'est pas sans danger...
Merci beaucoup pour ton aide. :-)
Ah... Une fois de plus j'ai dû lire de mauvaises références. J'ai lu
quelque part que les variables du type "référence à un objet" ne
contenaient pas l'objet lui-même, mais justement une référence sur
l'objet en question (une sorte de "pointeur" [avec des méga guillemets]
vers l'objet)
que l'objet lui (son code en binaire) se trouvait dans une zone de la
mémoire appelée le tas. Je n'en sais pas plus et c'est peut-être des
bêtises alors.
tout downcast est sous la seule responsabilité du codeur.
... exactement ! Ça doit être une des fonctions du cast : dire au
compilateur "là cher compilateur, tu me laisses gérer moi le codeur,
je prends la main !". Mais ce n'est pas sans danger...
Merci beaucoup pour ton aide. :-)
Ah... Une fois de plus j'ai dû lire de mauvaises références. J'ai lu
quelque part que les variables du type "référence à un objet" ne
contenaient pas l'objet lui-même, mais justement une référence sur
l'objet en question (une sorte de "pointeur" [avec des méga guillemets]
vers l'objet)
que l'objet lui (son code en binaire) se trouvait dans une zone de la
mémoire appelée le tas. Je n'en sais pas plus et c'est peut-être des
bêtises alors.
tout downcast est sous la seule responsabilité du codeur.
... exactement ! Ça doit être une des fonctions du cast : dire au
compilateur "là cher compilateur, tu me laisses gérer moi le codeur,
je prends la main !". Mais ce n'est pas sans danger...
Merci beaucoup pour ton aide. :-)
Bonjour à tous,
Je précise que je suis débutant en Java.
Pouvez vous m'expliquer pourquoi ce code se compile correctement. En
fait, je ne comprends pas pourquoi l'erreur manifeste de ce code
(provenant de l'opération de cast illégale il me semble) n'est pas
détectée dès la compilation, mais seulement au moment de l'exécution ?
Merci d'avance.
//-------------------------------------
class Animal
{
public void faireDuBruit()
{
System.out.println("???????") ;
}
}
class Chien extends Animal
{
public void faireDuBruit()
{
System.out.println("Woua Woua !") ;
}
}
class Test
{
public static void main( String [] args)
{
Animal a = new Animal() ;
Chien c = (Chien) a ; // On "cast" la référence a
c.faireDuBruit() ; // Boum !!
}
}
//-------------------------------------
Bonjour à tous,
Je précise que je suis débutant en Java.
Pouvez vous m'expliquer pourquoi ce code se compile correctement. En
fait, je ne comprends pas pourquoi l'erreur manifeste de ce code
(provenant de l'opération de cast illégale il me semble) n'est pas
détectée dès la compilation, mais seulement au moment de l'exécution ?
Merci d'avance.
//-------------------------------------
class Animal
{
public void faireDuBruit()
{
System.out.println("???????") ;
}
}
class Chien extends Animal
{
public void faireDuBruit()
{
System.out.println("Woua Woua !") ;
}
}
class Test
{
public static void main( String [] args)
{
Animal a = new Animal() ;
Chien c = (Chien) a ; // On "cast" la référence a
c.faireDuBruit() ; // Boum !!
}
}
//-------------------------------------
Bonjour à tous,
Je précise que je suis débutant en Java.
Pouvez vous m'expliquer pourquoi ce code se compile correctement. En
fait, je ne comprends pas pourquoi l'erreur manifeste de ce code
(provenant de l'opération de cast illégale il me semble) n'est pas
détectée dès la compilation, mais seulement au moment de l'exécution ?
Merci d'avance.
//-------------------------------------
class Animal
{
public void faireDuBruit()
{
System.out.println("???????") ;
}
}
class Chien extends Animal
{
public void faireDuBruit()
{
System.out.println("Woua Woua !") ;
}
}
class Test
{
public static void main( String [] args)
{
Animal a = new Animal() ;
Chien c = (Chien) a ; // On "cast" la référence a
c.faireDuBruit() ; // Boum !!
}
}
//-------------------------------------