Kapittel 7: Mer om arv. Java som første programmeringsspråk

Like dokumenter
Kapittel 7: Mer om arv. Java som første programmeringsspråk

Kapittel 7: Mer om arv

Kapittel 7: Mer om arv

Kapittel 6: Arv. Redigert av: Khalid Azim Mughal

Kapittel 9: Sortering og søking Kort versjon

Kapittel 8: Programutvikling

Kapittel 8: Sortering og søking INF100

Kapittel 8: Sortering og søking

Kapittel 8: Sortering og søking INF100

Kapittel 9: Sortering og søking Kort versjon

Kapittel 9: Sortering og søking Kort versjon

Kapittel 9: Sortering og søking Kort versjon

Repitisjonskurs. Arv, Subklasser og Grensesnitt

Eksekveringsrekkefølgen (del 1) Oppgave 1. Eksekveringsrekkefølgen (del 2) Kommentar til oppgave 1. } // class Bolighus

Kapittel 5: Objektkommunikasjon

En klasse som arver, eller selv deklarerer en abstrakt metode, må deklareres som abstrakt.

INF1010 våren 2008 Uke 4, 22. januar Arv og subklasser

Kort om meg. INF1000 Uke 2. Oversikt. Repetisjon - Introduksjon

class Book { String title; } class Dictionary extends Book { int wordcount; } class CartoonAlbum extends Book { int stripcount; }

Konstruktører. Bruk av konstruktører når vi opererer med "enkle" klasser er ganske ukomplisert. Når vi skriver. skjer følgende:

Arv. Book book1 = new Book(); book1. title = "Sofies verden" class Book { String title; } class Dictiona ry extends Book {

INF 1000 (uke 2) Variabler, tilordninger og uttrykk

Oversikt. INF1000 Uke 1 time 2. Repetisjon - Introduksjon. Repetisjon - Program

Introduksjon til objektorientert programmering

Oversikt. INF1000 Uke 2. Repetisjon - Program. Repetisjon - Introduksjon

public static <returtype> navn_til_prosedyre(<parameter liste>) { // implementasjon av prosedyren

INF1010 våren Arv og subklasser del 1

INF1010 våren Arv og subklasser - del 2

Leksjon 6. Objekt. Evt. importsetninger. public class Klasse { Konstruktør. Objektmetoder. Innkapsling (private): set-og get-metoder

Forelesning inf Java 5

Forelesning inf Java 5

OPPGAVE 1 OBLIGATORISKE OPPGAVER (OBLIG 1) (1) Uten å selv implementere og kjøre koden under, hva skriver koden ut til konsollen?

Forklaring til programmet AbstraktKontoTest.java med tilhørende filer Konto.java, KredittKonto.java, SpareKonto.java

public static <returtype> navn_til_prosedyre(<parameter liste>) { // implementasjon av prosedyren

INF1010 våren Arv og subklasser del 1

INF1000 EKSTRATILBUD. Stoff fra uke 1-5 (6) 3. oktober 2012 Siri Moe Jensen

INF1010 våren Arv og subklasser - del 2

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

IN1010 våren 2018 Tirsdag 15. mai. Repetisjon av subklasser og tråder. Stein Gjessing Institutt for informatikk Universitetet i Oslo

1- og 2-veis Innkapsling Java Stabel Kø Prio-kø Iterator. Enveis- og toveislister Innkapsling («boxing») (Big Java 6.8.5)

I dag skal vi se på. INF 1000 (uke 2) Variabler, tilordninger og uttrykk. Gruppene starter denne uken! Klart for første oblig

INF1010 våren februar. Arv og subklasser, del 2

Eksamen. Objektorientert Programmering IGR 1372

INF1010 Arv. Marit Nybakken 2. februar 2004

Introduksjon til objektorientert. programmering. Hva skjedde ~1967? Lokale (og globale) helter. Grunnkurs i objektorientert.

Dagens tema Kapittel 8: Objekter og klasser

INF1010 våren Arv, subklasser og grensesnitt - del 2

INF1010 våren Arv og subklasser - del 2

Kapittel 11: Unntakshåndtering. Java som første programmeringsspråk

TOD063 Datastrukturer og algoritmer

Programmeringsspråket C

Forkurs INF1010. Dag 1. Andreas Færøvig Olsen Tuva Kristine Thoresen

Læringsmål for forelesningen

Oppsummering. Kort gjennomgang av klasser etc ved å løse halvparten av eksamen Klasser. Datastrukturer. Interface Subklasser Klasseparametre

Kapittel 15: Grafiske brukergrensesnitt: Enkel GUI. Del I

Object interaction. Innhold. Abstraksjon Grunnleggende programmering i Java Monica Strand 3. september 2007.

Kapittel 1: Datamaskiner og programmeringsspråk

Lese fra fil. INF1000 : Forelesning 5. Eksempel. De vanligste lesemetodene. Metoder:

Kapittel 15: Grafiske brukergrensesnitt: Enkel GUI. Del I

Kapittel 13: Grafiske brukergrensesnitt INF 100. Java som første programmeringsspråk

Eksamensrelevant repetisjonsstoff. Deklarasjoner og variabeltyper. Konstanter

I dag skal vi se på. INF 1000 (uke 2) Variabler, tilordninger og uttrykk. Gruppene starter i dag! Klart for første oblig

INF 1000 (uke 2) Variabler, tilordninger og uttrykk

LC191D Videregående programmering Høgskolen i Sør-Trøndelag, Avdeling for informatikk og e-læring. Else Lervik, januar 2012.

Innhold uke 4. INF 1000 høsten 2011 Uke 4: 13. september. Deklarasjon av peker og opprettelse av arrayobjektet. Representasjon av array i Java

Kapittel 11: Unntakshåndtering. Java som første programmeringsspråk

INF Notater. Veronika Heimsbakk 10. juni 2012

INF1010 våren februar. Arv og subklasser, del 2. Repetisjon. Repetisjon - Biler. Repetisjon: Klasser - Subklasser

< T extends Comparable<T> > Indre klasser mm. «Det du bør ha hørt om før oblig 4»

Kapittel 3: Bruk av objekter

Generiske mekanismer i statisk typede programmeringsspråk

Hva er verdien til variabelen j etter at følgende kode er utført? int i, j; i = 5; j = 10; while ( i < j ) { i = i + 2; j = j - 1; }

INF 1000 høsten 2011 Uke september

Løsningsforslag ukeoppg. 6: 28. sep - 4. okt (INF Høst 2011)

INF1000 (Uke 6) Mer om metoder, tekster

INF1000 undervisningen INF 1000 høsten 2011 Uke september

UNIVERSITETET I BERGEN Det matematisk-naturvitenskapelige fakultet

Rep: Metoder. INF1000 (Uke 6) Mer om metoder, tekster. Rep: Metoder. 3 typer variable: Klassevariable. Java-programmene så langt i kurset:

Eksamen i emnet INF100 Grunnkurs i programmering (Programmering I) og i emnet INF100-F Objektorientert programmering i Java I

Eksamen i emnet INF100 Grunnkurs i programmering (Programmering I) og i emnet INF100-F Objektorientert programmering i Java I Løsningsforslag

IN 211 Programmeringsspråk. Java. på 20 enkle ark. spesielt for de som kan. Simula. (og gjerne litt C) Ark 1 av 20

IN1010 våren 2018 Tirsdag 6. februar. Arv og subklasser - del 2

2 Om statiske variable/konstanter og statiske metoder.

Fra Python til Java. En introduksjon til programmeringsspråkenes verden. Dag Langmyhr

Forelesningsquiz. Forelesning inf Java 5. Sett dere to (eller tre) sammen og besvar de fire spørsmålene på utdelt ark. Tid: 15 min.

INF1010 våren 2017 Torsdag 2. februar. Arv og subklasser - del 2

Oversikt. Uke 2, INF 1000, 30 aug Variable, tilordninger og uttrykk. Repetisjon: Java programmering

INF1000 (Uke 5) Mer om løkker, arrayer og metoder

Blokker og metoder INF1000 (Uke 6) Metoder

JAVA Oppsummering for IS-102. Even Åby Larsen

Innhold uke 7. Objektorientert programmering i Python: Introduksjon. Lite tilbakeblikk: Programflyt og skop. Lite tilbakeblikk: Funksjoner er uttrykk

INF1010 våren Arv og subklasser, del 2

Kapittel 1: Datamaskiner og programmeringsspråk

INF 1010, vår 2005 Løsningsforslag uke 11

INF1000 Behandling av tekster

Forelesning inf Java 4

INF1000 Metoder. Marit Nybakken 16. februar 2004

Del 3: Evaluere uttrykk

Mål med kurset. Java i INF Dagens tema. GUI med Swing. Dokumentasjon

Transkript:

Kapittel 7: Mer om arv Forelesningsnotater for: Java som første programmeringsspråk Khalid Azim Mughal, Torill Hamre, Rolf W. Rasmussen Cappelen Akademisk Forlag, 2003. ISBN 82-02-23274-0 http://www.ii.uib.no/~khalid/jfps/ Vi gir tillatelse til å bruke disse notatene i tilknytning til boken. Modifisert: 16/1/06 JFPS 7: Mer om arv 7-1/53

Emneoversikt Programmering med arv: En superklasse med flere subklasser Polymorfisme og dynamisk metodeoppslag Bruk av polymorfe referanser Konsekvenser av polymorfisme Kontrakter i Java Metodeprototyp Abstrakte metoder Kontrakttype Multippel arv for kontrakter Kontrakter og polymorfe referanser Super- og subkontrakter Abstrakte klasser: Instansiering og arv Metodeoverkjøring Konkrete klasser Arv kontra aggregering Innpakning av primitive datatyper: Innpakningsklasser Konverteringsmetoder Synlighet: Pakker og importering Synlighet, arv og tilstand Likhet Referanse- og objektlikhet equals()-metoden JFPS 7: Mer om arv 7-2/53

Programmering med arv En superklasse har ofte flere subklasser, som deklarerer nye eller overskygger felt, og/eller overkjører instansmetoder for å oppfylle subklassens abstraksjon. AnsattV0 fornavn etternavn timelønn NORMAL_ARBEIDSUKE beregnukelønn() skrivtilstand() beregnovertid() TimebetaltArbeiderV0 beregnukelønn() ArbeidsLederV0 ledertillegg beregnukelønn() skrivtilstand() AkkordArbeiderV0 antallenheter prisperenhet beregnukelønn() skrivtilstand() JFPS 7: Mer om arv 7-3/53

Polymorfe referanser Hvilket objekt en referanse skal betegne under utføring kan ikke alltid avgjøres under kompilering.... AnsattV0 enansatt; System.out.println("Velg 1=ansatt, 2=timebetalt, 3=leder, 4=akkord:"); int valg = Terminal.lesInt(); if (valg == 1) enansatt = new AnsattV0("Nils", "Nilsen", 150.0); else if (valg == 2) enansatt = new TimebetaltArbeiderV0("Jon", "Ås", 0); else if (valg == 3) enansatt = new ArbeidsLederV0("Ottar", "Boss", 350, 600); else if (valg == 4) enansatt = new AkkordArbeiderV0("Per", "Berg"); else enansatt = new AnsattV0("Ole", "Olsen", 125.50); // Hvilket objekt betegner enansatt ved utgangen av if-setningen?... Kompilatoren kan ikke avgjøre hvilket objekt referansen enansatt vil betegne ved utgangen av if-setningen ovenfor. En polymorf referanse er en referanse som kan referere til objekter av forskjellige klasser til forskjellige tider. En referanse til en superklasse er polymorf siden den kan referere til objekter av alle subklasser til superklassen under utføring. JFPS 7: Mer om arv 7-4/53

Dynamisk metodeoppslag Når en metode blir påkalt på et objekt er det klassen til objektet (dvs. aktuell type) og metodens signatur som avgjør hvilken metodedefinisjon som blir utført. Typen til referansen (dvs. deklarert type) som betegner objektet er ikke relevant i denne sammenhengen.... // Hvilket objekt betegner enansatt ved utgangen av if-setningen? System.out.println("Ukelønn=" + enansatt.beregnukelønn() // Hvilken beregnukelønn()-metode blir utført? ); enansatt.skrivtilstand();// Og hvilken skrivtilstand()-metode blir utført her?... Dynamisk metodeoppslag er prosessen som bestemmer hvilken metodedefinisjon en metodesignatur betegner under utføring, basert på klassen til objektet. Denne prosessen kan medføre søking oppover i arvhierarkiet for å finne metodedefinisjon. For det første kallet overnfor utføres beregnukelønn()-metoden i den klassen som objektet enansatt betegner tilhører. For det andre kallet blir skrivtilstand()-metoden i AnsattV0 utført, dersom objektet enansatt betegner tilhører AnsattV0- eller TimebetaltArbeiderV0- klassen. Eller utføres skrivtilstand() i en av de to andre subklassene, avhengig om enansatt betegner en arbeidsleder eller en akkordarbeider. JFPS 7: Mer om arv 7-5/53

Bruk av polymorfe referanser class AnsattTabell { // Fra Program 7.5 public static AnsattV0[] hentansatte() { AnsattV0[] ansatte = { // (1) new AnsattV0("Ole", "Brumm", 325.0), new TimebetaltArbeiderV0("Kari","Bø", 325.0), new AkkordArbeiderV0("Lasse", "Liten", 45.50, 126), new ArbeidsLederV0("Ottar", "Boss", 400.0, 500.0), ; return ansatte; public static double[] henttimer() { double[] timer = { 37.5, 25.0, 30.0, 45.0 ; // (2) return timer; public static void main(string[] args) { AnsattV0[] ansatttab; // tabell over ansatte double[] ansatttimer; // timer arbeidet denne uken // Henter data om ansatte og timer ansatttab = hentansatte(); ansatttimer = henttimer(); JFPS 7: Mer om arv 7-6/53

// Går gjennom alle ansatte og skriver utvalgte egenskaper for (int i=0; i<ansatttab.length; i++){ System.out.println( "Ansatt " + (i+1) + ": " + ansatttab[i].fornavn + " " + // (3) ansatttab[i].etternavn + // (4) " har en ukelønn på " + ansatttab[i].beregnukelønn(ansatttimer[i])); // (5) Utskrift fra kjøring: Ansatt 1: Ole Brumm har en ukelønn på 12187.5 Ansatt 2: Kari Bø har en ukelønn på 8125.0 Ansatt 3: Lasse Liten har en ukelønn på 5733.0 Ansatt 4: Ottar Boss har en ukelønn på 21500.0 JFPS 7: Mer om arv 7-7/53

Konsekvenser av polymorfisme Polymorfisme lar oss betegne ulike typer objekter med en felles (polymorf) referanse, så lenge disse objektene tilhører en av subklassene eller superklassen i et arvhierarki. Dynamisk metodeoppslag gjør at samme kall i koden kan resultere i at ulike metodeimplementasjoner blir utført under kjøring. Aktuell type bestemmer hvilken metode som kalles. Klienter kan behandle super- og subklasseobjekter på samme måte, og trenger ikke endres selv om nye subklasser blir lagt til. Dermed blir utvikling og vedlikehold av klienter enklere. JFPS 7: Mer om arv 7-8/53

Kontrakter i Java En kontrakt i Java definerer et sett av tjenester - men uten å gi noen implementasjon. Kontrakten inneholder et sett av metodeprototyper. En metodeprototyp består av metodens navn, parameterliste og returtype men ingen implementasjon. Vi sier at metoden er abstrakt. Eksempel: interface IIdrettslagsMedlem { double beregnkontingent(); Klasser som vil implementere en kontrakt må angi dette vha. nøkkelordet implements, f.eks. class Student implements IIdrettslagsMedlem { double beregnkontingent() { return 100.0; //... andre metoder og felt og gi en implementasjon av kontraktens metoder. JFPS 7: Mer om arv 7-9/53

Kontrakter i Java (forts.) En kontrakt er ikke en klasse - så vi kan ikke lage objekter av en kontrakt. Men en kontrakt definerer en type - kontrakttypen - og vi kan deklarere referanser av denne typen, f.eks. IIdrettslagsMedlem enstudent; En referanse av en kontrakttype kan betegne objekter av alle klasser som implementerer kontrakten: class AnsattV0 implements IIdrettslagsMedlem {... double beregnkontingent() {...... IIdrettslagsMedlem etmedlem; etmedlem = new AnsattV0("Ole", "Olsen", 125.0);... etmedlem = new Student("Jens", "Jensen"); Med en kontrakttype-referanse kan vi derfor få utført alle tjenester som kontrakten definerer. JFPS 7: Mer om arv 7-10/53

Kontrakter i Java (forts.) En kontrakt kan også brukes til å importere delte konstanter. interface ViktigeKonstanter { int AVSLUTT = -1; int FORTSETT = 1; class ViktigKlasse implements ViktigeKonstanter { public int svar() { if (ferdig()) return AVSLUTT; // Kontraktnavn ikke nødvendig pga implements. else return FORTSETT; boolean ferdig() {... Dersom klassen ViktigKlasse ikke hadde deklarert at den implementerte kontrakten ViktigeKonstanter, måtte den ha brukt punktumnotasjon, f.eks. ViktigeKonstanter.AVSLUTT, for å få fatt i konstantene. JFPS 7: Mer om arv 7-11/53

Kontrakter i Java (forts.) En klasse kan implementere flere kontrakter i Java. Dette kalles multippel arv for kontrakter. class ArbeidsLederV0 extends AnsattV0 implements IFagforeningsMedlem, ITillitsValgt {... Klassen må da implementere alle abstrakte metoder fra samtlige kontrakter. En kontrakt B kan utvide en annen kontrakt A. Da kalles A en superkontrakt og B en subkontrakt. En klasse som implementerer B må implementere metodene fra både A og B. interface ITikk { void tikk(); interface ITikkTakk extends ITikk { void takk(); class Klokke implements ITikkTakk { void tikk() {... // fra ITikk (superkontrakten) void takk() {... // fra ITikkTakk (subkontrakten) JFPS 7: Mer om arv 7-12/53

Arvhierarki Object equals() tostring() getclass() Ding ding() Kling ding() dong() String length() substring() equals() Dong dong() class Dong extends Ding {... Klang class Klang extends Kling {... JFPS 7: Mer om arv 7-13/53

Bruk av kontrakter for å håndtere objekter av flere typer Lag en referanse type som kan betegne ting som har både dong()- og ding()-metoder. «kontrakt» DingDong ding() dong() Object equals() tostring() notify() Ding ding() Kling ding() dong() String length() substring() equals() Dong dong() Klang En variabel av type DingDong kan refererer til et Dong-, et Kling- og et Klang-objekt, men ikke til et Ding-objekt. Arv Interface JFPS 7: Mer om arv 7-14/53

Bruk av kontrakter for å håndtere objekter av flere typer (forts.) interface DingDong { public void ding(); public void dong(); class Ding { public void ding() { System.out.println("ding fra Ding"); class Dong extends Ding implements DingDong { public void dong() { System.out.println("dong fra Dong"); class Kling implements DingDong{ public void dong() { System.out.println("dong fra Kling"); public void ding() { System.out.println("ding fra Kling"); class Klang extends Kling { public void klang() { System.out.println("klang fra Klang"); JFPS 7: Mer om arv 7-15/53

public class TestInterface { public static void main(string[] args) { DingDong dingdonger[] = new DingDong[3]; // Oppretter tabell av referanser dingdonger[0] = new Dong(); // Initialiserer referansene dingdonger[1] = new Kling(); dingdonger[2] = new Klang(); for (int i = 0; i < dingdonger.length; i++) dingdonger[i].ding(); // Polymorfe referanser + dynamisk metodeoppslag Utskrift fra kjøring: ding fra Ding ding fra Kling ding fra Kling JFPS 7: Mer om arv 7-16/53

Oppsummering av kontrakter i Java En klasse må eksplisitt deklarere at den implementerer en kontrakt. Klassen (eller dens subklasser) må implementere metoder for metodeprototyper spesifisert i kontrakten. Dersom en klasse implementerer en kontrakt, implementerer også alle dens subklasser den automatisk p.g.a. arv. Arv gjelder også for kontrakter: super- og subkontrakter. Kontrakter definerer en ny referanse type, og referanser av en kontrakttype er polymorfe. En klasse kan implementere flere kontrakter. En klasse som implementerer en subkontrakt må også implementere alle superkontraktens metoder. To varianter av arv: Design-arv: Multippel-kontrakt arv der objekter kan tilhøre mange typer (vha. kontrakter i Java). Implementasjonsarv: Enkel-implementasjonsarv der metode- og variabeloppslag er enklere (vha. subklasser i Java). Nesten alle fordeler av generell multippel arv uten alle implementasjonsvanskeligheter. JFPS 7: Mer om arv 7-17/53

Abstrakte klasser En abstrakt klasse er en klasse som det ikke kan opprettes objekter av. Abstrakte klasser kan brukes som en superklasse, som gjennom arv tvinger alle subklasser til å overholde en felles kontrakt. En abstrakt klasse kan implementere deler (eller hele) kontrakten. En Java-kontrakt derimot implementerer ingenting av kontrakten. En subklasse til en abstrakt klasse må implementere de abstrakte metodene i superklassen. Gjør subklassen ikke det, må den deklareres abstrakt. Klienter kan bruke referanser av den abstrakte klassen til å betegne subklasseobjekter, og vha. polymorfisme få utført riktige instansmetoder. Eksempel: Vi ønsker å gi rabatt på varer. Klassen VareMedRabatt blir abstrakt superklasse for alle rabatterte varer. Klassene Vare og VareMedEnhetspris gjenbrukes. Eksempel: Bruk av Template Method designmønster - en abstrakt klasse implementerer et felles rammeverk for oppførsel; subklasser må implementere de deler som er spesifikke for dem. JFPS 7: Mer om arv 7-18/53

Abstrakte klasser (forts.) Vare varenavn beholdning hentvarenavn() hentbeholdning() settvarenavn() settbeholdning() tostring() VareMedEnhetsPris enhetspris hentenhetspris() tostring() «abstrakt» VareMedRabatt finnrabatt() VareMedFastRabatt rabatt finnrabatt() tostring() VareMedProsentRabatt finnrabatt() tostring() JFPS 7: Mer om arv 7-19/53

Abstrakte klasser (forts.) public class Vare { //... som tidligere public class VareMedEnhetspris extends Vare { //... som tidligere public abstract class VareMedRabatt extends VareMedEnhetspris { VareMedRabatt(String varenavn, int beholdning, double pris) { super(varenavn, beholdning, pris); // kaller superklassens konstruktør abstract double finnrabatt(double prisutenrabatt, int antallbestilt); public class VareMedFastRabatt extends VareMedRabatt { private double rabatt; // fast rabatt i kroner VareMedFastRabatt(String varenavn, int beholdning, double pris, double rabatt) { super(varenavn, beholdning, pris); // kaller superklassens konstruktør assert rabatt >= 0.0 : "Varens rabatt må være større eller lik 0 kr."; this.rabatt = rabatt; public double finnrabatt(double prisutenrabatt, int antallbestilt){return rabatt; public String tostring() { // overkjører tostring() fra VareMedEnhetspris-klassen return super.tostring() + "\trabatt: " + rabatt; JFPS 7: Mer om arv 7-20/53

Abstrakte klasser (forts.) public class VareMedProsentRabatt extends VareMedRabatt { int rabattintervall; // antall varer som må selges for å få rabatt double prosentsats; // prosentsats rabatten økes med per intervall double maksimalsats; // maksimal rabattsats VareMedProsentRabatt(String varenavn, int beholdning, double pris, int rabattintervall, double prosentsats, double maksimalsats) { super(varenavn, beholdning, pris); // kaller superklassens konstruktør assert rabattintervall > 0 : "Rabattintervall må være > 0"; assert prosentsats >= 0.0 : "Rabatt må være >= 0.0% per intervall"; assert maksimalsats >= 0.0 : "Maksimal rabatt må være >= 0.0%"; this.rabattintervall = rabattintervall; this.prosentsats = prosentsats; this.maksimalsats = maksimalsats; public double finnrabatt(double prisutenrabatt, int antallbestilt) { int antallintervaller = antallbestilt / rabattintervall; double rabatt = antallintervaller * prosentsats; if (rabatt > maksimalsats) rabatt = maksimalsats; assert rabatt >= 0.0 : "Gitt rabatt må være >= 0%"; return rabatt/100.0*prisutenrabatt; JFPS 7: Mer om arv 7-21/53

public String tostring() { // overkjører tostring() fra VareMedEnhetspris-klassen return super.tostring() + "\trabatt-intervall: " + rabattintervall + "\tprosentsats: " + prosentsats + "\tmaks.sats: " + maksimalsats; public class Utsalg { public static void main(string[] args) { VareMedEnhetspris[] varelager = { new VareMedEnhetspris("Coca cola 0.5l", 150, 20.0), new VareMedFastRabatt("Pepsi 0.5l", 100, 20, 0.50), new VareMedEnhetspris("Solo 0.5l", 50, 20.0), new VareMedFastRabatt("Farris 0.5l", 50, 20, 1.50), new VareMedProsentRabatt("Coca cola 0.33l", 500, 12, 10, 0.5, 10.0) ; int[] bestilling = { 50, 50, 10, 20, 250 ; double sum = 0; double rabatt = 0; double varepris, varerabatt; for (int i=0; i<varelager.length; i++) { varepris = varelager[i].hentenhetspris(); varerabatt = 0; if (varelager[i] instanceof VareMedRabatt) { VareMedRabatt vare = (VareMedRabatt) varelager[i]; varerabatt = vare.finnrabatt(varepris, bestilling[i]); JFPS 7: Mer om arv 7-22/53

varepris -= varerabatt; varerabatt *= bestilling[i]; // for hele ordren varepris *= bestilling[i]; // for hele ordren System.out.println("Pris for " + bestilling[i] + " stk. av varen '" + varelager[i].hentvarenavn() +"' er " + varepris + " kr."); sum += varepris; rabatt += varerabatt; System.out.println("Total sum: " + sum + " kr."); System.out.println("Rabatt: " + rabatt + " kr er trukket fra."); Utskrift fra kjøring: Pris for 50 stk. av varen 'Coca cola 0.5l' er 1000.0 kr. Pris for 50 stk. av varen 'Pepsi 0.5l' er 975.0 kr. Pris for 10 stk. av varen 'Solo 0.5l' er 200.0 kr. Pris for 20 stk. av varen 'Farris 0.5l' er 370.0 kr. Pris for 250 stk. av varen 'Coca cola 0.33l' er 2700.0 kr. Total sum: 5245.0 kr. Rabatt: 355.00000000000006 kr er trukket fra. JFPS 7: Mer om arv 7-23/53

Arv kontra aggregering Arv tilbyr gjenbruk av klasser ved at nye klasser får tilgang til variabler og metoder fra superklassen (og alle superklasser lengre opp i arvhierarkiet). Aggregering tilbyr gjenbruk av klasser ved at nye klasser deklarerer sammensatte objekter der objekter av eksisterende klasser inngår som delobjekter. Arv brukes når: den nye klassen er en naturlig spesialisering av en eksisterende klasse. den eksisterende klassen kan utvides (dvs. ikke er en endelig klasse). Aggregering brukes når: den nye klassen representerer sammensatte objekter, og det allerede er deklarert klasser for delobjektene. en eksisterende klasse ikke kan utvides. Merk at aggregering tilbys som standard i Java, mens for arv må vi bruke nøkkelordet extends. JFPS 7: Mer om arv 7-24/53

Innkapsling av primitive datatyper Se også egen notat om automatiske konverteringer mellom primitive datatyper og tilsvarende wrapper-klasser. Verdier av primitive typer er ikke objekter. Hvordan kan vi implementere en stabel av heltallsobjekter? Ved å bruke wrapper-klassen Integer som er en klasseinnpakning for heltall. Klasseinnpakninger (Boolean, Character, Byte, Short, Integer, Long, Float, Double) kan brukes til å lage ekte objekter for verdier av primitive datatyper. Primitive verdier lagret i objekter av klasseinnpakninger kan ikke endres, bare leses. JFPS 7: Mer om arv 7-25/53

Innkapsling av primitive datatyper (forts.) Klasseinnpakning: Character Integer Double Konverter til objekt fra en primitiv verdi Konverter objekt til en primitiv verdi Konverter objekt til en streng som representerer en primitiv verdi Konverter til objekt fra en streng som representerer en primitiv verdi Sammenligning av objekter Character cc1 = 'a'; Integer ii1 = 100; Double dd1 = 3.14; char c1 = cc1; int i1 = ii1; double d1 = dd1; String ss1 = cc1.tostring(); Character cc2 = "a".charat(0); boolean b = cc1.equals(cc2); String ss1 = ii1.tostring(); Integer ii2 = new Integer("100"); boolean b = ii1.equals(ii2); String ss1 = dd1.tostring(); Double dd2 = new Double("3.14"); boolean b = dd1.equals(dd2); JFPS 7: Mer om arv 7-26/53

int i; String str; Integer ref; Innkapsling av primitiv datatyper (forts.) streng str = Integer.toString(i); str = String.valueOf(i); str = ref.tostring(); str = String.valueOf(ref); i = Integer.parseInt(str); ref = Integer.valueOf(str); ref = new Integer(str); heltall objekt i = ref; i = ref.intvalue(); ref = i; ref = new Integer(i); JFPS 7: Mer om arv 7-27/53

Nyttige metoder i klasseinnpakninger Klasseinnpakninger inneholder nyttige (statiske) metoder, bl.a. for konvertering av verdier fra en primitiv type til en annen. public class Konvertering { public static void main(string[] args) { // konverterer String til heltall String str = "2000"; int år = Integer.parseInt(str); // konverterer String til flyttall double pi = Double.parseDouble("3.14"); System.out.println("År: " + år); System.out.println("Pi: " + pi); JFPS 7: Mer om arv 7-28/53

Nyttige metoder i klasseinnpakninger (forts.) public class KonverteringII { public static void main(string[] args) { // konverterer tall til String String str_i = Integer.toString(2000); String str_d = Double.toString(3.14); // konverterer String til objekt med tilsvarende tall Integer år_obj = Integer.valueOf("2000"); Double pi_obj2 = Double.valueOf("3.14"); // en del nyttige metoder for char char c1 = 'a', c2 = 'a', c3 = '9'; if (Character.isLowerCase(c1)) { c1 = Character.toUpperCase(c1); if (Character.isUpperCase(c2)) { c1 = Character.toLowerCase(c1); if (Character.isDigit(c3)) { System.out.println("Siffer: " + c3); if (Character.isLetter(c1)) { System.out.println("Bokstav: " + c1); JFPS 7: Mer om arv 7-29/53

Synlighet: Pakker Klasser i Java kan grupperes i pakker. Alle standard Java-pakker er i java-pakken f.eks. java.lang, java.util, java.io, java.awt, java.applet. Pakker er hierarkisk organisert: en pakke kan inneholde andre pakker og klasser. Pakker kan dessuten inneholde Java-kontrakter. Pakkehierarkiet eller organiseringshierarkiet i Java ligner filsystemhierarkiet. JFPS 7: Mer om arv 7-30/53

Synlighet: Pakkehierarki i Java julepakke pakkex pakkey pakkez KlasseA pakkey pakkez KlasseB KlasseC KlasseD KlasseA KlasseB KlasseC KlasseD Organiseringen unngår navnekonflikter. JFPS 7: Mer om arv 7-31/53

Pakketilhørighet Hvilken pakke en klasse tilhører angis i package-setning i kildekodefilen. F.eks. vil bytekodefilen til KlasseA lagt inn i julepakke.pakkex.pakkey: package julepakke.pakkex.pakkey; public class KlasseA {... Hvis det ikke står noen package-setning i kildekodefilen, vil bytekoden til klasser i kildekodefilen lagt inn i standardpakke, dvs. Java-bytekode til klassene i kildekodefilen lagres og utføres fra den inneværende (arbeids)katalogen. JFPS 7: Mer om arv 7-32/53

Pakkebruk En klasse kan refereres ved å bruke pakkestien,.f.eks. java.lang.string enstreng; julepakke.pakkex.pakkey.klassea ena; En metode i KlasseA kan refereres ved: julepakke.pakkex.pakkey.klassea.statiskmetodefraklassea(); import-setningen gir mulighet til å bruke forkortelser: // Eksempel 1 import julepakke.pakkex.pakkey.klassea; // KlasseA kan brukes uten hele pakkestien. KlasseA.statiskMetodeFraKlasseA(); KlasseA refobja; // Eksempel 2 import julepakke.pakkex.pakkey.*; // Alle klasser i pakkey er tilgjengelige via klassenavn. KlasseA.statiskMetodeFraKlasseA(); KlasseB refobjb; JFPS 7: Mer om arv 7-33/53

Klassesynlighet En public-klasse er tilgjengelig i alle andre pakker, dvs. er synlig der pakken den er deklarert i er synlig. Høyst en public-klasse per fil. En klasse uten public-adgangsmodifikator er kun synlig i den pakken den er deklarert i, dvs. klassen har pakkesynlighet. package no.uib.ii.javapakker.opplysninger; public class Allmen { // synlig i andre pakker //... class Gradert { // kun synlig i pakken no.uib.ii.javapakker.opplysninger //... JFPS 7: Mer om arv 7-34/53

Synlighet av klasser i pakker Adgangsmodifikator ingen (dvs. pakkesynlighet) public Effekt Klassen er kun tilgjengelig for andre klasser i den samme pakken. Klassen er tilgjengelig for alle andre klasser, både i og utenfor pakken. For å få tilgang fra en klasse utenfor pakken, må vi enten: (a) importere pakken og gi det klassenavnet som er brukt i pakken (f.eks. ArbeidsLeder), eller (b) bruke pakkestien foran klassenavnet (f.eks. no.dottkom.ansatt.arbeidsleder) JFPS 7: Mer om arv 7-35/53

Synlighet av medlemmer i en public klasse A: variabler og metoder Adgangsmodifikator Effekt public Medlemmet er tilgjengelig for alle andre klasser, både i og utenfor pakken. ingen (dvs. pakkesynlighet) Medlemmet er kun tilgjengelig for andre klasser i den samme pakken. protected Medlemmet er tilgjengelig for andre klasser i pakken (som om det var merket med public). Utenfor pakken er det kun subklasser av A som kan bruke medlemmet. private Medlemmet er kun tilgjengelig innenfor klassen A. JFPS 7: Mer om arv 7-36/53

Medlemmer med pakkesynlighet Dersom ingen adgangsmodifikator er spesifisert for en variabel eller metode, har dette medlemmet pakkesynlighet. dvs. kun synlig i pakken medlemmet er deklarert i. class Lys { // instansvariabler med (standard) pakkesynlighet int antallwatt; boolean indikator; String lokasjon; public void settwatt(int watt) { antallwatt = watt; // Andre metoder... public class Drivhus { public static void main(string[] args) { Lys nyttlys = new Lys(); nyttlys.antallwatt = 100; // OK pga pakkesynlighet. nyttlys.settwatt(100); // OK pga public-synlighet. JFPS 7: Mer om arv 7-37/53

Eksempel: Ansatt-klassene i pakke Ansatt-klassene fra kap.6 plasseres i pakken no.dottkom.ansatt. Vi gir alle medlemmer synlighet public, dvs. de blir synlig både i og utenfor pakken. package no.dottkom.ansatt; public class Ansatt { // Statisk variabel (konstant) public final static double NORMAL_ARBEIDSUKE = 37.5; // Feltvariabler public String fornavn; public String etternavn; public double timelønn; public Ansatt() { // eksplisitt standardkonstruktør // Lar alle feltvariabler få standardverdier // Andre konstruktører og metoder... JFPS 7: Mer om arv 7-38/53

Eksempel: Ansatt-klassene i pakke (forts.) En klient importerer pakken og bruker Ansatt-klassen. package no.dottkom.ansatt; // testprogram i samme pakke import no.dottkom.ansatt.*; // importerer alle klasser i pakken class TestAnsatt { public static void main(string[] args) { // Referanse vha klassenavn - ok Ansatt enansatt = new Ansatt("Per", "Bø", 275.0); System.out.println("Ukelønn for en ansatt:" + enansatt.beregnukelønn(37.5)); // Referanse vha av pakkesti - ok, men unødvendig pga import no.dottkom.ansatt.ansatt ennyansatt = new no.dottkom.ansatt.ansatt("jon", "Ås", 350.0); System.out.println("Ukelønn for en ny ansatt:" + ennyansatt.beregnukelønn(37.5)); JFPS 7: Mer om arv 7-39/53

Pakkehierarki tilsvarer filhierarki inneværende katalog Ansatt.java no TestAnsatt.java dottkom ansatt Ansatt.class... TestAnsatt.class JFPS 7: Mer om arv 7-40/53

Eksempel: Ansatt-klassene i pakke (forts.) Kompilering av Ansatt-klassen: javac -d. Ansatt.java Merk parameter -d. som sørger for å lage katalogstruktur no/dottkom/ansatt under inneværende katalog (.) En eksplisitt filsti kan angis der pakken skal lages. Uten denne parameteren ville klassefilene blitt lagt i inneværende katalog. Kompilering av TestAnsatt-klassen: javac -d. TestAnsatt.java Kjøring av programmet: java -ea no.dottkom.ansatt.testansatt Utskrift fra kjøring: Ukelønn for en ansatt:10312.5 Ukelønn for en ny ansatt:13125.0 JFPS 7: Mer om arv 7-41/53

Kort om CLASSPATH-miljøvariabel Oppsettet skissert ovenfor for kompilering med pakker forutsetter at CLASSPATHmiljøvariabelen er satt riktig. Den angir hvor kompilatoren skal lete etter pakker (som ikke er med i de standard Java-pakkene). I CLASSPATH-miljøvariabelen angis stien til katalogen der pakken ligger, ikke stien til pakken. Dersom pakken no.ii.uib.java.nyttig ligger i katalogen C:\bibliotek, må stien C:\bibliotek angis i CLASSPATH-miljøvariabelen. Det er nyttig å inkludere den inneværende katalogen (working directory) i CLASSPATHmiljøvariabelen. Den inneværende katalogen betegnes med punktum (.) som kan angis i CLASSPATH-miljøvariabelen. Dette medfører at kompilatoren vil også lete for pakker i den inneværende katalogen. Eksempel med oppsettet ovenfor for kompilering med pakker forutsetter at den inneværende katalogen er angitt i CLASSPATH-miljøvariabelen. JFPS 7: Mer om arv 7-42/53

Eksempel: Ansatt-klassene i pakke (forts.) Klassene i Ansatt-pakken kan distribueres som en katalogstruktur med klassefiler. En mer kompakt måte er å lage en JAR (Java ARchive) fil: jar cmf hovedklasse.txt ansatt.jar no Her angir parameter c at vi ønsker å lage en JAR-fil. Parameter m lager og inkluderer en såkalt manifest-fil (hovedklasse.txt). Manifestet angir hvilken klasse i pakken som har main()-metoden som kan kjøres. Innholdet i vår manifest-fil (som er en tekstfil) er: Main-Class: no.dottkom.ansatt.testansatt Parameter f spesifiserer navn på JAR-fil (ansatt.jar). Merk at siden parameter m kommer før f, må navn på manifest-fil gis før navn på JAR-fil. Siste parameter (no) angir katalogen vi ønsker å legge inn. Alle underkataloger og filer i disse tas med automatisk. Kjøring av programmet: java -ea -jar ansatt.jar Utskrift fra kjøring: Akkurat den samme som for kjøring med klassefiler! JFPS 7: Mer om arv 7-43/53

Synlighet, arv og tilstand Private medlemmer ikke blir arvet av subklassene. Dermed kan ikke subklasser referere direkte til superklassens private medlemmer vha. felt- eller metodenavn, men kan likevel anse disse medlemmene som en del av sin egen tilstand eller atferd. Subklassene kan få indirekte tilgang til superklassens private medlemmer gjennom arvede metoder. Overkjørte og skyggete medlemmer ikke blir arvet. Nøkkelordet super må brukes til å få adgang til dem. public class Vare2 { // synlighet eksplisitt deklarert private String varenavn; private int beholdning; public int hentbeholdning() { return beholdning; //... ellers som i Vare-klassen public class VareMedEnhetspris2 extends Vare2 { // synlighet eksplisitt deklarert private double enhetspris; //... ellers som i VareMedEnhetspris-klassen JFPS 7: Mer om arv 7-44/53

Synlighet, arv og tilstand (forts.) Tilstanden i et VareMedEnhetspris2-objekt: :VareMedEnhetspris2 «Vare2» -varenavn = "Coca cola 0.5l" -beholdning = 20 +settvarenavn() +settbeholdining() +hentvarenavn() +hentbeholdning() +tostring() «VareMedEnhetspris2» -enhetspris = 12.50 envare:ref(varemedenhetspris2) +hentenhetspris() +tostring() JFPS 7: Mer om arv 7-45/53

Likhet: Referanse- og objektlikhet Likhetsoperatoren (==) kontrollerer om 2 referanser refererer til det samme objektet. Om 2 objekter har samme tilstand, dvs. har samme innhold, kontrolleres vanligvis ved å overkjøre metoden equals() fra Object-klassen. class Punkt { private int x; private int y; //... konstruktør //... hent- og sett-metoder public boolean equals(object obj) { // overkjører equals()-metoden fra Object-klassen if (obj instanceof Punkt) { Punkt p = (Punkt) obj; return ((p.x==x)&&(p.y==y)); else return false; public String tostring() { // overkjører tostring()-metoden fra Object-klassen return "\tx= " + x + ",\ty=" + y; JFPS 7: Mer om arv 7-46/53

Likhet: Referanse- og objektlikhet (forts.) public class LikhetsKlient { public static void main(string[] args) { Punkt p1, p2, p3; p1 = new Punkt(10, 6); // p1.x lik 10 og p1.y lik 6 p2 = new Punkt(10, 6); // p2.x lik 10 og p2.y lik 6 System.out.println("p1: " + p1); System.out.println("p2: " + p2); System.out.println("Sammenligner referanser p1 og p2: " + (p1==p2)); // false System.out.println("Sammenligner innhold p1 og p2: " + p1.equals(p2)); // true p2.setty(12); // p2.x lik 10 og p2.y lik 12 System.out.println("p2: " + p2); System.out.println("Sammenligner innhold p1 og p2: " + p1.equals(p2)); // false p3 = p2; System.out.println("p3: " + p3); System.out.println("Sammenligner referanser p2 og p3: " + (p2==p3)); // true System.out.println("Sammenligner innhold p2 og p3: " + p2.equals(p3)); // true JFPS 7: Mer om arv 7-47/53

Utføring av programmet: p1: x= 10, y=6 p2: x= 10, y=6 Sammenligner referanser p1 og p2: false Sammenligner innhold p1 og p2: true p2: x= 10, y=12 Sammenligner innhold p1 og p2: false p3: x= 10, y=12 Sammenligner referanser p2 og p3: true Sammenligner innhold p2 og p3: true JFPS 7: Mer om arv 7-48/53

Metodebinding For overlastede metoder, blir et metodekall bindet til riktig metode under kompilering. Den deklarerte typen til referansen og kallsignaturen avgjøre hvilken overlastede metode har den meste spesifikke metodesignaturen. Denne metoden blir utført under kjøring. For overkjørte metoder, blir et metodekall bindet til riktig metode under utføring. Aktuell typen til objektet avgjøre hvilken metode blir utført, og kan kreve søking opp i arvhierarkiet under utføring. JFPS 7: Mer om arv 7-49/53

class Punkt2 { private int x; private int y; Punkt2(int x, int y) { this.x = x; this.y = y; public int hentx() { return x; public int henty() { return y; public void settx(int x) { this.x = x; public void setty(int y) { this.y = y; Overkjøring kontra Overlasting public boolean equals(punkt2 obj) { // overlaster equals()-metoden fra Object-klassen if (obj instanceof Punkt2) { Punkt2 p = (Punkt2) obj; return ((p.x==x)&&(p.y==y)); else return false; public String tostring() { // overkjører tostring()-metoden fra Object-klassen return "\tx= " + x + ",\ty=" + y; JFPS 7: Mer om arv 7-50/53

public class LikhetsKlient2 { public static void main(string[] args) { Object p1, p2, p3; // NB. Referanser av supertype til Punkt2. p1 = new Punkt2(10, 6); // p1.x lik 10 og p1.y lik 6 p2 = new Punkt2(10, 6); // p2.x lik 10 og p2.y lik 6 System.out.println("p1: " + p1); System.out.println("p2: " + p2); System.out.println("p1==p2: " + (p1==p2)); // false System.out.println("p1.equals(p2): " + p1.equals(p2)); // false System.out.println("p1.equals((Punkt2)p2)): " + p1.equals((punkt2)p2)); // false System.out.println("((Punkt2) p1).equals((punkt2)p2)): " + ((Punkt2) p1).equals((punkt2)p2)); // true ((Punkt2)p2).settY(12); // p2.x lik 10 og p2.y lik 12 System.out.println("p2: " + p2); System.out.println("p1.equals(p2): " + p1.equals(p2)); // false p3 = p2; System.out.println("p3: " + p3); System.out.println("p2==p3: " + (p2==p3)); // true System.out.println("p2.equals(p3): " + p2.equals(p3)); // true JFPS 7: Mer om arv 7-51/53

Utføring av programmet: p1: x= 10, y=6 p2: x= 10, y=6 p1==p2: false p1.equals(p2): false <=================== Object.equals(Object o) p1.equals((punkt2)p2)): false <=================== Object.equals(Object o) ((Punkt2) p1).equals((punkt2)p2)): true <=================== Punkt2.equals(Punkt2 o) p2: x= 10, y=12 p1.equals(p2): false <=================== Object.equals(Object o) p3: x= 10, y=12 p2==p3: true p2.equals(p3): true <=================== Object.equals(Object o) JFPS 7: Mer om arv 7-52/53

Substitusjonsprinsippet - Liskov En referansetype kan være: et klassenavn et kontraktnavn en tabelltype Subtyper og supertyper: I arvhierarkiet, en referansetype kan ha en eller flere supertyper. Referansetypen er en subtype til hver av dens supertyper. Substitusjonsprinsippet: Subtypers atferd er i samsvar med spesifikasjon av deres supertyper, d.v.s. at et subtype-objekt kan substitueres for et supertype-objekt. JFPS 7: Mer om arv 7-53/53