Exercice Java : Géneralites

EXERCICE + CORRIGE EN JAVA :  géneralites sur le java

 

 

1) Définition: objet, classe, classe enveloppe, Héritage
Objet : est l'instance d'une classe. C'est une entité qui a des attributs (variables) et des méthodes (fonctions) associés.

Classe : Une classe est un modèle ou un plan pour créer des objets. Elle définit les attributs et les méthodes que les objets créés à partir de cette classe auront.

Classe enveloppe : Une classe enveloppe (wrapper class) est une classe qui encapsule un type de données primitif et lui donne des méthodes utiles. Par exemple, les classes Integer, Double, etc., enveloppent les types primitifs int, double, etc.

Héritage : L'héritage est un concept de la programmation orientée objet où une classe peut hériter des attributs et des méthodes d'une autre classe. Cela favorise la réutilisation du code.
2) Comparaison d'objets et Classe GeniusTest
2.1 Pour comparer deux objets d'une classe, on doit éviter d'utiliser == car cela compare les références d'objets, pas leurs contenus.

2.2 Pour comparer des objets de la classe A, on doit utiliser la méthode equals() ou une méthode personnalisée de comparaison. Exemple avec GeniusTest :


public class GeniusTest {
    // ...

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        // Comparaison détaillée des attributs de GeniusTest
        GeniusTest other = (GeniusTest) obj;
        return Objects.equals(mbre1, other.mbre1) && Objects.equals(mbre2, other.mbre2);
    }
}
3) Définir et donner un exemple: Polymorphisme, classe enveloppe, exception, bloc déclaré statique, classe anonyme
3.1 Polymorphisme : Le polymorphisme permet à un objet d'être traité comme une instance de sa classe parente. Exemple avec GeniusTest :


public class GeniusTest {
    public void polymorphicMethod(A a) {
        // Code qui utilise l'objet a, peu importe la classe concrète réelle
    }
}
3.2 Classe enveloppe : Voir la réponse précédente.

3.3 Exception : Une exception est un événement anormal qui se produit pendant l'exécution d'un programme. Exemple :


try {
    // Code susceptible de provoquer une exception
} catch (SomeException e) {
    // Gestion de l'exception
}
3.4 Bloc déclaré statique : Un bloc statique est un bloc de code qui est exécuté lors de la chargement de la classe. Exemple :


public class GeniusTest {
    static {
        // Code exécuté une seule fois lors du chargement de la classe
    }
}
3.5 Classe anonyme : Une classe anonyme est une classe sans nom directement déclarée dans le code. Exemple :


SomeInterface instance = new SomeInterface() {
    @Override
    public void someMethod() {
        // Implémentation de SomeInterface sans créer une classe distincte
    }
};
4) Quand doit-on préférer utiliser une classe abstraite plutôt qu'une interface?
On préfère utiliser une classe abstraite lorsque nous avons une implémentation partielle commune à toutes les sous-classes et que nous voulons fournir une base commune pour les méthodes. On utilise une interface lorsque nous voulons spécifier un contrat sans fournir d'implémentation par défaut.
5) Questions sur la classe A
5.1 Comparaison d'objets de la classe A : On doit éviter d'utiliser == et utiliser plutôt la méthode equals(). Voir la réponse à la question 2.2.

5.2 Affectation de surface et affectation en profondeur :

Affectation de surface (shallow copy) : Les références des objets sont copiées, pas les objets eux-mêmes. Cela peut conduire à des problèmes si les objets contiennent des références à d'autres objets.

Affectation en profondeur (deep copy) : Les objets et tous les objets référencés sont copiés. Cela garantit une copie indépendante de chaque objet.

Exemple illustratif :


// Affectation de surface
A a1 = new A();
A a2 = a1; // a2 et a1 référencent le même objet

// Affectation en profondeur
A a1 = new A();
A a2 = a1.clone(); // Supposons que la classe A implémente l'interface Cloneable
5.3 Code pour une affectation en profondeur :


public class A implements Cloneable {
    private B mbre1;
    private B mbre2;

    @Override
    public A clone() throws CloneNotSupportedException {
        A clonedA = (A) super.clone();
        // Copier également les objets B (sous-objets)
        clonedA.mbre1 = this.mbre1.clone();
        clonedA.mbre2 = this.mbre2.clone();
        return clonedA;
    }
}

QUESTIONS DE COURS JAVA :

Questions 1 et 2 :
Définition: objet, classe, classe anonyme, classe enveloppe (0,75x=3pts)
Comment pouvez-vous garantir que toutes les erreurs que peut provoquer une instruction (un appel de méthode par exemple) soient traitées ? (Ipt)
Réponses :

Objet : Un objet en Java est une instance d'une classe. Il est une entité qui a un état et un comportement. Les objets sont créés à partir des classes et peuvent interagir entre eux.

Classe : Une classe en Java est un modèle ou un plan pour créer des objets. Elle définit les variables et les méthodes communes à tous les objets de ce type.

Classe Anonyme : Une classe anonyme est une classe sans nom, utilisée pour créer une instance de cette classe en même temps qu'elle est définie.

Classe Enveloppe : Les classes enveloppes (wrapper classes) en Java sont utilisées pour encapsuler des types primitifs dans des objets. Par exemple, Integer est une classe enveloppe pour le type primitif int.

Garantir le traitement des erreurs : Pour garantir que toutes les erreurs sont traitées, vous pouvez utiliser des blocs try-catch. Dans un bloc try, vous placez le code susceptible de générer une exception, et dans un bloc catch, vous spécifiez comment traiter cette exception.

Questions 3 et 4 :
Si plusieurs types d'exceptions sont traités, dans quel ordre les blocs catch doivent-ils être placés ? (Ipt)
Quelle est la différence entre throw et throws ? (Ipt)
Réponses :

Ordre des blocs catch : Les blocs catch doivent être placés de la plus spécifique à la plus générale. Cela signifie que vous devez attraper les exceptions les plus spécifiques d'abord, puis les plus générales à la fin.

Différence entre throw et throws :

throw : Utilisé pour lever une exception explicite dans un programme.
throws : Utilisé dans la signature de la méthode pour déclarer les types d'exceptions que la méthode peut lancer. Cela informe le compilateur des exceptions potentielles, mais la gestion réelle se fait à l'endroit où la méthode est appelée.

Questions 5 et 6 :
Définition: classe, objet, Héritage, encapsulation (0,5ptx4=2pts)
Si une variable possède le même nom qu'une variable d'instance, comment pouvez-vous faire référence à la variable d'instance dans la portée de la variable locale? (Ipt)
Réponses :

Héritage : L'héritage en Java permet à une classe (sous-classe) d'hériter des caractéristiques et des comportements d'une autre classe (super-classe).

Encapsulation : L'encapsulation est le principe de regrouper les données (variables) et les méthodes qui les manipulent dans une seule unité appelée classe.

Référence à une variable d'instance dans la portée d'une variable locale : Pour faire référence à la variable d'instance lorsque le nom est le même que celui d'une variable locale, on utilise le mot-clé this. Par exemple, this.variableInstance.

Question 7 :
Dans quel cas doit-on utiliser une classe abstraite ? une interface? (1,5pts)
Réponse :

Classe Abstraite : On utilise une classe abstraite lorsque l'on veut fournir une base commune pour plusieurs classes dérivées. Elle peut contenir des méthodes abstraites (non implémentées) et des méthodes concrètes.

Interface : On utilise une interface lorsque l'on veut définir un contrat que plusieurs classes peuvent implémenter. Elle ne contient que des signatures de méthodes (pas de corps de méthode) et est utilisée pour définir un comportement commun à plusieurs classes.

Question 8 :
En java, on peut créer un tableau irrégulier où chaque tableau élément du tableau de tableaux a sa propre taille. Donner le code java permettant de créer un tableau bidimensionnel tel que, le premier sous tableau soit de taille 2, et le second de taille 4. (1pt)
Réponse :


public class TableauIrregulier {
    public static void main(String[] args) {
        // Création d'un tableau bidimensionnel irrégulier
        int[][] tableauIrregulier = new int[2][];
        tableauIrregulier[0] = new int[2];  // Premier sous-tableau de taille 2
        tableauIrregulier[1] = new int[4];  // Deuxième sous-tableau de taille 4

        // Accès et modification des éléments
        tableauIrregulier[0][0] = 1;
        tableauIrregulier[1][2] = 3;
    }
}

Question 9 :
On dispose d'une classe A contenant des membres de type classe (disons mbrel et mbre2 de type B). On suppose qu'on ait deux variables al et a2 de type A contenant chacune une référence d'une instance de A: Expliquez pourquoi on doit éviter d'utiliser pour comparer deux objets d'une classe(0,5pt). Comment doit-on procéder pour le cas de la classe A ci-dessus? (pt)
Réponse :

L'utilisation de == pour comparer des objets en Java compare les références, pas les contenus des objets. Cela signifie que cela vérifie si les deux références pointent vers le même objet en mémoire, pas s'ils ont des valeurs égales.

Pour comparer les contenus des objets de la classe A, on devrait plutôt utiliser la méthode equals() que la classe A devrait être personnalisée pour implémenter. Dans la classe A, on devrait surcharger la méthode equals() pour définir comment comparer deux instances de A en fonction de leurs membres mbrel et mbre2.

Question 10 :
Les tableaux sont des objets clonables. Pour cloner un tableau bidimensionnel, on ne peut pas se contenter de l'appel de la méthode clone(). Justifiez cette assertion. (1pt)
Réponse :

L'appel de la méthode clone() pour un tableau bidimensionnel ne crée qu'une copie superficielle, c'est-à-dire que seuls les tableaux de la première dimension sont clonés, pas les tableaux de la deuxième dimension. Cela signifie que les références vers les tableaux de la deuxième dimension sont partagées entre l'original et le clone.

Pour obtenir une copie profonde d'un tableau bidimensionnel, on doit parcourir chaque élément du tableau d'origine et cloner chaque sous-tableau individuellement.

Question 11 :
Pour les classes A et D définies comme suit:

class A {
    public static int f(int x) { return x + 3; }
    public int g(int x) { return (x * f(x)); }
}

class D extends A {
    public static int f(int x) { return x; }
    public int g(int x) { return (super.g(x) + f(x) + 5); }
}
// Qu'affichera le code suivant ?

class B extends A {
    public static int f(int x) { return x; }
    public int g(int x) { return (super.g(x) * f(x) + 5); }
}

public class Main {
    public static void main(String[] args) {
        B b = new B();
        A a = b;
        System.out.println(a.f(2)*a.g(3));
    }
}
Réponse :

295

Exercice : 05 pts   Questions de Cours

  1. Définir et donner un exemple :
  • Membre de classe déclaré static : Un membre de classe déclaré static appartient à la classe plutôt qu'à une instance de la classe. Exemple : public static int compteur = 0;
  • Bloc déclaré static : Un bloc statique est un ensemble d'instructions déclaré suivant une syntaxe particulière . Exemple :
public class Genius {  
      
     static
         // ceci est un bloc statique  
    }  
}
 Attribut déclaré final : Un attribut peut être déclaré comme final. Cela signifie qu’il n’est plus possible d’affecter une valeur à cet attribut une fois qu’il a été initialisé. Dans cas, le compilateur exige que l’attribut soit initialisé explicitement. Exemple : 
public class GeniusAuto {
  public String marque;
  public float vitesse;
  public final int nombreDeRoues = 4;
}

L’attribut GeniusAuto.nombreDeRoues sera initialisé avec la valeur 4 pour chaque instance et ne pourra plus être modifié.

GeniusAuto voiture = new GeniusAuto();

voiture.nombreDeRoues = 5; // ERREUR DE COMPILATION

  •  Méthode déclarée final : Une méthode déclarée final ne peut pas être redéfinie par les sous-classes. Exemple :

public final void afficher() {

    System.out.println("Méthode finale");

}

  • Classe déclarée final : Une classe déclarée final ne peut pas être étendue par d'autres classes. Exemple : public final class MyClass {}
  1. L'intérêt de déclarer une interface est de fournir un contrat pour les classes qui l'implémentent, en définissant les méthodes qu'elles doivent avoir. Oui, on peut déclarer des classes sans passer par une interface, mais l'utilisation d'interfaces permet de favoriser la modularité, l'abstraction et le polymorphisme.
  2. On doit éviter d'utiliser == pour comparer deux objets d'une classe car cela compare les références mémoire et non les valeurs. Dans le cas général, on devrait utiliser la méthode equals() pour effectuer une comparaison basée sur les valeurs des objets.

QUESTION COURS JAVA

Exercice : Indiquer les réponses correctes. Correcte ?

Une classe est une instance d'un objet. ✘

Dans une méthode, il est possible d'accéder à l'instance courante à l'aide du mot-clé this. ✔

Le mot-clé private permet de garantir qu'une variable ne pourra être accédée que par toutes les instances de la classe à laquelle elle appartient. ✔

Il est possible de déclarer des variables dans une interface si elles sont déclarées final. ✔

Il est impossible d'appeler un constructeur à partir d'un autre constructeur de la même classe. ✘

Il faut toujours définir un constructeur sans paramètre dans une classe. ✘

Une classe mère ne peut pas définir de membres protected. ✘

Une classe fille a accès à tous les membres de ses super-classes. ✘

En Java, toutes les classes héritent de la classe Object. ✔

Les variables statiques sont accessibles uniquement à partir de méthodes statiques. ✘

Une classe abstraite ne peut hériter d'une autre classe abstraite. ✘

Une classe abstraite doit définir au moins une méthode abstraite. ✘

Une méthode abstraite peut être appelée dans la classe qui la définit. ✔

Les exceptions sont des objets. ✔

Les méthodes de la classe String ne modifient jamais le contenu du receveur. ✔

 

EXERCICE 2 :

Expliquer la différence entre le concept de liaison dynamique et celui de liaison statique. Illustrer votre propos par deux exemples de code (un pour chaque type de liaison).

La liaison dynamique (ou liaison tardive) et la liaison statique (ou liaison précoce) sont deux concepts liés à la résolution des méthodes en programmation orientée objet.

Liaison dynamique :

La résolution de la méthode se fait pendant l'exécution du programme.

Le choix de la méthode à appeler dépend du type réel de l'objet.

Exemple de code :

class Animal {
    void faireSon() {
        System.out.println("Certains animaux font du bruit");
    }
}

class Chien extends Animal {
    void faireSon() {
        System.out.println("Le chien aboie");
    }
}

public class Genius {
    public static void main(String[] args) {
        Animal monAnimal = new Chien();
        monAnimal.faireSon(); // Appelle la méthode faireSon() de Chien
    }
}

 

Liaison statique :

La résolution de la méthode se fait lors de la compilation.

Le choix de la méthode à appeler dépend du type déclaré de la référence.

Exemple de code :

class Animal {
    void faireSon() {
        System.out.println("Certains animaux font du bruit");
    }
}

class Chien extends Animal {
    void faireSon() {
        System.out.println("Le chien aboie");
    }
}

public class Genius {
    public static void main(String[] args) {
        Animal monAnimal = new Animal();
        monAnimal.faireSon(); // Appelle la méthode faireSon() de Animal
    }
}

 

Dans le premier exemple, avec la liaison dynamique, la méthode appelée dépend du type réel de l'objet, tandis que dans le deuxième exemple, avec la liaison statique, la méthode appelée dépend du type déclaré de la référence.

 

EXERCICE 3 : Expliquer la difference entre une exception verifiee et une exception non-verifiee. Indiquer dans quel cas il est convient d’utiliser l’une ou l’autre. donne des exemples ( Classe des enitier, EntierException) :

reponse : Les exceptions vérifiées (checked exceptions) et les exceptions non vérifiées (unchecked exceptions) sont deux types d'exceptions en Java, et leur distinction réside dans le fait que le compilateur impose ou non leur gestion explicite.

Exceptions Vérifiées (Checked Exceptions) :

Ce sont des exceptions qui héritent de la classe Exception (mais pas de RuntimeException).

Le compilateur oblige à gérer ces exceptions, soit en utilisant une clause throws dans la signature de la méthode, soit en utilisant un bloc try-catch pour les attraper.

Elles sont généralement utilisées pour des situations où l'application peut anticiper et traiter l'erreur.

Exemple avec une classe d'entier (EntierException est supposée être une exception vérifiée) :

public class EntierException extends Exception {
    public EntierException(String message) {
        super(message);
    }

    public static void main(String[] args) {
        try {
            verifierEntier(10);
            verifierEntier(-5); // Cela générera une EntierException
        } catch (EntierException e) {
            System.out.println("Exception vérifiée : " + e.getMessage());
        }
    }

    public static void verifierEntier(int entier) throws EntierException {
        if (entier < 0) {
            throw new EntierException("Entier négatif non autorisé");
        }
        // Autres traitements si l'entier est valide
    }
}

Exceptions Non Vérifiées (Unchecked Exceptions) :

Ce sont des exceptions qui héritent de RuntimeException.

Le compilateur n'impose pas explicitement la gestion de ces exceptions.

Elles sont généralement utilisées pour des erreurs de programmation (bug) ou des situations imprévues.

Exemple avec une classe d'entier (ArithmeticException est une exception non vérifiée) :

public class EntierNonVerifie {
    public static void main(String[] args) {
        int resultat = diviser(10, 0); // Cela générera une ArithmeticException
        System.out.println("Résultat : " + resultat);
    }

    public static int diviser(int a, int b) {
        return a / b; // Tentative de division par zéro
    }
}

En gros on utilise des exceptions vérifiées lorsque l'on veut forcer la gestion explicite des erreurs dans le code, tandis que les exceptions non vérifiées sont généralement réservées aux erreurs de programmation et aux situations imprévues.

 

Exercice 4 : Donner deux mesures qu’il est recommande de mettre en place pour preserver l’encapsulation au sein d’une classe. Illustrer vos propos en donnant un exemple de code java. Expliquer quel peut etre l’interet de definir une classe abstraite

Solution :

Pour préserver l'encapsulation au sein d'une classe en Java, il est recommandé de suivre les pratiques suivantes :

Déclarer les variables d'instance comme privées :

En déclarant les variables d'instance comme privées, on limite l'accès direct à ces variables depuis l'extérieur de la classe.

L'accès aux données se fait via des méthodes d'accès (getters et setters), ce qui permet un contrôle total sur la manière dont les données sont manipulées.

Utiliser des méthodes d'accès (getters et setters) :

L'utilisation de méthodes d'accès permet de fournir un moyen contrôlé d'accéder et de modifier les données encapsulées.

Les getters permettent de lire la valeur d'une variable d'instance, tandis que les setters permettent de modifier cette valeur tout en appliquant des vérifications si nécessaire.

Illustrons ces principes avec un exemple de code Java :

 

public class Genius { // Variables d'instance privées private String nom;

private int age; // Constructeur publicGenius(String nom, int age) { this.nom = nom; this.age = age; }

// Méthodes d'accès pour la variable "nom" public String getNom() { return nom; } public void setNom(String nom) { // On peut ajouter des vérifications ici si nécessaire this.nom = nom; } // Méthodes d'accès pour la variable "age" public int getAge() { return age; } public void setAge(int age) { // On peut ajouter des vérifications ici si nécessaire this.age = age; } // Autres méthodes de la classe... }

Dans cet exemple, les variables nom et age sont privées, et l'accès à ces données se fait à travers les méthodes getNom, setNom, getAge, et setAge. Cela permet de contrôler l'accès et la modification des données encapsulées.

Quant à la définition d'une classe abstraite, voici son intérêt :

Intérêt de définir une classe abstraite :

Une classe abstraite peut contenir à la fois des méthodes abstraites (sans implémentation) et des méthodes concrètes (avec implémentation).

Elle sert souvent de classe de base pour d'autres classes (sous-classes) qui étendent son comportement.

Les méthodes abstraites dans une classe abstraite sont implémentées par les sous-classes, favorisant ainsi la polymorphie et la réutilisation du code.

Illustrons cela avec un exemple simple :

public abstract class Forme {
    // Méthode abstraite à implémenter par les sous-classes
    public abstract double calculerSurface();

    // Méthode concrète partagée par toutes les sous-classes
    public void afficherType() {
        System.out.println("Type de forme : " + this.getClass().getSimpleName());
    }
}

// Exemple de sous-classe
public class Cercle extends Forme {
    private double rayon;

    public Cercle(double rayon) {
        this.rayon = rayon;
    }

    @Override
    public double calculerSurface() {
        return Math.PI * Math.pow(rayon, 2);
    }
}

// Exemple d'utilisation
public class Main {
    public static void main(String[] args) {
        Forme cercle = new Cercle(5.0);
        cercle.afficherType();
        System.out.println("Surface du cercle : " + cercle.calculerSurface());
    }
}

Dans cet exemple, la classe abstraite Forme définit une méthode abstraite calculerSurface() que les sous-classes, comme Cercle, doivent implémenter. La classe abstraite fournit également une méthode concrète afficherType(), qui est partagée par toutes les sous-classes. L'utilisation de cette hiérarchie de classes permet une structure plus modulaire et extensible.

 

 

 

Qu'est-ce que la JVM ?

Réponse : La JVM (Java Virtual Machine) est une machine virtuelle qui permet l'exécution de programmes Java. Elle traduit le bytecode Java en instructions compréhensibles par la machine sous-jacente.

Quel est le rôle principal de la JVM dans l'exécution de programmes Java ?

Réponse : La JVM est responsable de l'exécution du bytecode généré par le compilateur Java. Elle gère la gestion de la mémoire, l'exécution des threads, la gestion des exceptions et d'autres aspects de l'exécution du programme Java.

Pourquoi Java est-il considéré comme une plate-forme indépendante grâce à la JVM ?

Réponse : Java est considéré comme indépendant de la plate-forme parce que le code source est compilé en bytecode, qui est ensuite interprété par la JVM spécifique à chaque plate-forme. Ainsi, le même bytecode peut être exécuté sur différentes machines sans modification.

Qu'est-ce que le JDK ?

Réponse : Le JDK (Java Development Kit) est un ensemble d'outils de développement nécessaires pour développer des applications Java. Il comprend le compilateur Java, la JVM, des bibliothèques, des outils de débogage et d'autres utilitaires.

Différence entre le JDK et le JRE ?

Réponse : Le JDK comprend le JRE (Java Runtime Environment) ainsi que des outils de développement supplémentaires tels que le compilateur Java. Le JRE comprend uniquement la JVM et les bibliothèques nécessaires pour l'exécution des applications Java.

Qu'est-ce que le JRE ?

Réponse : Le JRE (Java Runtime Environment) est un ensemble d'outils qui fournit l'environnement d'exécution nécessaire pour exécuter des applications Java. Il comprend la JVM et les bibliothèques Java standard.

Est-il possible d'exécuter une application Java sans le JRE ?

Réponse : Non, le JRE est nécessaire pour exécuter des applications Java. Il fournit la JVM et d'autres composants nécessaires pour l'exécution des programmes Java.

Questions sur le Bytecode :

Qu'est-ce que le bytecode Java ?

Réponse : Le bytecode Java est un code intermédiaire généré lors de la compilation d'un programme Java. Il est indépendant de la plate-forme et est exécuté par la JVM.

Pourquoi utilise-t-on le bytecode dans Java ?

Réponse : Le bytecode est utilisé pour rendre les programmes Java indépendants de la plate-forme. Il permet à la JVM de traduire le bytecode en code machine spécifique à chaque plate-forme lors de l'exécution.

Si vous avez trouvé les exercices corrigés en Java de Mr JoëlYk intéressants et utiles, pourquoi ne pas les partager avec d'autres personnes qui pourraient également en bénéficier ? Partagez ce lien sur les réseaux sociaux ou envoyez-le à vos amis et collègues. Vous pourriez aider quelqu'un à améliorer ses compétences en programmation ou à trouver des solutions à des problèmes complexes. N'oubliez pas que la connaissance doit être partagée pour grandir. Merci pour votre soutien et votre partage !

Contact WhatsApp : +237 652027193 | Réaliser Par Joël_Yk

  • Aucune note. Soyez le premier à attribuer une note !

Ajouter un commentaire

Anti-spam