Deel 1 : Basisprincipes van objectoriëntatie HFST 1 - een instantie = een bepaald object namen van klassen hoofdletter namen van objecten kleine letter parameters = de extra waarden die bij sommige methodes ingevoerd moeten worden een type geeft aan welke soort gegevens geschikt zijn als paramters HFST 2 - - - - - - public class Naamvandeklasse { … } de inhoud van een klasse samengevat: 1) de velden bevatten gegevens die het object moet gebruiken 2) met de constructors kan een object op de juiste manier worden ingesteld op het moment dat het wordt aangemaakt 3) met de methodes wordt het gedrag van de objecten geïmplimenteerd een formele parameter is alleen beschikbaar voor een object binnen de body van een constructor of methode die deze declareert. Het bereik van een parameter is beperkt tot de body van de constructor of methode waarin deze wordt gedeclareerd. Het bereik van een veld daarentegen is de hele klassedefinitie De levensduur van een parameter is beperkt tot 1 aanroep van een constructor of methode De levensduur van een veld daarentegen is gelijk aan de levensduur van het object waartoe het behoort het is een absolute regel in Java dat een constructor geen returntype mag hebben accessor = een methode die informatie over de toestand van een object teruggeeft mutator = een methode die de toestand van een object verandert conditioneel statement : if (voer een test uit die alleen waar of niet waar uitkomt) { voer statements uit als resultaat waar was } else { voer deze statements uit als resultaat niet waar was } net als formele parameters hebben lokale variabelen een bereik dat beperkt is tot de statements van de methode waartoe ze behoren kenmerken van variabelen: (velden, formele en lokale) 1) alle 3 variabelen kunnen een waarde opslaan die overeenkomt met het voor hen gedefinieerde type 2) velden worden buiten constructors en methodes gedefiniëerd 3) velden worden gebruikt om gegevens op te slaan die gedurende de hele levensduur van een object bestaan. Op die manier beschrijven ze de huidige toestand van een object. 4) Velden werken klassebreed; ze zijn benaderbaar vanuit de hele klasse en kunnen dus worden gebruikt binnen alle constructors en methodes van de klasse waarin ze gedefinieerd zijn. 5) Zolang ze als private gedefinieerd zijn, kunnen velden niet van buiten de klasse waarin ze gedefinieerd zijn benaderd worden. 6) Formele parameters en lokale variabelen bestaan alleen tijdens de periode dat een constructor of methode wordt uitgevoerd. 7) Formele parameters worden gedefinieerd in de header van een constructor of methode. Ze krijgen hun waarde van buitenaf en worden geïnitialiseerd door de actuele parameterwaarden die een onderdeel zijn van de constructor of methodeaanroep. 8) Formele parameters hebben een bereik dat beperkt is tot het bereik van de constructor of de methode waarin ze gedefinieerd wordt. 9) Lokale variabelen worden gedefinieerd binnen de body van een constructor of methode. Ze kunnen alleen binnen de body van de constructor of methode gebruikt en geïnitialiseerd worden. Lokale variabelen moeten geïnitialiseerd worden voordat ze in een expressie worden gebruikt; ze hebben dus geen standaardwaarden. 10) Lokale variabelen hebben een bereik dat beperkt is tot het blok waarin ze gedefinieerd zijn. Ze kunnen niet van buiten dat blok benaderd worden. HFST 3 - - - Java kent 2 sterk verschillende types: a) primitieve types: worden vooraf gedefinieerd in Java (opgeslaan in een variabele) b) objecttypes: worden gedefinieerd door klassen (opgeslaan in een verwijzing naar een object) logische operatoren: = gebruiken de boolean waarden als argument en produceren een nieuwe boolean waarde als resultaat. en && of || niet ! integer convergeren in een String: “” + getal de syntax van een externe methode-aanroep: object.methodenaam ( parameters ); de syntax van een interne methode-aanroep: methodenaam ( parameter ); HFST 4 - gebruiken van een Arraylist: import java.util.ArrayList { private ArrayList … ; … { a = new ArrayList () ; } … { - - - - - - - a.add( a ); } // we willen de grootte weten { return a.size (); } //we willen er eentje zien (welke) { System.out.println ( a.get( welke ) ); } 3 belangrijke kenmerken van een ArrayList 1) de klasse kan de interne capaciteit op verzoek aanpassen: wanneer er items aan toegevoegd worden maakt de klasse er gewoon ruimte voor 2) de klasse houdt een eigen teller van het huidige aantal opgeslagen items. De methode size () retourneert het aantal opgeslagen objecten. 3) De klasse houdt ook de volgorde van de opgeslagen items bij. Je kunt ze later in dezelfde volgorde ophalen. om iets te verwijderen uit een ArrayList a.remove ( index ); de indexnummers van de overgebleven items verschuiven met 1 eenheid while – lus while ( loop conditie ) { loop body; } een Iterator gebruiken import java.util.Iterator; … // toont alle objecten uit de ArrayList { Iterator = a.iterator (); while (it.hasNext () ) { System.out.println ( it.next () ); } } het begrip null is een speciale waarde in Java met de betekenis ‘geen object’ Casten: Een cast bestaat uit de naam van een type die tussen een paar haakjes geschreven wordt. Casten wordt veel gebruikt wanneer objecten uit een collectie worden opgehaald. Casten is noodzakelijk omdat het mogelijk is om elk type in een collectie op te slaan. We moeten de compiler dus duidelijk maken welk type object we ophalen. collectie met een vaste omvang : Array hoewel de onveranderlijke omvang van arrays in veel situaties een belangrijk nadeel is, hebben ze tenminste 2 voordelen t.o.v. collectieklassen met een veranderlijke omvang: 1) het benaderen van items in een array is vaak efficiënter dan het benaderen van items in een vergelijkbare collectie met veranderlijke omvang 2) arrays kunnen objecten of waarden van het primitieve type bevatten. Collecties met veranderlijke omvang kunnen alleen objecten bevatten gebruik van Arrays … - private int [] a; … { a = new int [ getal ]; } // de lengte bepalen { return a.length; } for – lus met name handig als i. we enkele statements een bepaald aanteel keer willen uitvoeren ii. we een variabele binnen de lus nodig hebben waarvan de waarde steeds een regelmatig aantal verandert (meestal + 1) for ( initialisering; conditie; actie na de body) { te herhalen statements; } HFST 5 - - - - - String: trim () doet spaties aan begin en einde weg length () geeft lengte terug toLowerCase () zet alles in kleine letters om equals () vergelijkt startsWith () begint met… de klasse Random () import java.util.Random ; Random rg ; rg = new Random ; int getal = rg.nextInt (eventueel een maximum); public vs. private i. public geeft aan dat een constructie van een klasse, veld of methode voor iedereen zichtbaar is (= een onderdeel van de interface is) ii. private geeft aan dat het niet zichtbaar is van buitenaf (=een onderdeel van de implementatie is) het begrip static i. met het begrip static worden klassevariabelen in Java gedefinieerd. Klassevariabelen zijn velden die opgeslagen zijn in een klasse zelf en niet in een object ii. klassevariabelen worden vaak gebruikt als een waarde altijd voor alle instanties van een klasse gelijk moet zijn constanten i. het begrip static word vaak gebruikt voor het definiëren van constanten. In Java worden deze gedefinieerd met het begrip final: private final int a = …; ii. als een waarde niet mag veranderen is het een goed ideee om deze final te declareren. Daardoor wordt het onmogelijk om de waarde achteraf te veranderen. Elke poging om een veld met een constante te veranderen zal resulteren in een foutmelding bij het compileren. - in de praktijk komt het vaak voor dat constanten in alle instanties van een klasse gelden. In dat geval declareren we klasseconstanten als volgt private static final int a = …; HFST 6 - elke afzonderlijke methode kan, zodra die geschreven en gecompileerd is getest worden belangrijk bij het testen is om ervoor te zorgen dat de begrenzingen worden gecontroleerd bij een regressietest wordt een test die eerder met succes werd uitgevoerd, opnieuw uitgevoerd om er zeker van te zijn dat de nieuwe versie ook met succes kan werken. HFST 7 afhankelijkheid = de onderlinge verbondenheid van klassen (we streven naar een zwakke afhankelijkheid). - Cohesie = het aantal en de diversiteit van de taken waarvoor 1 afgebakend stuk van een toepassing verantwoordelijk is - Dupliceren van code is een kenmerk van een slecht ontwerp - Inkapselingsregel (de informatie over de implementatie verbergen) stelt dat alleen informatie over wat een klassse kan doen, zichtbaar moet zijn en niet hoe ze dit doet. - Ontwerpen op basis van verantwoordelijkheid: elke klasse moet zorgen voor de verwerking van de eigen gegevens. - We proberen een klasseontwerp te maken dat later gemakkelijk gewijzigd kan worden omdat de effecten van de wijziging goed te traceren zijn. - Slecht: impliciete afhankelijkheid is een situatie waarbij een klasse afhankelijk is van interne informatie van een andere klasse, maar waarbij deze afhankelijkheid niet meteen duidelijk is. - Waneer we het hebben over cohesie van methodes proberen we de ideale situatie te bereiken dat een methode verantwoordelijk is voor exact 1 goed omschreven taak. - Voordelen van cohesie: a) betere leesbaarheid b) mogelijkheid tot hergebruik - herschikken is de activiteit waarmee de structuur van bestaande klassen en methodes worden aangepast om ze te kunnen gebruiken wanneer de toepassing gewijzigd of uitgebreid worden. 1) eerst wordt de toepassing herschikt zodat deze dezelfde functionaliteit heeft als de oorspronkelijke versie. Zodra we deze stap voltooid hebben, moeten we de regressietest uitvoeren om te kijken of we geen onbedoelde fouten geïntroduceerd hebben. 2) Daarna (alleen als zeker is dat de functionaliteit van de eerste versie = functionaliteit van de tweede versie) verbeteren we het programma. Daarna testen we opnieuw. een methode is te lang als deze meer dan 1 logische taak uitvoert een klasse is te complex als deze meer dan 1 logische entiteit vormt - TOEPASSINGEN ZONDER BLUEJ - klasse methodes ( static methodes ) kunnen aangeroepen worden zonder instantie, alleen de klasse volstaat - - - een klassemethode word gedefinieerd door het begrip static voor de typenaam in het argument van de methode te plaatesen bv. public static int aantaldagen ( ) { … } zo’n methode kan worden aangeroepen door de naam van de klasse waarin deze gedefinieerd is te specifiëren voor het punt bv. int days = Calendar.aantaldagen () ; de methode main in eerste instantie hebben we alleen klassen, dus de eerste methode die we toe kunnen passen moet een klassemethode zij: je specifiëert de klasse die gestart moet worden en Java zal dan een methode in die klasse aanroepen met de naam main beperkingen van klassemethodes: 1) een klassemethode mag geen instantievelden benaderen die gedefinieerd zijn in de klasse 2) een klassemethode mag geen instantiemethode van de klasse aanroepen bv. public static void main ( String [] args ) { Game game = new Game (); Game.start (); } Deel 2 : De structuur van toepassingen HFST 8 - - - - overerving is een mechanisme waarmee we ons probleem van de gedupliceerde code kunnen oplossen. Overerving is soms ook een ‘is een’-relatie genoemd, een subklasse is immers een specialisatie van de superklasse. Het is mogelijk om meer dan 2 subklassen te laten erven van dezelfde superklasse en een subklasse kan op zijn beurt weer een superklasse zijn voor andere subklassen. De klassen vormen dan een overervingshiërarchie. Overerving in Java public class Subklasse extends Superklasse het begrip super is een aanroep van de constructor van de superklasse in Java moet een constructor van een subklasse altijd de constructor van de bijbehorende superklasse als eerste statement aanroep als je deze aanroep van de constructor van de superklasse niet expliciet schrijft, zal de Java-compiler zo’n aanroep automatisch proberen in te voegen om er voor te zorgen dat de velden van de superklasse correct geïnitialiseerd worden. Het automatisch invoegen van deze aanroep zal alleen lukken als de superklasse een constructor zonder parameters heeft. voordelen van overerving 1) voorkomen van gedupliceerde code 2) hergebruik van code 3) gemakkelijk onderhoud 4) uitbreidbaarheid substitutie we kunnen een subklasse object gebruiken waar een superklasse object verwacht worden, omdat het subklasse object een speciale uitvoering van de superklasse is. Maar omgekeerd is dit niet toegestaan. - - Hoewel we een expliciete superklasse kunnen declareren, even alle klassen waarvoor geen superklasse gedeclareerd is, altijd impliciet van een klasse met de naam Object Reden voor een superklasse voor alle objecten: 1) de klasse Object kan methodes definiëren die dan automatisch beschikbaar zijn voor elk bestaand object 2) we kunnen polymorfe variabelen declareren van het type object die een willekeurig object kunnen bevatten Java-collecties polymorfe collecties (ze kunnen gelijktijdig verschillende soorten constructies bevatten) We kennen in Java primitieve types (int, boolean, char …) die geen objecttypes zijn. De oplossing zijn wrapperklassen: elk primitieve type in Java heeft een bijbehorende wrapperklasse die hetzelfde type representeert, maar een echt objecttype is Bv. voor int Integer HFST 9 - - - een subklasse erft de informatie van de superklasse, maar deze heeft geen kennis van de subklasse we noemen het gedeclareerd type van de variabele het statische type, omdat het gedeclareerd is in de broncode we noemen het type van het object dat opgeslagen is in een variabele het dynamische type, omdat het afhankelijk is van de toekenningen tijdens de uitvoering van het programma in tegenstelling tot de super-aanroepen in constructors moet de naam van de methode van de superklasse expliciet geschreven worden super.methodenaam ( eventule parameter ); in tegenstelling tot de super-aanroepen in de constructor moet de aanroep niet het eerste statement zijn in tegenstelling tot de super-aanroepen in de constructor wordt een super-aanroep in methodes niet automatisch gegenereerd en zijn deze optioneel de methode toString () wordt gebruikt om van een object een stringrepresentatie te maken. HFST 10 - - - - je herkent een abstracte methode aan 1) de definitie van de methode wordt voorafgegaan door abstract 2) de definitie van de methode heeft geen body (de header wordt afgesloten met een puntkomma) van abstracte klassen kunnen geen instanties worden gemaakt alleen abstracte klassen kunnen abstracte methodes hebben; daardoor kunnen alle methodes in concrete klassen altijd uitgevoerd worden. Als we een abstracte methode in een concrete klasse zouden toestaan, zouden we een instantie van een klasse kunnen maken zonder een implimentatie voor een methode abstracte klassen met abstracte methodes zorgen ervoor dat subklassen de abstracte methodes overschrijven en implimenteren. Als een subklasse geen implimentatie voor een geërfde abstracte methode heeft, is deze zelf abstract en kunnen er geen instanties gemaakt worden. Een subklasse is alleen concreet als deze implimentatiees bevat voor alle geërfde abstracte methodes doel van abstracte methodes = hoewel ze geen implimentatie leveren, garanderen ze toch dat alle subklassen een implimentatie van deze methode hebben - - - - meervoudige overerving bestaat in gevallen waarbij 1 klasse van meer dan 1 superklasse erft. De subklasse heeft dan alle kenmerken van de superklassen plus de kenmerken die gedefinieerd zijn in de subklasse zelf in Java is meervoudige overerving niet toegestaan, maar men heeft wel interfaces, waarmee een zekere vorm van meervoudige overerving mogelijk is: de methodes van interfaces hebben geen body ( ze lijken dus erg op abstracte klassen waarin alle methodes abstract zijn) public interface Naam { … } alle methodes in een interface zijn abstract;; de methodes mogen geen body hebben, het begrip abstract is NIET nodig de zichtbaarheid moet niet gedeclareerd worden (= het begrip public moet niet voor elke methode gedeclareerd worden) een interface mag alleen velden hebben als waarde van een constante; de begrippen public, static en final mogen weggelaten worden. een klasse kan van een interface op dezelfde manier erven als van een andere klasse, Java gebruikt het begrip implements voor overervende intercaces als een klasse zowel een klasse uibreidt als een interface implimenteert, dan moet het begrip extends als eerste in de header worden ingeschreven het aantal interfaces dat geïmplimenteerd kan worden, is onbeperkt public class Naam implements nr1, nr2 { … } wanneer de klasse bedoeld is om implimentaties voor een paar methodes te bevatten, moeten we een abstracte klasse gebruiken; als we kunnen kiezen, genieten interfaces onze voorkeur als we een type als een abstracte klasse definiëren, kunnen subklassen geen andere klasse uitbreiden. Omdat interfaces meervoudige overerving mogelijk maken, kunnen we deze daar dus wel voor gebruiken HFST 11 - - - - een exception opgooien: throw new Exeption type ( “Uitleg” ); alle subklassen van de Java-standaardklasse RunTimeExeption zijn ongecontroleerde exeptions; alle andere subklassen van Exeption zijn gecontroleerde exeptions Gecontroleerd = waar je een fout kan verwachten Ongecontroleerd = normaal geen fouten ( programmeerfouten) Gebruik ongecontroleerde exeptions voor situaties die leiden tot een programmeerfout (meestal omdat te verwachten is dat een logische fout het programma zal doen stoppen) Een gecontroleerde exeptions gebruik je dus best voor situaties waar er een probleem ontstaat dat mogelijk door de gebruiken kan worden opgelost Ongecontroleerde exeptions gebruik je voor situaties die redelijkerwijs hadden voorkomen kunnen worden. Het is dan ook duidelijk dat gecontroleerde exeptions gebruikt moeten worden in situaties waarover de programmeur geen macht heeft Wanneer een exeption wordt opgegooid, wordt de uitvoering van de opgooiende methode onmiddellijk stopgezet een specifiek gevolg daarvan is dat een methode met een returntype anders dan void verplicht is om returnstatements uit te voeren op een pad dat een exeption opgooit als de exeption niet opgevangen wordt zal het programma beëindigd worden met een foutmelding Voor het opgooien van een ongecontroleerde exeption gebruik je een throwstatement Bv. throw new IllegalArgumentexeption (“Foute”); - - - - - - - opgegooid door een constructor of methode om aan te geven dat de waarde van een of meerdere argumenten ongeldig zijn meestal is er een exeption-handler in de vorm van een try-blok: try { // benadert 1 of meerdere statements } catch ( Exeptiontype e ) { // meldt een exeption en lost het op } catch ( Exeptiontype e) { // tweede probleemsoort } het doorgeven van exeptions wordt veel gebruikt wanneer de aanroepende methode zelf geen oplossing kan bieden voor de exeption; naar methodes die dit wel kunnen op een hiërarchisch hoger niveau de try-blok kan nog een derde component bevatten: de finally-clausule ( gebruikt voor statements die altijd, ongeacht de aanwezigheid van een exeption, uitgevoerd worden na een bewaakt statement) een finally-clausule wordt ook uitgevoerd als er een returnstatement uitgevoerd wordt in de try- of catch-clausule als er een exeption opgegooid wordt in de try- of catch-clausule die niet opgevangen wordt, wordt de finally-clausule toch uitgevoerd als de standaard exeptionklasse niet passend genoeg is voor een bepaald probleem, kan je zelf nieuwe meer specifieke exeptionklassen definiëren en daarbij overerving gebruiken meestal zal de belangrijkste reden voor het nieuw definiëren van een exeptionklasse zijn om de aanvullende informatie op te nemen in het exeption-object om een betere foutdiagnose en oplossing van de fout mogelijk te maken fouten oplossen: een eerste vereiste voor het met succes oplossen van fouten is dat de gebruiker iets doet met de ontvangen foutmelding. Het try-blok van Java is de manier om een foutenoplossingsmechanisme te leveren bij een opgegooide exeption. De oplossing van een fout zal meestal bestaan uit 1 of meerdere handelingen binnen de catchclausule gevolgd door een nieuwe poging. Om pogingen te herhalen kan het try-blok in een lus geplaatst worden fouten voorkomen: om fouten te voorkomen is vaak een nauwe samenwerking nodig tussen programmeur en gebruiker.