Föreläsning 1-2
Innehåll
Språkkonstruktioner i Java
Interface Exceptions
Introduktion till generik
Autoboxing - och unboxing
Introduktion till delar av Javas klassbibliotek
Java Collections Framework interface och klasser för samlingar av element
interfacen Iterator och Iterable och foreach-sats i Java - används för att traversera genom en samling element
Jämföra objekt metoden equals, interfacet Comparable
Språkkonstruktioner i Java, Javas klassbibliotek - mål
Undervisningsmoment:
föreläsning 1-2 övning 1
laboration 1 Avsnitt i läroboken:
1.1-1.6, 2.1, Appendix A6, A11, A12 I gamla upplagan: 1.1-1.3, 2.1-2.4, 4.1
Exempel på vad du ska kunna
Förklara begreppen: abstraktion, abstrakt datatyp, specikation, implementation, interface, pre- och post-conditions
deklarera interface i Java
Skriva klasser som implementerar interface
Språkkonstruktioner i Java, Javas klassbibliotek - mål, forts
Exempel på vad du ska kunna, forts
Skriva metoder som genererar exception
Förklara begreppen: generik, typparameter, autoboxing och unboxing Använda generiska klasser
Implementera generiska klasser
Använda en iterator för att traversera en samling element
Implementera iteratorer för enkla datastrukturer som listor och vektorer
Förklara interfacet Comparable och kunna implementera detta interface
Formulera testfall och använda JUnit för att testa klasser.
Förklara begreppen: skuggning, överlagring, polymorsm
Objektorienterad design
Man utgår från de data programmet ska arbeta med, alltså de verkliga
saker (objekt) som nns i problemet.
Objekten har
egenskaper (attribut)
operationer som kan utföras på objektet (motsvaras av metoder)
Objekten beskrivs i en klass. Klassen fungerar alltså som mall för objekten.
Vi gör en abstrakt modell av verkligheten. Endast egenskaper som är väsentliga för problemet nns med.
Att abstrahera betyder att bortse från oväsentliga detaljer för att istället framhäva det som är relevant.
Abstrakt datatyp (ADT)
Denition
En abstrakt modell tillsammans med de operationer man kan utföra på den.
Exempel:
Abstrakt modell: komplexa tal
Operationer på modellen: hämta realdel, hämta imaginärdel, addera . . .
En ADT motsvaras av en specikation av en klass eller av ett interface En klass är en implementering av en ADT
Abstrakta datatyper
Fördelar
Man får en väldenierad utvidgning av programspråket (ett klassbibliotek).
Utvidgningen gör det enklare för användaren att lösa sitt problem.
implementeringen kan ändras utan att det påverkar resten av programmet.
En ADT kan utnyttjas för era problem (component reuse).
En ADT kan testas separat.
Interface
Interface i Java
Betyder gränssnitt
Innehåller ingen implementering Alla metoder är implicit publika
Kan användas för att specicera en ADT
public interface ComplexNumber { /** returns real part */
double getRe();
/** returns imaginary part */
double getIm();
/** adds this number and rhs and returns result as a new complex number */
ComplexNumber add(ComplexNumber rhs);
Interface
Implementera ett interface
Ett interface kan implementeras av en eller era klasser.
public class MyComplexNumber implements ComplexNumber { private double re;
private double im;
public MyComplexNumber(double re, double im) { this.re = re;
this.im = im;
}
public double getRe() { return re;
} ...
Interface
Implementera ett interface, forts
...
public double getIm() { return im;
}
public ComplexNumber add(ComplexNumber rhs) {
return new MyComplexNumber(re+rhs.getRe(),im+rhs.getIm());
} }
Interface
Implementera era interface
En klass kan implementera era interface
men bara ärva från en klass.
public class MyComplexNumber2 implements ComplexNumber, Cloneable { // implementering av alla metoder i interfacen
// ComplexNumber och Cloneable }
Interface
Interface som typnamn
Interface kan användas som typnamn.
ComplexNumber c;
public void p(ComplexNumber c) {...}
Fördel: man binder sig inte till en speciell implementering
c = x; är ok när x är en instans av en klass som implementerar interfacet ComplexNumber
anrop p(x) är ok när x är en instans av en klass som implementerar interfacet ComplexNumber
Interface
Kontrakt
Interfacet fungerar som kontrakt.
Flera implementeringar (klasser) kan uppfylla kontraktet.
Användare har tillgång till alla operationer i ett interface innan de är implementerade.
Det är bara när man skapar instanser som man behöver tillgång till en implementerande klass.
Man kan enkelt byta en implementerande klass mot en annan.
ComplexNumber c1 = new MyComplexNumber(1,2);
ComplexNumber c2 = c1;
c2 = c2.add(c1);
p(c2);
Interface
Övning
Övning
Deniera ett interface med namnet Resizable med en metod resize som är void och har en parameter scaleFactor av typen double.
Övning
Ändra i klassen Square så att den implementerar interfacet Resizable.
public class Square { private double side;
public Square(double side) { this.side = side;
}...
Pre- och postconditions
Kontrakt på metodnivå
Preconditions är villkor som måste vara uppfyllda för att en metod ska kunna utföra sin uppgift.
Ibland nns inga preconditions.
När de nns, är de ofta villkor som parametrarna ska uppfylla.
Postconditions beskriver hur exekvering av metoden förändrar tillståndet hos objektet.
Behöver bara anges om metoden förändrar tillståndet (oftast void-metoder).
För metoder som inte är void bör man i stället ge en kommentar om vad som returneras.
Pre- och postconditions
Exempel
public class BankAccount { private int balance;
...
/*** Deposits the specified amount.
* pre: The specified amount is >= 0
* post: The specified amount is added to balance
* @param n The amount to deposit public void deposit(int n) {*/
balance = balance + n;
} ...
Fel i program (buggar)
Olika slags fel
Syntaxfel bryter mot språkets grammatik (syntax).
Exempel: glömt ett {, glömt deklarera en variabel innan den används ...
Exekveringsfel (Runtime errors eller Exceptions) upptäcks vid exekvering.
Exempel: ArrayIndexOutOfBoundException, NullPointerException, ...
Logiska fel Programmet kan köras men ger fel resultat.
Exekveringsfel
Vad händer vid ett exekveringsfel?
Ett objekt (exception) skapas som beskriver typen av fel.
Programmet avbryts.
Ett felmeddelande skrivs ut där
typ av fel
stacktrace (sekvensen av metodanrop)
framgår.
Exception
Sammanfattning
Betyder undantag
Exception genereras (throws) vid exekveringsfel.
Man kan fånga (catch) exception och då själv avgöra hur felsituationen ska hanteras.
Man kan skriva kod som genererar exception inuti en metod. (Används om det uppstår en situation som gör det omöjligt för metoden att
utföra sin uppgift.)
Exception
Olika typer av fel beskrivs av olika subklasser till klassen Exception.
Exception
RuntimeException IOException
FileNotFoundException
...
ArrayIndexOutOfBoundException
NullPointerException
NoSuchElementException
...
Exceptions
Unchecked och checked
Det nns två slag av Exceptions:
Unchecked Exceptions
Subklass till RuntimeException.
Behöver inte fångas.
Exempel: ArrayIndexOutOfBoundException, NullPointerException
Checked Exceptions
Måste fångas någonstans i anropskedjan, annars kompileringsfel.
Metoder som genererar sådana måste ange det i sin metodrubrik.
Exempel:
public Scanner createScanner(String fileName) throws
FileNotFoundException { } ...
Exceptions
Unchecked och checked, forts
Unchecked Exceptions används då felet beror på programmeraren
Ex: NullPointerException eller ArrayIndexOutOfBoundsException
Checked Exceptions används då felet inte beror på programmeraren
Ex: FileNotFoundException om man försöker öppna en l som inte
nns
Fånga checked Exceptions
Exempel
När man anropar en metod som genererar en checked exception måste man ta hand om det. Normalt fångar man det i en try-catch-sats:
Scanner scan = null;
try {
// försöker öppna en fil med namnet fileName scan = new Scanner(new File(fileName));
} catch (FileNotFoundException e) {
System.err.println("Couldn't open file " + fileName);
System.exit(1);
}... använd scan ...
Om exception inträar, avbryts exekveringen av satserna i try-blocket och satserna i catch-blocket exekveras.
Fånga checked Exceptions
Forts
I satsen catch(Exception e) kan t.ex. följande metoder användas för att få mer information:
e.printStackTrace(); som skriver ut information om raden där felet inträat och den/de metodanrop som lett till denna rad.
e.getMessage(); som returnerar en sträng med meddelande om felets art.
Exempel:
Scanner scan = null;
try {
scan = new Scanner(new File(fileName));
} catch (FileNotFoundException e) { e.printStackTrace();
System.exit(1);
}... använd scan ...
Fånga exception
Mönster
try {
// kod som kan generera exception } catch (ExceptionClass e) {
// kod för att hantera exception }
try {
// kod som kan generera exception } catch (ExceptionClass1 e1) {
// kod för att hantera exception av typen ExceptionClass1 } catch (ExceptionClass2 e2) {
// kod för att hantera exception av typen ExceptionClass2 } finally {
// kod som utförs efter try-blocket eller efter catch-blocket }
Ignorera checked Exceptions
Man kan ignorera en checked Exception och kasta det vidare till den anropande metoden.
I så fall måste man ange det i metodrubriken i den metod där exception genereras:
public Scanner createScanner(String fileName) throws
FileNotFoundException { // Här genereras exception om filen inte går att öppna Scanner scan = new Scanner(new File(fileName));
return scan;
}
I den metod som anropar createScanner måste man ta hand om detta exception och kan korrigera felet på valfritt sätt.
Hantera unchecked exceptions
Metod som genererar unchecked exception behöver inte ange det i sin rubrik
Kan anges i kommentar
Den som anropar en metod som kan generera en unchecked exception behöver inte (men kan) fånga den i en try-catch-sats
Leder till exekveringsfel om de inte fångas.
Generera exception
Exempel:
throw new IllegalArgumentException("amount to deposit < 0");
Mönster:
throw new ExceptionClass();
throw new ExceptionClass(message);
Eekt:
Ett nytt exception-objekt skapas.
Exekveringen av metoden avbryts.
Javasystemet letar efter fångande catch-block.
Generera exception
Exempel
/*** Deposits the specified amount.
* pre: The specified amount is >= 0
* post: The specified amount is added to balance
* @param n The amount to deposit
* @throws IllegalArgumentException if the specified amount is < 0 public void deposit(int n) {*/
if (n < 0) {
throw new IllegalArgumentException("amount to deposit < 0");
}balance = balance + n;
}
Egna exceptionklasser
Om man vill kan man implementera en egen exceptionklass (behövs sällan, det nns färdiga exceptionklasser i Javas bibliotek för de esta situationer).
Om den ska vara checked:
public class SpellException extends Exception { } ...
Om den ska vara unchecked:
public class SomeSortOfException extends RuntimeException { } ...
Exceptions
Övning
Övning
1. Ändra följande metod så att exception genereras i de fall det är lämpligt.
/*** Withdraws the specified amount.
* pre: The specified amount is >= 0 and <= balance
* post: Balance is decreased by the specified amount
* @param n The amount to withdraw public void withdraw(int n) {*/
balance = balance - n;
}
2. Antag att variabeln acc refererar till ett bankkonto-objekt och att
metoden withdraw nns i bankkonto-klassen. Anropa withdraw och skriv
Autoboxing unboxing
Primitiva typer - wraperklasser
Primitiva typer i Java:
boolean short intlong charbyte float double
Motsvarande wrapper-klasser:
Boolean Short Integer LongCharacter ByteFloat
Double
Autoboxing unboxing
Exempel:
Integer i = new Integer(2);
Fr o m Java 5.0 kan vi skriva:
i = i + 1;
Detta var inte tillåtet i i tidigare versioner av Java. Där måste man skriva:
i = new Integer(i.intValue() + 1);
Autoboxing unboxing
Autoboxing automatisk konvertering från primitiv typ till objekt av motsvarande wrapper-klass
Unboxing automatisk konvertering av objekt av wrapperklass till motsvarande primitiva typ
Exempel:
Integer k = 3; // autoboxing int j = k; // unboxing Integer i = new Integer(2);
i = i + 1;
// Unboxing av i för att beräkna i+1.
// Därefter autoboxing av resultatet vid // tilldelningen.
Autoboxing unboxing
i samband med collection-klasser
Praktiskt när man vill använda Javas collection-klasser för att lagra element av primitiv typ. Ex:
ArrayList<Integer> myList = new ArrayList<Integer>();
myList.add(1); // Konvertering till Integer-objekt här.
...int j = myList.get(0); // Konvertering till int här.
Generik
Introduktion till Generik i Java
Här introduceras generiska klasser och interface.
Mer om generik nns att läsa på OH-bilderna Mer om generik som
nns på kursens hemsida:
generik och arv wildcards
vektorer och generik generiska metoder
Vissa av dessa moment dyker upp och förklaras i samband med laborationer.
Generik
Bakgrund
Klasser bör implementeras så att de blir generella d.v.s. går att använda i många olika sammanhang.
En klass som hanterar en lista av element ska inte skrivas så att den bara kan hantera listor med heltal.
Lösningen har i tidigare javaversioner varit att ge parametrar i metoderna den mest generella typen Object.
Ex: add-operationen i en lista kunde ha signaturen public boolean add(Object x);
Generik
Bakgrund forts
Typosäkerhet utan generik!
I den gamla modellen kunde man skriva:
myList.add(new Integer(1));
myList.add(new Integer(2));
myList.add(new Person(Kalle));
Om avsikten är att listan ska innehålla tal, har vi gjort fel på rad 3.
Kompilatorn kan inte upptäcka detta koden är korrekt, både Integer och Person är subklasser till Object.
Generik i Java
Ger oss möjlighet att abstrahera över typer
Vi kan använda typparametrar när vi denierar en klass. Ex:
public class ArrayList<E> {...}
Vid användning av en generisk klass anges ett aktuellt typargument.
Ex:
ArrayList<Integer> myList = new ArrayList<Integer>();
Generik i Java
Kompilatorn kommer att upptäcka typfel. Ex:
ArrayList<Integer> myList = new ArrayList<Integer>();
myList.add(new Person("Kalle"));
ger nu kompileringsfel, myList får enligt sin deklaration endast innehålla objekt av typen Integer.
Exempel på en generisk klass
java.util.ArrayList
Utdrag ur den generiska klassen java.util.ArrayList:
public class ArrayList<E> { public ArrayList() {...}
public boolean add(E x) {...}
public void add(int index, E x) {...}
public E get(int index) {...}
} ...
Alla add-metoder har inparameter av typen E. Därför kan enbart objekt av klassen E (eller subklasser till denna) sättas in i listan.
Exempel på en generisk klass
java.util.ArrayList, forts
Observera att inte alla operationer i ArrayList<E> har E som
typparameter. T.ex. har contains och remove följande signaturer:
public boolean contains(Object x);
public boolean remove(Object x);
Användare som inte känner till den exakta typen av ett element x ska
kunna anropa metoderna. Dock kommer man att få resultat true om och endast om x nns i listan (och alltså även är av rätt typ).
Användning av en generisk klass
java.util.ArrayList
Exempel:
ArrayList<String> list = new ArrayList<String>();
list.add("Lisa");
list.add("Per");
...String s = list.get(0);
System.out.println(s);
...
Implementering av generisk klass
Java 1.4
public class Container { private Object item;
public Container(Object x) { item = x;
}
public Object get() { return item;
}
public void set(Object x) { item = x;
} }
Fr o m Java 5.0 generisk klass
public class Container<E> { private E item;
public Container(E x) { item = x;
}
public E getItem() { return item;
}
public void setItem(E x) { item = x;
} }
Generisk klass med era typparametrar
Implementering
public class Pair<K, V> { private K key;
private V value;
public Pair(K key, V value) { this.key = key;
this.value = value;
}
public V getValue() { return value;
}
public void setValue(V val) { value = val;
}
Generisk klass med era typparametrar
Användning
Exempel:
Pair<String, Integer> pair = new Pair<String, Integer>("June", 30);
int nbrDays = pair.getValue();
Generiska interface
Även interface kan vara generiska. Ex:
public interface Set<E> { boolean add(E x);
int size();
boolean contains(Object x);
} ...
Generik syntax
Deklaration av parametriserade (generiska) klasser/interface:
public class Set<E> {...}
public interface Comparable<T> ...
public class Pair<K,V> ...
Klassen/interfacet har en parameterlista som omges av tecknen < och
>.
En parameter namnges med en typvariabel (markeras ovan) som kan vara en godtycklig identierare.
Om det är era parametrar används komma som skiljetecken.
Generik syntax
Generiska klasser/interface denierar en samling av typer: en typ för varje möjlig instansiering av typparametrarna.
Deklarationen av Set<E> på föregående bild denierar t ex följande parametriserade typer:
Set<Integer>
Set<Character>
Set<String>
Set<Set<String>> // nästling tillåten ...
Generik syntax
Vi kan använda parametriserade typer i deklaration av attribut, variabler, metodparametrar, ... Ex:
ArrayList<Integer> myList;
Pair<Integer, String> aPair;
public static printSet(Set<Integer> s) {...}
När vi skapar instanser av generiska klasser anges typargumenten inom tecknen < och > Ex:
ArrayList<Integer> myList = new ArrayList<Integer>();
Pair<Integer, String> aPair =
new Pair<Integer, String>();
Generik syntax
I generiska klasser/interface kan typparametrarna användas för att deklarera attribut, variabler, ... Ex:
public class Container<E> { private E item;
public Container(E x){
this.item = x;
}
public E getItem()){
returnh item;
...} }
Restriktioner för typparametrar och typvariabler
Parameter till generisk klass kan inte vara primitiv typ:
SomeClass<int> c = ... // Går inte!
Typvariabler kan inte användas för att skapa objekt:
public class SomeClass<E> { public void p() {
E x = new E(); // Fel!
...
Typparametrar kan inte användas för att överlagra metoder:
public class MyClass<T,U> { public void p(T x) {...}
public void p(U x) {...} // Fel!
...
Introduktion till delar av Javas klassbibliotek
Java Collections Framework interface och klasser för samlingar av element
interfacen Iterator och Iterable och foreach-sats i Java - används för att traversera genom en samling element
interfacet Comparable
Läsanvisningar
Interfacet List och Klassen ArrayList behandlas i avsnitt 2.1.
Fler interface och klasser behandlas senare i kursen/läroboken.
Dokumentation
På Javas hemsida (länk nns på kursens hemsida) nns dokumentation av Javas standardklasser.
JCF Java Collections Framework
Är en hierarki av interface, abstrakta klasser och konkreta klasser för samlingar av element.
Finns i paketet java.util.
Basen i hierarkin är ett interface Collection:
interface Collection<E> { boolean add(E x);
boolean contains(Object x);
boolean remove(Object x);
boolean isEmpty();
int size();
} ...
JCF interface hierarki
<<Interface>>
Map
<<Interface>>
SortedMap
<<Interface>>
Collection
<<Interface>>
Queue
<<Interface>>
List
<<Interface>>
Set
<<Interface>>
SortedSet
JCF interface hierarki
Collection en samling av element, där dubbletter tillåts Queue en samling av element som utgör en kö
List en samling element där dubbletter tillåts och där
positionering är möjlig (första, sista, element på plats i, ...) Set en samling element där dubbletter är förbjudna
SortedSet som Set men med krav att elementen går att jämföra
Map en samling av element, där varje element har en en nyckel och ett värde (jfr. lexikon)
SortedMap som Map men med krav att nycklarna går att jämföra
JCF några klasser
Interface Implementering
Queue LinkedList, PriorityQueue List ArrayList, LinkedList
Set HashSet
SortedSet TreeSet
Map HahsMap
SortedMap TreeMap
Iteratorer
Antag att vi lagrar ett antal personer i en lista (eller i någon annan samlingsklass):
ArrayList<Person> pList = new ArrayList<Person>();
// här sätts Person-objekt in i samligen }
Hur ska vi göra för iterera genom samligen och behandla alla personerna (t.ex. skriva ut alla personernas namn)?
Interfacet Iterator<E>
En instans av en klass som implementerar interfacet Iterator används för att iterera över alla element i en samling.
public interface Iterator<E> {
/** Returns true if the iteration has more elements. */
boolean hasNext();
/** Returns the next element in the iteration. */
E next();
/** Removes from the underlying collection the last element returned by the iterator (optional). */
void remove();
}
Hur får man tag på ett iterator-objekt?
Interfacet Iterable<E>
I Java nns följande interface:
public interface Iterable<E> {
/** Returns an iterator over a set of elements of type E */
Iterator<E> iterator();
}
Interfacet Collection ärver interfacet Iterable:
public interface Collection<E> extends Iterable<E> ...
Alla klasser som implementerar Collection måste alltså implementera metoden iterator().
JCF interface hierarki
med Iterable<E> och Iterator<E>
<<Interface>>
Collection
<<Interface>>
Queue
<<Interface>>
List
<<Interface>>
Set
<<Interface>>
SortedSet
<<Interface>>
Iterable iterator()
<<Interface>>
Iterator hasNext()
next() remove()
<<Interface>>
Map
<<Interface>>
SortedMap
Användning av iterator
Exempel
ArrayList<Person> pList = new ArrayList<Person>();
// här sätts Person-objekt in i samlingen ...Iterator<Person> itr = pList.iterator();
while (itr.hasNext()) { Person p = itr.next();
// behandla p } ...
Lägg märke till hur man skaar sig en iterator genom att anropa metoden iterator.
Metoden iterator()
Exempel på collection-klass med metoden iterator
public class ArrayCollection<E> implements Collection<E> { private E[] theCollection;
private int size;
... impl av konstruktor, add, ...
public Iterator<E> iterator() { return new ArrayIterator();
}
private class ArrayIterator implements Iterator<E> { .... implementering på nästa bild ...
} }
Implementering av interfacet Iterator<E>
Exempel: Klassen ArrayIterator
private class ArrayIterator implements Iterator<E> { private int pos;
private ArrayIterator() { pos = 0;
}
public boolean hasNext() { return pos < size;
} ...
Implementering av interfacet Iterator<E>
Exempel: Klassen ArrayIterator, forts
...
public E next() { if (hasNext()) {
E item = theCollection[pos];
pos++;
return item;
} else {
throw new NoSuchElementException();
} }
public void remove() {
throw new UnsupportedOperationException();
} }
Implementering av interfacet Iterator<E>
Inre klass
Den klass som implementerar interfacet Iterator kan vara inre klass i den klass som representerar samlingen.
En inre klass har tillgång till alla attribut i den omgivande klassen det utnyttjas t.ex. i operationen next.
Den kan vara privat, och ha en en privat konstruktor, eftersom det bara är den omgivande klassen som skapar instanser. Metoderna hasNext, ... måste däremot vara publika eftersom interfacet
Iterator föreskriver detta.
Implementering av interfacet Iterator<E>
Kommentar
Implementeringen som visats här är förenklad:
Iteratorer har enligt sitt kontrakt inte till uppgift att klara av att samlingen modieras mellan anrop av next().
En korrekt iterator-implementering måste upptäcka detta och generera en exception om samlingen modieras.
foreach-sats i Java
Exempel
ArrayList<Person> pList = new ArrayList<Person>();
// här sätts Person-objekt in samlingen ...for (Person p : pList) {
// behandla p }
Ett sätt att enkelt iterera över samlingar. Man slipper att explicit använda en iterator.
for (Person p : pList) ... kan läsas som för varje p i pList. Kan användas för objekt av klasser som implementerar Iterable och för vektorer.
foreach-sats
Vektorer
Kan också användas för att iterera över elementen i en vektor.
Ex: En metod som skriver ut namn på personer som lagrats i en vektor av typ Person[]:
public void print(Person[] a) { for (Person p : a) {
System.out.println(p.getName());
} }
Iterator foreach-sats
Övning
Övning
Antag att vi har följande lista:
LinkedList<Integer> list = new LinkedList<Integer>();
list.add(25);
list.add(42);
...
Summera talen i list genom att använda iterator() resp. foreach-sats.
foreach-sats
Begränsningar
Foreach-sats kan inte användas när man explicit behöver tillgång till iteratorn i koden.
Exempel: Tag bort alla personer som matchar x ur en ArrayList<Person>
pList:
Iterator<Person> itr = pList.iterator();
while (itr.hasNext()) {
if (itr.next().equals(x)) { itr.remove();
} }
Här behövs iteratorn för att kunna ta bort element.
foreach-sats
Begränsningar
Foreach-sats kan inte användas för att iterera parallellt över era samlingar, motsvarande följande kod:
ArrayList<Person> list1, list2;
...Iterator<Person> itr1 = list1.iterator();
Iterator<Person> itr2 = list2.iterator();
while(itr1.hasNext() && itr2.hasNext()) {
System.out.println(itr1.next() + " " + itr2.next());
}
Nästlad foreach-sats
Däremot går det bra med nästlade loopar.
Ex: Skriv ut alla kombinationer av strängar str1 str2 där str1 nns i vektorn first och str2 nns i vektorn second. first och second är av typen String[] :
for (String f : first ) {
for (String s : second) {
System.out.println(f + " " + s);
} }
Söka efter objekt i en lista
Följande klass beskriver en person:
public class Person {
private String name;
private int idNbr;
public Person (String name, int idNbr) { this.name = name;
this.idNbr = idNbr;
} }
Vad skrivs ut när följande rader exekveras?
ArrayList<Person> list = new ArrayList<Person>();
list.add(new Person("Kalle", 1));
list.add(new Person("Kajsa", 2));
Jämföra likhet
Metoden equals
Metoden equals används för att jämföra om två objekt är lika:
Person p1 = ...;
Person p2 = ;...
if (p1.equals(p2)) {...}
Metoden equals nns i superklassen Object. Den returnerar true om och endast om de jämförda objekten är identiska.
Om man istället vill att innehållet inuti objekten ska jämföras måste man omdeniera (skugga) equals.
Exempel: Om man vill att två personer ska anses lika när de har samma id-nummer måste man omdeniera equals i klassen Person.
Omdeniera equals
Specikation
public boolean equals(Object obj);
Ur equals specikation:
x.equals(x) ska returnera true (reexivitet).
Om x.equals(y) returnerar true så ska y.equals(x) returnera true (symmetri).
Om x.equals(y) returnerar true och y.equals(z) returnerar true så ska x.equals(z) returnera true (transitivitet).
x.equals(null) ska returnera false.
Omdeniera equals med instanceof
public boolean equals(Object obj) { if (obj instanceof Person) {
return idNbr == ((Person) obj).idNbr;
} else {
return false;
} }
Observera att parametern till equals måste vara av typ Object,
annars blir det inte skuggning. Därför måste också typomvandling till Person ske när man ska använda obj:s idNbr.
Uttrycket obj instanceof Person returnerar true om obj:s typ är Person eller någon subklass till Person.
Uttrycket obj instanceof Person returnerar false om obj har
Omdeniera (skugga) equals med instanceof
Fördelar och nackdelar
Uttrycket obj instanceof Person returnerar true om obj:s typ är Person eller någon subklass till Person.
Lösningen tillåter alltså att subklasser ärver equals-metoden.
Man kan använda equals i en arvshieariki och jämföra
subklassobjekt och superklassobjekt.
Kan leda till att equals inte uppfyller kraven i specikationen (om man t.e.x skuggar equals i subklassen).
Detta undviks om man bara tillåter jämförelser mellan objekt av samma typ. Se nästa bild.
Omdeniera equals med getClass
public boolean equals(Object obj) { if (obj == this) {
return true;
}if (obj == null) { return false;
}if (this.getClass() != obj.getClass()) { return false;
}return idNbr == ((Person) obj).idNbr;
}
Metoden getClass returnerar typen för det objekt obj refererar till under exekveringen.
Interfacet Comparable
Specikation
I Java nns ett generiskt interface, Comparable<T>:
public interface Comparable<T> {
/*** Compares this object with the specified object for order.
* Returns a negative integer, zero, or a positive integer as
* this object is less than, equal to, or greater than the
* specified object.
public int compareTo(T x);*/
}
Objekt av klasser som implementerar detta interface går att jämföra med varandra och kan t.ex. sorteras.
Implementering av interfacet Comparable
Exempel
public class Person implements Comparable<Person> { private String name;
private int idNbr;
...
public int compareTo(Person x) { return idNbr - x.idNbr;
}
public boolean equals(Object obj) { if (obj instanceof Person) {
return compareTo((Person) obj) == 0;
} else {
return false;
} }
Jämföra likhet
Metoderna compareTo och equals
Interfacet Comparable innehåller bara metoden compareTo.
Men för klasser som implementerar interfacet Comparable nns det två sätt att jämföra avseende likhet:
Person p1 = ...;
Person p2 = ;...
if (p1.compareTo(p2) == 0) {...}
if (p1.equals(p2)) {...}
Båda sätten att jämföra ska ge konsistenta resultat.
Därför bör metoden equals omdenieras i klasser som implementerar Comparable.
Implementering av interfacet Comparable
Övning
Övning
Ändra klassen Person så att den implementerar interfacet Comparable.
Jämförelsen av Person-objekt ska göras med avseende på namnet.
public class Person { private String name;
private int idNbr;
} ...
Typparametrar med begränsningar
Ibland behöver man ange begränsning på typparmetern:
public class ASortedCollection<E extends Comparable<E>>
<E extends T> betyder:
E måste vara subklass till T om T är en klass. Det är också tillåtet att E
= T.E måste implementera interfacet T om T är ett interface.
I exemplet ovan anger vi alltså att E måste vara en typ som
implementerar interfacet Comparable<E>. Vi kan därmed använda metoden compareTo på objekt av typen E i implementeringen av ASortedCollection.