CodeGym/Java Blog/Willekeurig/Java-polymorfisme
John Squirrels
Niveau 41
San Francisco

Java-polymorfisme

Gepubliceerd in de groep Willekeurig
OOP-gerelateerde vragen vormen een integraal onderdeel van het technische sollicitatiegesprek voor een Java-ontwikkelaarsfunctie bij een IT-bedrijf. In dit artikel zullen we het hebben over één principe van OOP - polymorfisme. We zullen ons concentreren op de aspecten die vaak worden gevraagd tijdens interviews, en ook enkele voorbeelden geven voor de duidelijkheid.

Wat is polymorfisme op Java?

Polymorfisme is het vermogen van een programma om objecten met dezelfde interface op dezelfde manier te behandelen, zonder informatie over het specifieke type van het object. Als u een vraag beantwoordt over wat polymorfisme is, wordt u hoogstwaarschijnlijk gevraagd uit te leggen wat u bedoelde. Leg het allemaal nog een keer uit voor de interviewer, zonder een heleboel extra vragen op te roepen. Interviewtijd: polymorfisme op Java - 1Je kunt beginnen met het feit dat de OOP-benadering het bouwen van een Java-programma inhoudt op basis van de interactie tussen objecten, die zijn gebaseerd op klassen. Klassen zijn eerder geschreven blauwdrukken (sjablonen) die worden gebruikt om objecten in het programma te maken. Bovendien heeft een klasse altijd een specifiek type, dat, met een goede programmeerstijl, een naam heeft die het doel ervan suggereert. Verder kan worden opgemerkt dat aangezien Java sterk getypeerd is, de programmacode altijd een objecttype moet specificeren wanneer variabelen worden gedeclareerd. Voeg daarbij het feit dat strikt typen de veiligheid en betrouwbaarheid van de code verbetert, en het mogelijk maakt, zelfs bij het compileren, om fouten als gevolg van incompatibiliteitstypes te voorkomen (bijvoorbeeld proberen een string te delen door een getal). Natuurlijk moet de compiler "weten" het gedeclareerde type - het kan een klasse van de JDK zijn of een klasse die we zelf hebben gemaakt. Wijs de interviewer erop dat onze code niet alleen de objecten van het in de aangifte aangegeven type kan gebruiken, maar ook de afstammelingen ervan.Dit is een belangrijk punt: we kunnen met veel verschillende typen als één type werken (mits deze typen zijn afgeleid van een basistype). Dit betekent ook dat als we een variabele declareren waarvan het type een superklasse is, we een instantie van een van zijn afstammelingen aan die variabele kunnen toewijzen. De interviewer zal het leuk vinden als je een voorbeeld geeft. Selecteer een klasse die kan worden gedeeld door (een basisklasse voor) meerdere klassen en laat een paar van hen deze erven. Basisklasse:
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.";
    }
}
Overschrijf in de subklassen de methode van de basisklasse:
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!");
    }
}
Een voorbeeld van polymorfisme en hoe deze objecten in een programma kunnen worden gebruikt:
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
        }
    }
}
Laat in de hoofdmethode zien dat de lijnen
Dancer breakdancer = new Breakdancer("Jay", 19);
Dancer electricBoogieDancer = new ElectricBoogieDancer("Marcia", 20);
declareer een variabele van een superklasse en wijs er een object aan toe dat een instantie is van een van zijn afstammelingen. U zult hoogstwaarschijnlijk worden gevraagd waarom de compiler niet flipt bij de inconsistentie van de typen die aan de linker- en rechterkant van de toewijzingsoperator worden gedeclareerd - Java is tenslotte sterk getypeerd. Leg uit dat hier een verbredende typeconversie aan het werk is — een verwijzing naar een object wordt behandeld als een verwijzing naar zijn basisklasse. Bovendien voert de compiler, nadat hij zo'n constructie in de code heeft aangetroffen, de conversie automatisch en impliciet uit. De voorbeeldcode laat zien dat het type dat aan de linkerkant van de toewijzingsoperator ( Dancer ) wordt gedeclareerd, meerdere vormen (types) heeft, die aan de rechterkant worden gedeclareerd ( Breakdancer , ElectricBoogieDancer). Elke vorm kan zijn eigen unieke gedrag hebben met betrekking tot de algemene functionaliteit die is gedefinieerd in de superklasse (de dansmethode ). Dat wil zeggen, een methode die in een superklasse is gedeclareerd, kan anders worden geïmplementeerd in zijn afstammelingen. In dit geval hebben we te maken met methode-overheersing, en dat is precies wat meerdere vormen (gedragingen) creëert. Dit kan worden gezien door de code uit te voeren in de hoofdmethode: Programma-uitvoer: ik ben Fred. Ik ben 18 jaar oud. Ik dans zoals iedereen. Ik ben Jay. Ik ben 19 jaar oud. Ik breakdance! Ik ben Marcia. Ik ben 20 jaar oud. Ik dans de elektrische boogie! Als we de methode in de subklassen niet overschrijven, krijgen we geen ander gedrag. Bijvoorbeeld,ElectricBoogieDancer les geeft, dan is de uitvoer van het programma dit: Ik ben Fred. Ik ben 18 jaar oud. Ik dans zoals iedereen. Ik ben Jay. Ik ben 19 jaar oud. Ik dans zoals iedereen. Ik ben Marcia. Ik ben 20 jaar oud. Ik dans zoals iedereen. En dit betekent dat het simpelweg geen zin heeft om de lessen Breakdancer en ElectricBoogieDancer te maken . Waar komt het principe van polymorfisme specifiek tot uiting? Waar wordt een object in het programma gebruikt zonder kennis van het specifieke type? In ons voorbeeld gebeurt dit wanneer de methode dance() wordt aangeroepen op het object Dancer d . In Java betekent polymorfisme dat het programma niet hoeft te weten of het object eenBreakdancer of ElectricBoogieDancer . Het belangrijkste is dat het een afstammeling is van de Dancer- klasse. En als u afstammelingen noemt, moet u er rekening mee houden dat overerving in Java niet alleen verlengt , maar ook implementeert. Dit is het moment om te vermelden dat Java geen meervoudige overerving ondersteunt - elk type kan één ouder (superklasse) en een onbeperkt aantal afstammelingen (subklassen) hebben. Dienovereenkomstig worden interfaces gebruikt om meerdere sets functies aan klassen toe te voegen. Vergeleken met subklassen (overerving) zijn interfaces minder gekoppeld aan de bovenliggende klasse. Ze worden heel veel gebruikt. In Java is een interface een referentietype, dus het programma kan een variabele van het interfacetype declareren. Nu is het tijd om een ​​voorbeeld te geven. Maak een interface:
public interface CanSwim {
    void swim();
}
Voor de duidelijkheid nemen we verschillende niet-gerelateerde klassen en laten ze de interface implementeren:
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.");
    }
}
belangrijkste methode:
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();
        }
    }
}
De resultaten die een polymorfe methode aanroepen die in een interface is gedefinieerd, laten ons de verschillen zien in het gedrag van de typen die deze interface implementeren. In ons geval zijn dit de verschillende tekenreeksen die worden weergegeven door de zwemmethode . Na bestudering van ons voorbeeld kan de interviewer vragen waarom deze code in de hoofdmethode wordt uitgevoerd
for (Swim s : swimmers) {
            s.swim();
}
zorgt ervoor dat de overheersende methoden die in onze subklassen zijn gedefinieerd, worden aangeroepen? Hoe wordt de gewenste implementatie van de methode geselecteerd terwijl het programma draait? Om deze vragen te beantwoorden, moet u late (dynamische) binding uitleggen. Binding betekent het tot stand brengen van een afbeelding tussen een methodeaanroep en de specifieke klasse-implementatie ervan. In wezen bepaalt de code welke van de drie methoden die in de klassen zijn gedefinieerd, zal worden uitgevoerd. Java gebruikt standaard late binding, dwz binding gebeurt tijdens runtime en niet tijdens het compileren, zoals het geval is bij vroege binding. Dit betekent dat wanneer de compiler deze code compileert
for (Swim s : swimmers) {
            s.swim();
}
het weet niet welke klasse ( Human , Fish of Uboat ) de code heeft die zal worden uitgevoerd wanneer het zwemmenmethode wordt genoemd. Dit wordt alleen bepaald wanneer het programma wordt uitgevoerd, dankzij het dynamische bindingsmechanisme (het controleren van het objecttype tijdens runtime en het selecteren van de juiste implementatie voor dit type). Als u wordt gevraagd hoe dit is geïmplementeerd, kunt u antwoorden dat de JVM bij het laden en initialiseren van objecten tabellen in het geheugen bouwt en variabelen koppelt aan hun waarden en objecten aan hun methoden. Daarbij, als een klasse wordt geërfd of een interface implementeert, is de eerste orde van zaken het controleren op de aanwezigheid van onderdrukte methoden. Als die er zijn, zijn ze gebonden aan dit type. Als dit niet het geval is, gaat het zoeken naar een overeenkomende methode naar de klasse die een stap hoger is (de ouder) en zo verder tot aan de hoofdmap in een hiërarchie met meerdere niveaus. Als het gaat om polymorfisme in OOP en de implementatie ervan in code, we merken op dat het een goede gewoonte is om abstracte klassen en interfaces te gebruiken om abstracte definities van basisklassen te geven. Deze praktijk volgt uit het principe van abstractie: gemeenschappelijk gedrag en eigenschappen identificeren en deze in een abstracte klasse plaatsen, of alleen gemeenschappelijk gedrag identificeren en in een interface plaatsen. Het ontwerpen en maken van een objecthiërarchie op basis van interfaces en klassenovererving is vereist om polymorfisme te implementeren. Met betrekking tot polymorfisme en innovaties in Java merken we op dat het vanaf Java 8 mogelijk is om bij het maken van abstracte klassen en interfaces de of alleen gemeenschappelijk gedrag identificeren en in een interface plaatsen. Het ontwerpen en maken van een objecthiërarchie op basis van interfaces en klassenovererving is vereist om polymorfisme te implementeren. Met betrekking tot polymorfisme en innovaties in Java merken we op dat het vanaf Java 8 mogelijk is om bij het maken van abstracte klassen en interfaces de of alleen gemeenschappelijk gedrag identificeren en in een interface plaatsen. Het ontwerpen en maken van een objecthiërarchie op basis van interfaces en klassenovererving is vereist om polymorfisme te implementeren. Met betrekking tot polymorfisme en innovaties in Java merken we op dat het vanaf Java 8 mogelijk is om bij het maken van abstracte klassen en interfaces dedefault trefwoord om een ​​standaardimplementatie te schrijven voor abstracte methoden in basisklassen. Bijvoorbeeld:
public interface CanSwim {
    default void swim() {
        System.out.println("I just swim");
    }
}
Soms vragen interviewers hoe methoden in basisklassen moeten worden gedeclareerd, zodat het principe van polymorfisme niet wordt geschonden. Het antwoord is simpel: deze methoden mogen niet statisch , privé of definitief zijn . Private maakt een methode alleen beschikbaar binnen een klasse, dus u kunt deze niet overschrijven in een subklasse. Static associeert een methode met de klasse in plaats van met een object, dus de methode van de superklasse wordt altijd aangeroepen. En final maakt een methode onveranderlijk en verborgen voor subklassen.

Wat geeft polymorfisme ons?

U zult hoogstwaarschijnlijk ook worden gevraagd hoe polymorfisme ons ten goede komt. Je kunt dit kort beantwoorden zonder te verzanden in de harige details:
  1. Het maakt het mogelijk om klasse-implementaties te vervangen. Testen is erop gebouwd.
  2. Het vergemakkelijkt de uitbreidbaarheid, waardoor het veel gemakkelijker wordt om een ​​fundament te leggen waarop in de toekomst kan worden voortgebouwd. Het toevoegen van nieuwe typen op basis van bestaande typen is de meest gebruikelijke manier om de functionaliteit van OOP-programma's uit te breiden.
  3. Hiermee kun je objecten combineren die een gemeenschappelijk type of gedrag delen in één verzameling of array en ze uniform behandelen (zoals in onze voorbeelden, waar we iedereen dwongen om te dansen() of zwemmen() :)
  4. Flexibiliteit bij het maken van nieuwe typen: u kunt kiezen voor de implementatie van een methode door de ouder of deze overschrijven in een subklasse.

Enkele afscheidswoorden

Polymorfisme is een zeer belangrijk en uitgebreid onderwerp. Het is het onderwerp van bijna de helft van dit artikel over OOP in Java en vormt een groot deel van de basis van de taal. In een interview ontkom je er niet aan om dit principe te definiëren. Als je het niet weet of niet begrijpt, komt er waarschijnlijk een einde aan het interview. Wees dus geen slapper - evalueer uw kennis vóór het interview en fris deze indien nodig op.
Opmerkingen
  • Populair
  • Nieuw
  • Oud
Je moet ingelogd zijn om opmerkingen te kunnen maken
Deze pagina heeft nog geen opmerkingen