CodeGym/Blog Java/Aleatoriu/Polimorfismul Java
John Squirrels
Nivel
San Francisco

Polimorfismul Java

Publicat în grup
Întrebările legate de POO sunt o parte integrantă a interviului tehnic pentru un post de dezvoltator Java într-o companie IT. În acest articol, vom vorbi despre un principiu al OOP – polimorfismul. Ne vom concentra asupra aspectelor despre care sunt adesea întrebați în timpul interviurilor și, de asemenea, vom oferi câteva exemple pentru claritate.

Ce este polimorfismul în Java?

Polimorfismul este capacitatea unui program de a trata obiecte cu aceeași interfață în același mod, fără informații despre tipul specific al obiectului. Dacă răspundeți la o întrebare despre ce este polimorfismul, cel mai probabil vi se va cere să explicați ce ați vrut să spuneți. Fără a declanșa o grămadă de întrebări suplimentare, expuneți totul pentru intervievator încă o dată. Timpul interviului: polimorfismul în Java - 1Puteți începe cu faptul că abordarea OOP presupune construirea unui program Java bazat pe interacțiunea dintre obiecte, care se bazează pe clase. Clasele sunt modele scrise anterior (șabloane) folosite pentru a crea obiecte în program. Mai mult, o clasă are întotdeauna un tip specific, care, cu un stil de programare bun, are un nume care sugerează scopul său. Mai mult, se poate observa că, deoarece Java este tastată puternic, codul programului trebuie să specifice întotdeauna un tip de obiect atunci când variabilele sunt declarate. Adăugați la aceasta faptul că tastarea strictă îmbunătățește securitatea și fiabilitatea codului și face posibilă, chiar și la compilare, prevenirea erorilor din cauza tipurilor de incompatibilitate (de exemplu, încercarea de a împărți un șir la un număr). Desigur, compilatorul trebuie să „știe” tipul declarat – poate fi o clasă din JDK sau una pe care am creat-o noi înșine. Arătați intervievatorului că codul nostru poate folosi nu numai obiectele de tipul indicat în declarație, ci și descendenții acestuia.Acesta este un punct important: putem lucra cu mai multe tipuri diferite ca un singur tip (cu condiția ca aceste tipuri să fie derivate dintr-un tip de bază). Aceasta înseamnă, de asemenea, că dacă declarăm o variabilă al cărei tip este o superclasă, atunci putem aloca o instanță a unuia dintre descendenții ei acelei variabile. Intervievatorului îi va plăcea dacă dați un exemplu. Selectați o clasă care ar putea fi partajată de (o clasă de bază pentru) mai multe clase și faceți ca câteva dintre ele să o moștenească. Clasa de baza:
public class Dancer {
    private String name;
    private int age;

    public Dancer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void dance() {
        System.out.println(toString() + " I dance like everyone else.");
    }

    @Override
    public String toString() {
        Return "I'm " + name + ". I'm " + age + " years old.";
    }
}
În subclase, suprascrieți metoda clasei de bază:
public class ElectricBoogieDancer extends Dancer {
    public ElectricBoogieDancer(String name, int age) {
        super(name, age);
    }
// Override the method of the base class
    @Override
    public void dance() {
        System.out.println(toString () + " I dance the electric boogie!");
    }
}

public class Breakdancer extends Dancer {

    public Breakdancer(String name, int age) {
        super(name, age);
    }
// Override the method of the base class
    @Override
    public void dance() {
        System.out.println(toString() + " I breakdance!");
    }
}
Un exemplu de polimorfism și modul în care aceste obiecte ar putea fi utilizate într-un program:
public class Main {

    public static void main(String[] args) {
        Dancer dancer = new Dancer("Fred", 18);

        Dancer breakdancer = new Breakdancer("Jay", 19); // Widening conversion to the base type
        Dancer electricBoogieDancer = new ElectricBoogieDancer("Marcia", 20); // Widening conversion to the base type

        List<dancer> disco = Arrays.asList(dancer, breakdancer, electricBoogieDancer);
        for (Dancer d : disco) {
            d.dance(); // Call the polymorphic method
        }
    }
}
În metoda principală , arătați că liniile
Dancer breakdancer = new Breakdancer("Jay", 19);
Dancer electricBoogieDancer = new ElectricBoogieDancer("Marcia", 20);
declară o variabilă a unei superclase și îi atribuie un obiect care este o instanță a unuia dintre descendenții săi. Cel mai probabil veți fi întrebat de ce compilatorul nu se răstoarnă la inconsecvența tipurilor declarate pe părțile din stânga și din dreapta ale operatorului de atribuire - la urma urmei, Java este puternic tastat. Explicați că aici funcționează o conversie de tip extins - o referință la un obiect este tratată ca o referință la clasa sa de bază. Mai mult, după ce a întâlnit un astfel de construct în cod, compilatorul realizează conversia automat și implicit. Exemplul de cod arată că tipul declarat în partea stângă a operatorului de atribuire ( Dancer ) are mai multe forme (tipuri), care sunt declarate în partea dreaptă ( Breakdancer , ElectricBoogieDancer ).). Fiecare formă poate avea propriul său comportament unic în raport cu funcționalitatea generală definită în superclasă ( metoda dansului ). Adică, o metodă declarată într-o superclasă poate fi implementată diferit în descendenții ei. În acest caz, avem de-a face cu suprascrierea metodei, care este exact ceea ce creează mai multe forme (comportamente). Acest lucru poate fi văzut rulând codul în metoda principală: Ieșire program: Sunt Fred. Am 18 ani. Dansez ca toți ceilalți. Eu sunt Jay. Am 19 ani. Eu breakdance! Eu sunt Marcia. Am 20 de ani. Dansez boogie-ul electric! Dacă nu suprascriem metoda din subclase, atunci nu vom obține un comportament diferit. De exemplu,ElectricBoogieDancer , apoi rezultatul programului va fi următorul: Eu sunt Fred. Am 18 ani. Dansez ca toți ceilalți. Eu sunt Jay. Am 19 ani. Dansez ca toți ceilalți. Eu sunt Marcia. Am 20 de ani. Dansez ca toți ceilalți. Și asta înseamnă că pur și simplu nu are sens să creezi clasele Breakdancer și ElectricBoogieDancer . Unde se manifestă în mod specific principiul polimorfismului? Unde este folosit un obiect în program fără cunoașterea tipului său specific? În exemplul nostru, se întâmplă când metoda dance() este apelată pe obiectul Dancer d . În Java, polimorfismul înseamnă că programul nu are nevoie să știe dacă obiectul este aBreakdancer sau ElectricBoogieDancer . Important este că este un descendent al clasei Dansatoare . Și dacă menționați descendenți, ar trebui să rețineți că moștenirea în Java nu este doar extinde , ci și implementează. Acum este momentul să menționăm că Java nu acceptă moștenirea multiplă - fiecare tip poate avea un părinte (superclasă) și un număr nelimitat de descendenți (subclase). În consecință, interfețele sunt folosite pentru a adăuga mai multe seturi de funcții la clase. În comparație cu subclasele (moștenire), interfețele sunt mai puțin cuplate cu clasa părinte. Sunt folosite foarte larg. În Java, o interfață este un tip de referință, astfel încât programul poate declara o variabilă de tipul interfeței. Acum este timpul să dau un exemplu. Creați o interfață:
public interface CanSwim {
    void swim();
}
Pentru claritate, vom lua diverse clase fără legătură și le vom face să implementeze interfața:
public class Human implements CanSwim {
    private String name;
    private int age;

    public Human(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public void swim() {
        System.out.println(toString()+" I swim with an inflated tube.");
    }

    @Override
    public String toString() {
        return "I'm " + name + ". I'm " + age + " years old.";
    }

}

public class Fish implements CanSwim {
    private String name;

    public Fish(String name) {
        this.name = name;
    }

    @Override
    public void swim() {
        System.out.println("I'm a fish. My name is " + name + ". I swim by moving my fins.");

    }

public class UBoat implements CanSwim {

    private int speed;

    public UBoat(int speed) {
        this.speed = speed;
    }

    @Override
    public void swim() {
        System.out.println("I'm a submarine that swims through the water by rotating screw propellers. My speed is " + speed + " knots.");
    }
}
metoda principala :
public class Main {

    public static void main(String[] args) {
        CanSwim human = new Human("John", 6);
        CanSwim fish = new Fish("Whale");
        CanSwim boat = new UBoat(25);

        List<swim> swimmers = Arrays.asList(human, fish, boat);
        for (Swim s : swimmers) {
            s.swim();
        }
    }
}
Rezultatele apelând la o metodă polimorfă definită într-o interfață ne arată diferențele de comportament ale tipurilor care implementează această interfață. În cazul nostru, acestea sunt diferitele șiruri afișate prin metoda înotului . După ce a studiat exemplul nostru, intervievatorul poate întreba de ce rulează acest cod în metoda principală
for (Swim s : swimmers) {
            s.swim();
}
determină apelarea metodelor de suprascrie definite în subclasele noastre? Cum este selectată implementarea dorită a metodei în timp ce programul rulează? Pentru a răspunde la aceste întrebări, trebuie să explicați legarea tardivă (dinamică). Legarea înseamnă stabilirea unei mapări între un apel de metodă și implementarea clasei sale specifice. În esență, codul determină care dintre cele trei metode definite în clase va fi executată. Java utilizează implicit legarea tardivă, adică legarea are loc în timpul execuției și nu în timpul compilării, așa cum este cazul legăturii timpurii. Aceasta înseamnă că atunci când compilatorul compilează acest cod
for (Swim s : swimmers) {
            s.swim();
}
nu știe ce clasă ( Uman , Pește sau Uboat ) are codul care va fi executat la înotse numeste metoda. Acest lucru este determinat doar atunci când programul este executat, datorită mecanismului de legare dinamică (verificarea tipului unui obiect în timpul execuției și selectarea implementării corecte pentru acest tip). Dacă sunteți întrebat cum este implementat acest lucru, puteți răspunde că la încărcarea și inițializarea obiectelor, JVM-ul construiește tabele în memorie și leagă variabilele cu valorile lor și obiectele cu metodele lor. Procedând astfel, dacă o clasă este moștenită sau implementează o interfață, prima ordine de lucru este de a verifica prezența metodelor suprascrise. Dacă există, ele sunt legate de acest tip. Dacă nu, căutarea unei metode de potrivire se mută la clasa care este cu un pas mai sus (părinte) și așa mai departe până la rădăcină într-o ierarhie pe mai multe niveluri. Când vine vorba de polimorfism în POO și implementarea sa în cod, observăm că este o bună practică să folosim clase și interfețe abstracte pentru a oferi definiții abstracte ale claselor de bază. Această practică decurge din principiul abstracției - identificarea comportamentului și proprietăților comune și plasarea lor într-o clasă abstractă, sau identificarea numai a comportamentului comun și punerea lui într-o interfață. Proiectarea și crearea unei ierarhii de obiecte bazate pe interfețe și moștenirea claselor sunt necesare pentru a implementa polimorfismul. În ceea ce privește polimorfismul și inovațiile în Java, observăm că începând cu Java 8, la crearea unor clase și interfețe abstracte este posibil să se folosească sau identificând doar comportamentul obișnuit și plasându-l într-o interfață. Proiectarea și crearea unei ierarhii de obiecte bazate pe interfețe și moștenirea claselor sunt necesare pentru a implementa polimorfismul. În ceea ce privește polimorfismul și inovațiile în Java, observăm că începând cu Java 8, la crearea unor clase și interfețe abstracte este posibil să se folosească sau identificând doar comportamentul obișnuit și plasându-l într-o interfață. Proiectarea și crearea unei ierarhii de obiecte bazate pe interfețe și moștenirea claselor sunt necesare pentru a implementa polimorfismul. În ceea ce privește polimorfismul și inovațiile în Java, observăm că începând cu Java 8, la crearea unor clase și interfețe abstracte este posibil să se foloseascăcuvânt cheie implicit pentru a scrie o implementare implicită pentru metodele abstracte din clasele de bază. De exemplu:
public interface CanSwim {
    default void swim() {
        System.out.println("I just swim");
    }
}
Uneori, intervievatorii întreabă despre cum trebuie declarate metodele din clasele de bază, astfel încât principiul polimorfismului să nu fie încălcat. Răspunsul este simplu: aceste metode nu trebuie să fie statice , private sau finale . Private face o metodă disponibilă numai în cadrul unei clase, astfel încât nu o veți putea înlocui într-o subclasă. Static asociază o metodă cu clasa mai degrabă decât cu orice obiect, astfel încât metoda superclasei va fi apelată întotdeauna. Și final face o metodă imuabilă și ascunsă de subclase.

Ce ne oferă polimorfismul?

Cel mai probabil veți fi întrebat despre modul în care ne avantajează polimorfismul. Puteți răspunde pe scurt la aceasta fără să vă blocați în detaliile păroase:
  1. Face posibilă înlocuirea implementărilor de clasă. Testarea este construită pe ea.
  2. Facilitează extensibilitatea, făcând mult mai ușoară crearea unei fundații pe care să se poată construi în viitor. Adăugarea de noi tipuri bazate pe cele existente este cea mai comună modalitate de a extinde funcționalitatea programelor OOP.
  3. Vă permite să combinați obiecte care au un tip sau un comportament comun într-o singură colecție sau matrice și să le manipulați uniform (ca în exemplele noastre, unde am forțat pe toți să danseze() sau să înoate() :)
  4. Flexibilitate în crearea de noi tipuri: puteți opta pentru implementarea unei metode de către părinte sau o puteți modifica într-o subclasă.

Câteva cuvinte de despărțire

Polimorfismul este un subiect foarte important și amplu. Este subiectul a aproape jumătate din acest articol despre POO în Java și formează o bună parte din fundația limbajului. Nu vei putea evita definirea acestui principiu într-un interviu. Dacă nu o știi sau nu o înțelegi, probabil că interviul se va termina. Așa că nu fi leneș – evaluează-ți cunoștințele înainte de interviu și reîmprospătează-le dacă este necesar.

Mai multe lecturi:

Comentarii
  • Popular
  • Nou
  • Vechi
Trebuie să fii conectat pentru a lăsa un comentariu
Această pagină nu are încă niciun comentariu