• No results found

Mera om generik. Innehåll. Generik och arv Wildcards Vektorer och generik Generiska metoder. EDA690 (Mera om generik) HT / 24

N/A
N/A
Protected

Academic year: 2022

Share "Mera om generik. Innehåll. Generik och arv Wildcards Vektorer och generik Generiska metoder. EDA690 (Mera om generik) HT / 24"

Copied!
24
0
0

Loading.... (view fulltext now)

Full text

(1)

Mera om generik

Innehåll

Generik och arv Wildcards

Vektorer och generik Generiska metoder

(2)

Begreppet subtyp/supertyp i Java

Supertyper för en viss klass C är alla klasser från vilka C ärver och alla interface som klassen implementerar.

C är subtyp till alla sina supertyper.

Exempel:

class A {...}

class B extends A {...}

interface I {...}

class C extends B implements I{...}

C är här subtyp till B, A och I (och Object) B är subtyp till A (och Object)

(3)

Generik och arv

Antag att vi har en generisk klass G<E> och att vi har två klasser

class Person ...

class Student extends Person ...

Det gäller då inte att G<Student> är subtyp till G<Person>.

Varför?

(4)

Generik och arv

LinkedList<Student> ls = new LinkedList<Student>();

LinkedList<Person> lp = ls; // fel!

lp.add(new Person(...));

Tilldelningen på rad 2 hade varit tillåten om LinkedList<Student> vore subklass till LinkedList<Person>.

Vi kan då (som på rad 3) sätta in Person-objekt i listan ls (eftersom lp refererar till samma listobjekt som ls).

När vi skapar listan ls på rad 1 är avsikten att säkerställa att enbart objekt av typen Student eller subklasser av denna skall kunna sättas in.

Således ingen typsäkerhet längre. Därför är rad 2 illegal och ger kompileringsfel!

(5)

Generik och arv  raw type

Antag att vi har en generisk klass class G<T,U,V>.

Klassens grundtyp (eng: raw type) denieras då som G.

T ex är LinkedList grundtyp för LinkedList<E>.

Variabler som deklarerats med en viss grundtyp kan tilldelas värden som är vilken som helst av den parametriserade klassens instanser.

Ex:

LinkedList myList = new LinkedList<Integer>();

myList = new LinkedList<String>();

(6)

Generik och arv

Om S är subtyp till T och G är en generisk klass så gäller det inte att G<S> är subtyp till G<T>.

En parametriserad typ G1 är subtyp till en annan parametriserad typ G2 om och endast om

G1 och G2 har identiska värden på parametrarna.

R1 är subtyp till R2 där R1 är grundtyp för G1 och R2 är grundtyp för G2.

Ex:LinkedList<Integer> är subtyp till Collection<Integer>.

LinkedList<Integer> är inte subtyp till LinkedList<Object>.

(7)

Generik och arv

Försök att skriva en metod som skriver ut innehållet i en samling av godtycklig typ i Java 5.0:

public static void printCollection(Collection<Object> c) { for (Object e: c) {

System.out.println(e);

} }

Kan dock enbart anropas med en parameter som är subklass till

Collection<Object> t ex LinkedList<Object>

Kan inte anropas med t ex en parameter av typen

LinkedList<String>

(8)

Wildcards

Lösningen på problemet är att använda s.k. wildcards.

Collection<?> är superklass till Collection<E> för alla E.

? är wildcard. Collection<?> är en collection of unknown.

Vi kan nu implementera vår metod i java 5.0:

public static void printCollection(Collection<?> c) { for (Object e: c) {

System.out.println(e);

} }

Nu kan metoden anropas med objekt av godtycklig collection-klass t ex Collection<Object> eller LinkedList<String>.

(9)

Wildcards

Man kan också deklarera variabler av parametriserad typ med hjälp av wildcards:

Collection<?> myCollection = new LinkedList<String>();

Men man kan inte använda en sådan variabel för att lägga in element i samlingen:

myCollection.add(..) // fel!!

(10)

Typparametrar med begränsningar

Ibland behöver man ange begränsning på typparmetern till en generisk klass:

public class ASortedCollection<E extends Comparable<E>>

Typparametern <E extends T> betyder att

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 implementationen av ASortedCollection.

(11)

Typparametrar med begränsningar

Följande är ok, Integer implementerar Comparable:

ASortedCollection c = new ASortedCollection<Integer>();

Följande är ok, String implementerar Comparable:

ASortedCollection c = new ASortedCollection<String>();

Följande är ok, om Person implementerar Comparable, annars kompileringsfel:

ASortedCollection c = new ASortedCollection<Person>();

(12)

Wildcards med begränsningar

Utgå från följande klasshierarki:

public abstract class Shape { public abstract void draw();

}

public class Circle extends Shape { public void draw() { ... }

}

public class Rectangle extends Shape { public void draw() { ... }

}

Vi vill skriva en metod som ritar alla element som nns i en lista av

(13)

Wildcards med begränsningar

public static void drawAll(LinkedList<Shape> shapes) { for (Shape s: shapes) {

s.draw();

} }

Denna metod kan dock inte anropas med en parameter av typ LinkedList<Circle> t.ex myList:

LinkedList<Circle> myList = new LinkedList<Circle>();

ty LinkedList<Circle> är inte subklass till LinkedList<Shape>.

(14)

Wildcards med begränsningar

Genom följande utformning accepterar metoden listor av typ LinkedList<Shape>, LinkedList<Circle> eller

LinkedList<Rectangle>:

public static void drawAll(LinkedList<? extends Shape> shapes) { for (Shape s: shapes) {

s.draw();

} }

<? extends E> är exempel på wildcard med begränsning.

<? extends E> kan utläsas: okänd subklass till E. Detta inkluderar E.

(15)

Wildcards med begränsningar

<? extends E> är exempel på wildcard med övre gräns.

Det nns också användning för wildcard med undre gräns:<? super E>.

<? super E> kan utläsas som okänd superklass till E". Detta inkluderar E.

Exempel på användning på följande två bilder:

(16)

Wildcards med begränsningar

Ibland vill man uttrycka att en typpparameter E står för en typ som har jämförelseoperationer denierade d.v.s. implementerar interfacet Comparable.

Ex. Sorterad lista. En första ansats:

public class SortedList<E extends Comparable<E>> { ... }

(17)

Wildcards med begränsningar

Ofta för restriktivt att kräva att E implementerar Comparable<E>.

Ex.

class Person implements Comparable<Person> { ... } class Student extends Person { ... }

Nu kan vi inte skapa en sorterad lista för studenter (trots att studenter går att jämföra med varandra):

SortedList<Student> list = new SortedList<Student>();

eftersom Student inte implementerar Comparable<Student>.

(18)

Wildcards med begränsningar

Genom att i stället ge klassen följande utformning

public class SortedList<E extends Comparable<? super E>>

blir det möjligt att skapa en sorterad lista med studenter:

SortedList<Student> list = new SortedList<Student>(); (*)

E extends Comparable<? super E> kan utläsas E implementerar interfacet Comparable<T> där T är en okänd superklass till E (vilket inkluderar E).

Student implementerar Comparable<Person> och Person är superklass till Student. Därför är (*) nu korrekt

(19)

Vektorer och generik

Man kan deklarera vektorer med typparameter som elementtyp.

Man kan dock inte skapa vektorer där elementtypen är en typparameter.

public class MyStack<E> {

E[] contents; // OK att deklarera!

public Stack() {

contents = new E[100]; // men kompileringfel här!

}...

}

(20)

Vektorer och generik

I exemplet med klassen MyStack kan man göra så här:

public class MyStack<E> { E[] contents;

public Stack() {

contents = (E[]) new Object[100];

}...

}

Vilket dock ger en varning av kompilatorn!

(21)

Vektorer och generik

Man kan inte skapa en vektor där elementen är en parametriserad typ:

LinkedList<String>[] a; // OK att deklarera

a = new LinkedList<String>[10]; // fel att skapa!

Obegränsade wildcards dock OK:

LinkedList<?>[] a = new LinkedList<?>[10];

(22)

Generiska metoder

Även metoder kan ha typpparametrar:

public class Utilities {

/* Fyller alla platser i a med elementet x */

public static <T> void fill(T[] a, T x) { for (int i = 0; i < a.length; i++) {

a[i] = x;

} } } ...

Typparameter (en eller era) anges inom < och > före metodens returtyp.

(23)

Generiska metoder

Generiska metoder kan anropas utan att man explicit anger vad typen T är:

Utilities.fill(new Integer[10], new Integer(3));

Utilities.fill(new String[5], new String("abc"));

För det första anropet fastställer kompilatorn typen T till Integer och i det andra till String.

(24)

Generiska metoder

Antag att vi har en klass Student:

Student extends Person{ ... }

Det är då möjligt att anropa metoden enligt:

Utilities.fill(new Person[10], new Student());

Kompilatorn fastställer här T till att vara Person (gemensam superklass till Person och Student som gör anropat legalt).

References

Related documents

Jag behöver skicka ett brev till någon från kraftringen som får möjlighet att yttra sig över sanktionsavgiften. Vart kan jag

Strand, Sanna 2019: ReInventing the Armed Forces: A Governmentality Analysis of Swedish Military Marketing and Outreach in the Era of Voluntarism PhD dissertation in Peace

[r]

[r]

[r]

[r]

[r]

The aim of the work is to point out the possibilities of adapting the teaching process according to individual needs of pupils in a mixed-ability class and to propose strategies