Fetstil Fetstil Kursiv Understrykning linje färgläggning tabellverk Punktlista Nummerlista Vänster Centrerat högerställt Utfyllt Länk Bild htmlmode
  • Forum & Blog
    • Forum - översikt
      • .Net
        • asp.net generellt
        • c#
        • vb.net
        • f#
        • silverlight
        • microsoft surface
        • visual studio .net
      • databaser
        • sql-server
        • databaser
        • access
        • mysql
      • mjukvara klient
        • datorer och komponenter
        • nätverk, lan/wan
        • operativsystem
        • programvaror
        • säkerhet, inställningar
        • windows server
        • allmänt
        • crystal reports
        • exchange/outlook
        • microsoft office
      • mjukvara server
        • active directory
        • biztalk
        • exchange
        • linux
        • sharepoint
        • webbservers
        • sql server
      • appar (win/mobil)
      • programspråk
        • c++
        • delphi
        • java
        • quick basic
        • visual basic
      • scripting
        • asp 3.0
        • flash actionscript
        • html css
        • javascript
        • php
        • regular expresssion
        • xml
      • spel och grafik
        • DirectX
        • Spel och grafik
      • ledning
        • Arkitektur
        • Systemutveckling
        • krav och test
        • projektledning
        • ledningsfrågor
      • vb-sektioner
        • activeX
        • windows api
        • elektronik
        • internet
        • komponenter
        • nätverk
        • operativsystem
      • övriga forum
        • arbete karriär
        • erbjuda uppdrag och tjänster
        • juridiska frågor
        • köp och sälj
        • matematik och fysik
        • intern information
        • skrivklåda
        • webb-operatörer
    • Posta inlägg i forumet
    • Chatta med andra
  • Konto
    • Medlemssida
    • Byta lösenord
    • Bli bonsumedlem
    • iMail
  • Material
    • Tips & tricks
    • Artiklar
    • Programarkiv
  • JOBB
  • Student
    • Studentlicenser
  • KONTAKT
    • Om pellesoft
    • Grundare
    • Kontakta oss
    • Annonsering
    • Partners
    • Felanmälan
  • Logga in

Hem / Artiklar / Titel på artikeln

Generics i Java 1.5

Postad 2004-12-14 av Jens Gustavsson i sektionen ASP.NET, C#, Okategoriserat med 2 Kommentarer | Läst av: 7012, Betyg: 93%

Förord

I den här artikeln beskriver jag vad generics är och hur det fungerar i Java 1.5.
Innehåll
  » Vad är generics?
  » Java 1.5 löser problemet
  » Annat än datastrukturer?
  » Generics är komplext




Vad är generics?


Generics är den nyhet i Java 1.5 som är mest efterlängtad. På svenska heter det "typparametrisering", det hela handlar om att skapa en ny typ genom att ange en typ som parameter till en annan typ. Men låt oss börja med något begripligt, nämligen hur vi har klarat oss utan generics hittills.

Sedan länge innehåller paketet java.util många bra datastrukturer att lagra objekt med, som exempelvis ArrayList, HashMap, HashSet, LinkedList och Stack. Alla dessa olika datastrukturer för lagring är bra och nödvändiga. Dessutom kommer det alltid finnas behov av att hitta på nya applikationsspecifika datastrukturer. Före version 1.5 är datastrukturerna dåliga på att hålla ording på vad de lagrar. De kan lagra allt som är subklasser till Object, och eftersom alla klasser i Java är subklasser till Object kan de lagra vilka objekt som helst. För att lägga till och hämta ut objekt ur en List kan man använda följande metoder:


void add(Object o)
Object get(int index)


Eftersom add-metoden accepterar alla subklasser till Object som parameter går det utmärkt att lägga in bil-objekt i listan. Om man vill använda get-metoden till att hämta ut en bil är det inte riktigt lika enkelt. Eftersom get-metoden har returvärde av typen Object måste man typkonvertera returvärdet innan det kan användas som en bil. Exempel:


Bil b = (Bil) billistan.get(42);


Att med parentesen (Bil) tala om för datorn att det man får ut ut billistan verkligen är ett bilobjekt kan ju kännas lite löjligt om man själv vet att man bara stoppat in just bilar. Ännu löjligare känns det eftersom man vet att kompilatorn inte vet någonting om vad som finns i listan utan nöjer sig med en parentes som säger vad programmeraren påstår finns där. Kompilatorn har alltså ingen chans att protestera med ett "Hörrödudu, det kan faktiskt finnas cyklar och spårvagnar i din lista". Istället upptäcks sådana fel först när programmet körs, ett exception kastas då och äntligen får man veta att där kryllar av cyklar och spårvagnar. Att typfel inte upptäcks vid kompileringen är ett problem eftersom det ökar arbetet med att hitta en sådan bugg samtidigt som risken att en den inte upptäcks alls under utvecklingsarbetet ökar.

Ett sätt att lösa problemet är att skapa en klass som heter BilLista och som klarar av att lagra just bilar i en lista. Denna blir helt typsäker och det kan verifieras av kompilatorn. Typsäkerheten kommer av att metoderna för att lägga till och hämta ut bilar deklareras för att ta emot respektive returnera just bil-objekt:


void add(Bil b)
Bil get(int index)


Om någon övermodig programmerare nu försöker stoppa in en ynka liten spårvagn i listan kommer kompilatorn straffa denne direkt. En spårvagn är inte en bil och metoden add fungerar bara med bilar! Den stora nackdelen med att skapa en sådan klass är att det är jobbigt och sedan är det ännu jobbigare att underhålla den. Det skulle väl gå an om det bara behövdes några stycken sådana datastrukturer i ett system, men så är det inte. Datastrukturer för att lagra objekt är vanliga. Jättevanliga.

Arrayer, som till exempel Bil[], är ju också typsäkra. Kan man inte använda dem om nu typsäkerhet är så viktigt? Den enda nackdelen med dem är ju att de är just arrayer, med allt vad det innebär: det går inte att ändra antalet element som kan lagras, det är besvärligt att skjuta in ett objekt i mitten, för att hitta ett objekt kan man tvingas söka igenom hela arrayen etc. Det går inte att byta detta till lagring i länkad-lista, hashtabell, mängd etc. Arrayer härstammar från en tid då komplicerade datastrukturer var en lyx och det var en stor sak att skapa en hashtabell. Idag är hashtabeller vardagsmat.

OK, sammanfattning av problemet: Man vill på ett lätt sätt kunna skapa lagringsplatser för objekt. Hur objekten ska lagras ska kunna bestämmas från fall till fall och det ska vara lätt att ändra och att hitta på nya lagringssätt. Det ska också gå att bestämma vilken sorts objekt som ska lagras och inget annat än sådana objekt ska kunna stoppas in av misstag. Vi har alltså två dimensioner som ska kunna varieras oberoende av varandra: datastruktur respektive typ på det som ska lagras. Och det är alltså detta problem som kan lösas med generics i Java 1.5.




Java 1.5 löser problemet


Så här gör man med Java 1.5:


ArrayList minLista = new ArrayList();


Genom att låta ett klassnamn följas av större-än-och-mindre-än-hakar med ett typnamn mellan skapar man en ny så kallad parametriserad typ. Här skapar vi en ArrayList som kan lagra bilar. Det fiffiga är att för den nya typen som skapats kan man använda följande metoder:


void add(Bil b)
Bil get(int index)


Det innebär att det bara går att fylla listan med bilar. Vi har statisk typkontroll. Hurra! Kompilatorn kan säga till när vi gjort fel och vi slipper jaga buggar lika ofta som förut. Det går att använda de parametriserade typerna ungefär som vilka typer som helst, till exempel är följande metoddeklarationer möjliga:


public void parkera(ArrayList b) {...}
public List getEvents() {...}


Även om det mest kommer vara utvecklare av klassbibliotek som skapar parametriserade typer så kan det vara kul att se hur det går till. Låt oss skapa ett liten fånig typparametriserad klass som kan lagra ett endaste litet objekt. Så här kan den se ut:


class SillyStorage {
private T theObject;
public void set(T o) {theObject = o;}
public T get() {return theObject;}
}


Att klassen deklareras som class SillyStorage innebär att klassen kan typparametriseras med vilken typ som helst och T är namnet på typparametern. Överallt i klassen där T sedan används kan man se det som att T ersätts av den typ man typparametriserat med. Den andra raden i klassen är alltså en deklaration av ett fält med namnet theObject som är av den typ som klassen är parametriserad med. Vi ser också att T används som typ på parametrar och returvärden i klassen. Nu är det möjligt att skapa ett SillyStorage för en specifik typ och få statisk typkontroll när den sedan används. Så här ser det ut:


SillyStorage s;
s = new SillyStorage();
s.set(new Bil());
Bil b = s.get();




Annat än datastrukturer?


Hittills har jag låtsats som om typparametrisering är något som bara är till för att kunna använda olika datastrukturer för att lagra data. Och det kommer utan tvekan vara det vanligaste användningsområdet för generics i Java. Jag kan avslöja att det går att typparametrisera vilka klasser som helst. Men generics i Java är inte speciellt användbara om man vill göra något spännande med sin typparameter, som till exempel att skapa ett objekt med den. Det är inte tillåtet att ändra den första raden i SillyStorage så här:


private T theObject = new T(); // Ej tillåtet


Om man vill anropa metoder på theObject är man begränsad till metoder som finns i klassen Object, eftersom kompilatorn inte förstår när andra anrop är korrekta. Det går att mildra detta problem genom att sätta begränsningar på vilken typ T får vara så här:


class SillyStorage {
...


Detta betyder att typparametern måste vara Fordon eller någon subklass till Fordon. Nu är man bara begränsad till metoder som finns i klassen Fordon. Dessa begränsningar gör att generics i Java lämpar sig bäst för klasser som inte behöver veta speciellt mycket om typparametern. Detta begränsar. Jag har svårt att se hur det kan användas till mycket annat än till datastrukturer och andra saker som hanterar objekt utan att göra något roligt med dem.




Generics är komplext


I den här beskrivningen har jag bara förklarat grundprinciperna för generics. Det finns mycket mer att veta, som till exempel att man kan typparametrisera metoder och att man kan använda jokertecken i vid typparametrisering (en variabel som deklareras som ArrayList kan referera till alla sorts ArrayListor av Fordon och dess subtyper). När man leker vidare med generics inser man att det kan bli ganska komplext. Mina exempel hittills har ju varit ganska enkla, men det finns gott om möjligheter att bli förvirrad. Till exempel kan man intuitivt tro att en metod som förväntar sig något av typen ArrayList som parameter ska acceptera en ArrayList. Men det gör den inte. Läs Generics in the Java Programming Language för att förstå varför (tips: vad händer om metoden vill lägga till en spårvagn i listan?). Efter att ha läst den kommer du också veta varför new ArrayList().getClass() == new ArrayList().getClass(). Tar man en titt i klassbiblioteket kan man också få se en del saker som tar ett tag att fundera ut vad de betyder. Hur många programmerare kommer någonsin förstå en sådan här metoddeklaration (som finns i klassen java.util.Collections):


public static > T
max(Collection coll) {...}


Att få starkare typkontroll är bra. Det låter oss hitta vissa fel redan vid kompileringstillfället. Frågan är om man inte på köpet fått ett annat stort problem: komplexitet. Kod som innehåller generics kan vara svårare att läsa och förstå än kod utan. Jag ser en risk att den ökade komplexiteten i språket kommer leda till att färre programmerare verkligen kommer behärska Java. Något som kan straffa sig i form av fler fel i programmen, vilket ju är precis vad generics ska motverka. Men förhoppningsvis räcker det för vanliga dödliga programmerare att förstå hur man skapar länkade listor med bilar och spårvagnar. De besvärliga detaljerna blir då bara något extra spännande att bita i för klassbibliotekskonstruktörer. Man kan ju alltid hoppas.

Titta gärna in till min blogg: www.jensgustavsson.se
Upp

2 Kommentarer


  1. Simon Dahlbacka
    21 dec 2004

    Mycket intressant ämne, och väldigt välskriven. Misstänker att jag återkommer till denna när jag jobbar med java nästa gång.


  2. Johan Kristensen
    3 sep 2006

    Jag håller inte riktigt med om att komplexiteten skulle vara ett problem. Välskrivna generiska klassbibliotek gör istället klientkoden enklare att läsa. Och t.o.m exemplet på metoddeklaration du visar i slutet är ganska logisk. Jag undrar dock om det verkligen är nödvändigt att ange att T är en subklass till Object.

Skriv en kommentar på artikeln

Ditt betyg på artikeln



Kommentar:





Nyligen

  • 09:09 Vill du köpa medicinska tester?
  • 12:47 Vem beviljar assistansen – kommune
  • 14:17 Någon med erfarenhet av hemstädnin
  • 14:14 Bör man använda sig av en båtförme
  • 14:12 Finns det någon intressant hundblo
  • 14:25 Tips på verktyg för att skapa QR-k
  • 14:23 Tips på verktyg för att skapa QR-k
  • 20:52 Fungerer innskuddsbonuser egentlig

Sidor

  • Hem
  • Bli bonusmedlem
  • Läs artiklar
  • Chatta med andra
  • Sök och erbjud jobb
  • Kontakta oss
  • Studentlicenser
  • Skriv en artikel

Statistik

Antal besökare:
Antal medlemmar:
Antal inlägg:
Online:
På chatten:
4 569 159
27 952
271 704
1 069
0

Kontakta oss

Frågor runt konsultation, rådgivning, uppdrag, rekrytering, annonsering och övriga ärenden. Ring: 0730-88 22 24 | pelle@pellesoft.se

© 1986-2013 PelleSoft AB. Last Build 4.1.7169.18070 (2019-08-18 10:02:21) 4.0.30319.42000
  • Om
  • Kontakta
  • Regler
  • Cookies