Ce document présente le corrigé détaillé d'un Questionnaire à Choix Multiples (QCM) de Programmation 1, spécifiquement élaboré pour les étudiants de Licence d'informatique. Datant du 1er décembre 2004, il constitue une ressource pédagogique essentielle pour l'approfondissement des concepts fondamentaux de la programmation orientée objet, avec un accent particulier sur le langage Java.
Ce corrigé couvre un éventail de notions cruciales, incluant l'encapsulation, le fonctionnement de la JVM, la gestion des objets et des références, le transtypage, ainsi que les subtilités des méthodes d'instance et statiques.
Corrigé QCM Programmation 1 -Concours QCM
Télécharger PDFCorrigé du QCM de Programmation 1
Ce document présente le corrigé détaillé d'un Questionnaire à Choix Multiples (QCM) sur les fondamentaux de la programmation, spécialement conçu pour les étudiants en Licence d'informatique. Il aborde des concepts clés de la programmation orientée objet et de Java.
Questions Générales
Barème : bonne réponse = 1 pt ; mauvaise réponse = -0,5 pt ; pas de réponse = 0 pt.
Question 1 : L'Encapsulation en Programmation Orientée Objet
Considérez le code Java suivant :
class B {
private int x;
private float y;
public void setX(int x) {
this.x = x;
}
public void setY(float y) {
this.y = y;
}
}
Le code ci-dessus est une illustration du principe d'encapsulation. L'encapsulation est un concept fondamental de la programmation orientée objet qui consiste à regrouper les données (ici, x et y) et les méthodes (setX, setY) qui opèrent sur ces données au sein d'une même unité, la classe. En déclarant les attributs x et y comme private, leur accès direct est restreint, et leur modification est contrôlée uniquement par des méthodes publiques, ce qui protège l'intégrité de l'objet.
Question 2 : Rôle de la JVM
La fonction principale de la Machine Virtuelle Java (JVM) est d'interpréter le bytecode. Le bytecode est un ensemble d'instructions de haut niveau, indépendantes de la plateforme, générées par le compilateur Java à partir du code source. La JVM lit et exécute ce bytecode, permettant ainsi aux programmes Java d'être portables et de fonctionner sur n'importe quel système d'exploitation pourvu d'une JVM.
Question 3 : Langages Orientés Objet
Parmi les langages de programmation, le C n'est pas un langage orienté objet. En revanche, SIMULA est généralement reconnu comme le premier langage à avoir introduit les concepts de l'orientation objet, tandis que C++ est une extension du langage C qui y ajoute des fonctionnalités orientées objet.
Question 4 : Héritage dans les classes Java
En Java, toutes les classes héritent implicitement ou explicitement de la classe Object. Cela signifie que Object est la super-classe ultime de toutes les classes dans la hiérarchie de classes Java, fournissant des méthodes de base que toutes les classes peuvent utiliser ou redéfinir.
Question 5 : Passage de paramètres en Java
Le passage de paramètres en Java est toujours effectué par valeur. Cela signifie qu'une copie de la valeur du paramètre est transmise à la méthode. Pour les types primitifs, c'est la valeur elle-même qui est copiée. Pour les objets, ce sont les références aux objets qui sont passées par valeur. Bien que la référence soit copiée, les modifications apportées à l'objet via cette référence dans la méthode affecteront l'objet original.
Question 6 : Communication entre Objets
Un objet traite un message reçu en exécutant une méthode d'instance. C'est simplement une terminologie différente, souvent utilisée dans le contexte de la programmation orientée objet, pour décrire le mécanisme par lequel un objet invoque une fonction (méthode) d'un autre objet ou de lui-même pour accomplir une tâche.
Questions Spécifiques
Barème : bonne réponse = 3 pt ; mauvaise réponse = -1 pt ; pas de réponse = 0 pt.
Question 7 : Gestion des Instances et du Garbage Collector
Combien d'instances de la classe A sont créées pendant l'exécution du code suivant ? Combien en reste-t-il après le passage du Garbage Collector ?
A u, b, c;
A a = new A();
b = new A();
c = b;
a = b;
Deux instances de la classe A sont créées par les deux appels à new A(). Initialement, la première instance est référencée par a et la deuxième par b. L'instruction a = b; réassigne la référence a pour qu'elle pointe également vers la deuxième instance. La première instance n'est alors plus référencée par aucune variable accessible et devient "orpheline". Par la suite, cette instance non référencée sera automatiquement détectée et nettoyée de la mémoire par le Garbage Collector de Java.
La réponse est donc : 2 instances créées ; 1 instance restante après le passage du Garbage Collector.
Question 8 : Polymorphisme, Upcasting et Downcasting
Étant donné que la classe Sardine étend la classe Poisson, trouvez la ligne de code qui compile correctement mais produit une erreur à l'exécution parmi les propositions suivantes :
-
Poisson y = new Poisson(); Sardine x = (Sardine)y; Poisson z = x;Cette séquence de code compile sans erreur. Le compilateur accepte l'affectation sans transtypage (upcasting implicite de
SardineversPoisson), le downcasting explicite ((Sardine)y), et l'upcasting implicite. Cependant, à l'exécution, l'objet référencé paryest un simplePoisson, et tenter de le transtyper enSardine(un type plus spécifique) via un downcasting explicite provoquera uneClassCastException. Cette ligne correspond à l'énoncé. -
Sardine y = new Sardine(); Poisson x = y; Sardine z = (Sardine)x;Cette séquence compile correctement. Il y a une affectation simple, un upcasting implicite (
SardineenPoisson), et un downcasting explicite. À l'exécution, le downcasting(Sardine)xse déroule sans erreur, car l'objet référencé parxest bien une instance deSardineà l'origine. Aucune erreur n'est produite. -
Poisson y = new Sardine(); Object x = y; Sardine z = x;La dernière affectation,
Sardine z = x;, est un downcasting implicite d'unObjectvers unSardine, ce qui est interdit en Java sans transtypage explicite. Cette ligne générera une erreur à la compilation. -
Poisson y = new Poisson(); Sardine z = new Sardine(); y = z;Cette séquence ne contient aucune opération de transtypage illégale. L'affectation
y = z;est un upcasting implicite valide (uneSardinepeut être traitée comme unPoisson). Le code compilera et s'exécutera sans problème.
Question 9 : Variables Statiques et d'Instance
Pour la classe D définie comme suit :
class D {
public static int x;
public int y;
public static void travailler() { // Ajout de 'void' pour une syntaxe Java correcte
x++;
}
public D() {
x++;
y--;
}
}
Qu'affichera le code suivant ?
D.travailler();
D a = new D();
D b = new D();
a.travailler();
System.out.println(b.x + " et " + b.y);
Analyse des valeurs :
xest une variable de classe (déclaréestatic). Elle est unique pour toute la classeDet partagée par toutes ses instances. Sa valeur est initialisée à 0 par défaut.D.travailler();incrémentex(xdevient 1).D a = new D();appelle le constructeur deD, qui incrémentex(xdevient 2).D b = new D();appelle le constructeur deD, qui incrémentex(xdevient 3).a.travailler();appelle la méthode statiquetravailler()(équivalent àD.travailler()), qui incrémentex(xdevient 4).
xest donc 4.yest une variable d'instance. Chaque objet de la classeDpossède sa propre variabley, initialisée à 0 par défaut.- La variable
b.yest affectée uniquement par le constructeur deb. Lors de l'appel ànew D()pourb, le constructeury--est exécuté.
b.yest donc -1.- La variable
La sortie affichée sera : 4 et -1.
Note : Dans la définition de la classe D fournie, la méthode travailler() manquait du type de retour void. Pour être un code Java valide, elle devrait être déclarée comme public static void travailler().
Question 10 : Chaînage de Constructeurs et Initialisation en Java
Pour les classes Oeuf et Poule définies comme suit :
class Oeuf {
public int x;
public Oeuf() {
x = 5;
}
public Oeuf(int y) {
x = y;
}
}
class Poule extends Oeuf {
public Poule() {
// Appel implicite à super() qui exécute Oeuf()
}
public Poule(int i) {
this(); // Appelle le constructeur Poule() de la même classe
x = x * i;
}
public Poule(String s) {
super(33); // Appelle le constructeur Oeuf(int y) de la super-classe
x--;
}
}
Qu'affichera le code suivant ?
Poule b1 = new Poule("2004");
Poule b2 = new Poule(2004);
Poule b3 = new Poule();
System.out.println(b1.x + " et " + b2.x + " et encore " + b3.x);
Analyse des initialisations :
- Pour
b1 = new Poule("2004");:- Le constructeur
Poule(String s)est appelé. - Il contient un appel explicite
super(33), ce qui exécuteOeuf(int y).b1.xest initialisé à 33. - Après l'appel à
super(), l'instructionx--est exécutée dansPoule(String s). Donc,b1.xdevient 32.
b1.xest 32. - Le constructeur
- Pour
b2 = new Poule(2004);:- Le constructeur
Poule(int i)est appelé. - Il contient un appel explicite
this(), ce qui exécute le constructeur par défautPoule(). - Le constructeur
Poule()contient un appel implicitesuper(), ce qui exécute le constructeur par défautOeuf().b2.xest initialisé à 5. - De retour dans
Poule(int i), l'instructionx = x * i;est exécutée. Donc,b2.x = 5 * 2004, ce qui donne 10020.
b2.xest 10020. - Le constructeur
- Pour
b3 = new Poule();:- Le constructeur
Poule()est appelé. - Il contient un appel implicite
super(), ce qui exécute le constructeur par défautOeuf().b3.xest initialisé à 5.
b3.xest 5. - Le constructeur
La sortie affichée sera : 32 et 10020 et encore 5.
Question 11 : Liaison Statique vs. Dynamique (Polymorphisme)
Pour les classes A et B définies comme suit :
class A {
public int f(int x) {
return (x + 1);
}
public static int g(int x) {
return 6;
}
}
class B extends A {
public int f(int x) {
return (x + 2);
}
public static int g(int x) {
return (x + 4);
}
}
Qu'affichera le code suivant ?
B b = new B();
A a = b;
System.out.println(a.f(2) * a.g(3));
Analyse de l'exécution :
- Pour la méthode d'instance
f:- La méthode
fest définie dans la classeAet redéfinie (surchargée) dans la classeB. - Le choix de la version de
fà exécuter s'effectue à l'exécution (mécanisme de liaison dynamique ou polymorphisme) et dépend du type réel de l'objet référencé. - Puisque la variable
a, bien que déclarée de typeA, référence en réalité un objet de typeB(A a = b;), la JVM exécutera la méthodefde la classeB. a.f(2)appellera doncB.f(2), ce qui retourne(2 + 2) = 4.
- La méthode
- Pour la méthode statique
g:- Les méthodes statiques sont associées à une classe et non à une instance. Leur version est choisie statiquement par le compilateur (liaison statique), basée sur le type déclaré de la variable, et non sur le type réel de l'objet.
- Ici,
aest déclarée de typeA. Par conséquent,a.g(3)est interprété comme un appel à la méthode statiqueA.g(3). A.g(3)retourne 6.
Le calcul final effectué par System.out.println() sera 4 * 6 = 24.
La sortie affichée sera donc : 24.
Foire Aux Questions (FAQ) sur la Programmation Orientée Objet en Java
Qu'est-ce que l'encapsulation en programmation orientée objet ?
L'encapsulation est un principe fondamental de la programmation orientée objet (POO) qui consiste à regrouper les données (attributs) et les méthodes (fonctions) qui les manipulent au sein d'une seule entité, la classe. Elle permet de masquer les détails d'implémentation internes de l'objet et de protéger les données contre les accès et modifications directs non autorisés. L'accès aux données se fait de manière contrôlée, généralement via des méthodes publiques appelées "getters" et "setters", garantissant ainsi la cohérence et l'intégrité de l'état de l'objet.
Quelle est la différence entre le passage par valeur et le passage par référence en Java ?
En Java, tous les paramètres sont passés par valeur. Cela signifie qu'une copie de la valeur du paramètre est transmise à la méthode appelée. Pour les types primitifs (comme int, float, boolean), c'est la valeur elle-même qui est copiée. Ainsi, modifier ce paramètre dans la méthode n'affecte pas la variable d'origine. Pour les objets, c'est la référence (l'adresse mémoire) de l'objet qui est copiée par valeur. La méthode reçoit donc une copie de cette référence. Elle peut utiliser cette référence pour modifier l'état interne de l'objet original, mais elle ne peut pas changer la référence elle-même pour faire pointer la variable d'origine vers un nouvel objet.
Quel est le rôle du Garbage Collector en Java ?
Le Garbage Collector (GC), ou "ramasse-miettes", est un mécanisme automatique de gestion de la mémoire en Java, intégré à la JVM. Son rôle principal est de libérer l'espace mémoire occupé par les objets qui ne sont plus référencés par aucune partie active du programme. En d'autres termes, il identifie et supprime les objets inutilisés (les "déchets") pour rendre leur mémoire disponible. Cela évite aux développeurs de devoir gérer manuellement l'allocation et la libération de la mémoire, réduisant ainsi les risques de fuites de mémoire et de problèmes liés à la gestion manuelle.