Vraag Java `final` methode: wat belooft het?


In een Java-klasse kan een methode worden gedefinieerd om te zijn final, om aan te geven dat deze methode niet mag worden opgeheven:

public class Thingy {
    public Thingy() { ... }
    public int operationA() {...}
    /** this method does @return That and is final. */
    public final int getThat() { ...}
}

Dat is duidelijk, en het kan van enig nut zijn om te beschermen tegen onbedoeld overriding, of misschien prestaties - maar dat is niet mijn vraag.

Mijn vraag is: vanuit een OOP oogpunt begreep ik dat, door een methode te definiëren final de klassenontwerper beloften deze methode zal altijd werken zoals beschreven of geïmpliceerd. Maar vaak kan dit buiten de invloed van de auteur van de klasse liggen, als wat de methode doet ingewikkelder is dan alleen een eigendom.

De syntactische beperking is mij duidelijk, maar wat is de implicatie in de OOP-zin? is final correct gebruikt in deze zin door de meeste klasseschrijvers?

Wat voor soort "contract" doet een final methode belofte?


111
2018-04-05 05:37


oorsprong


antwoorden:


Zoals genoemd, final wordt gebruikt met een Java-methode om aan te geven dat de methode niet kan worden overschreven (voor objectbereik) of verborgen (voor statische). Hierdoor kan de oorspronkelijke ontwikkelaar functionaliteit maken die niet kan worden gewijzigd door subklassen, en dat is de garantie die deze biedt.

Dit betekent dat als de methode afhankelijk is van andere aanpasbare componenten zoals niet-openbare velden / methoden, de functionaliteit van de laatste methode mogelijk nog steeds kan worden aangepast. Dit is echter goed, omdat het (met polymorfisme) gedeeltelijke aanpassingen mogelijk maakt.

Er zijn een aantal redenen om te voorkomen dat iets aanpasbaar is, zoals:

  • Prestatie - Sommige compilers kunnen de werking analyseren en optimaliseren, met name die zonder bijwerkingen.

  • Verkrijg ingekapselde gegevens - kijk naar onveranderlijke objecten waar hun attributen zijn ingesteld op de constructietijd en nooit mogen worden gewijzigd. Of een berekende waarde afgeleid van die attributen. Een goed voorbeeld is de Java String klasse.

  • Betrouwbaarheid en contract - Objecten zijn samengesteld uit primitieven (int, char, double, etc.) en / of andere objecten. Niet alle bewerkingen die van toepassing zijn op die componenten moeten van toepassing zijn of zelfs logisch als ze in het grotere object worden gebruikt. Methoden met de final modifier kan worden gebruikt om dat te garanderen. De Counter-klasse is een goed voorbeeld.


public class Counter {
    private int counter = 0;

    public final int count() {
        return counter++;
    }

    public final int reset() {
        return (counter = 0);
    }
}

Als het public final int count() methode is dat niet final, we kunnen zoiets als dit doen:

Counter c = new Counter() {   
    public int count() {
        super.count();   
        return super.count();   
    } 
}

c.count(); // now count 2

Of iets zoals dit:

Counter c = new Counter() {
    public int count() {
        int lastCount = 0;
        for (int i = super.count(); --i >= 0; ) {
            lastCount = super.count();
        }

        return lastCount;
    }
}

c.count(); // Now double count

127
2018-04-05 06:10



Wat voor soort "contract" is een belofte voor de definitieve methode?

Bekijk het de andere kant op, elke niet-definitieve methode maakt het impliciete garantie dat je het kunt overrulen met je eigen implementatie en de klas werkt nog steeds zoals verwacht. Wanneer u niet kunt garanderen dat uw klasse het overschrijven van een methode ondersteunt, moet u dit definitief maken.


23
2018-04-05 06:00



Allereerst kun je niet-abstracte klassen markeren final evenals velden en methoden. Op deze manier kan de hele klasse niet worden geclasseerd. Dus gedrag van klasse zal worden opgelost.

Ik ben het ermee eens dat markeermethoden final niet garanderen dat hun gedrag hetzelfde zal zijn in subklassen als deze methoden niet-definitieve methoden aanroepen. Als gedrag inderdaad moet worden opgelost, moet dit worden bereikt door conventie en zorgvuldig ontwerp. En vergeet dit niet op te merken in javadoc! (Java documentation)

Last but not least, final trefwoord heeft een zeer belangrijke rol in het JJMM (Java Memory Model). Het wordt door JMM gegarandeerd om zichtbaarheid te bereiken final velden waarvoor u geen goede synchronisatie nodig hebt. bijv .:

class A implements Runnable {
  final String caption = "Some caption";                           

  void run() {
    // no need to synchronize here to see proper value of final field..
    System.out.println(caption);
  }
}  

8
2018-04-05 05:46



Ik ben er niet zeker van dat je beweringen kunt doen over het gebruik van 'definitief' en hoe dit het algemene ontwerpcontract van de software beïnvloedt. U bent er zeker van dat geen ontwikkelaar deze methode kan negeren en zijn contract op die manier nietig kan verklaren. Maar aan de andere kant kan de laatste methode gebaseerd zijn op klasse- of instantievariabelen waarvan de waarden worden bepaald door subklassen, en kunnen ze andere klassenmethoden aanroepen die zijn overschreven. De uiteindelijke garantie is hooguit een zeer zwakke garantie.


0
2018-04-05 05:44



Nee, het is niet buiten de invloed van de auteur van de klasse. Je kunt het niet overschrijven in je afgeleide klasse, daarom zal het doen wat de auteur van de basisklasse bedoelde.

http://download.oracle.com/javase/tutorial/java/IandI/final.html

Vermeldenswaard is het deel waar het suggereert dat methoden die van constructeurs worden genoemd, zouden moeten zijn final.


0
2018-04-05 05:43