© 1999-2003, Flemming Koch Jensen
Alle rettigheder forbeholdt
Wrapper klasser

 

 

Lapper Man fristes til at sige, at det ikke er nogen tilfældighed at wrapper (dk.: en person, der pakker ting ind) rimer på lapper (i det mindste på papiret). Wrapper klasser eksisterer primært for at lappe på Java's manglende objektorientering. Det drejer sig om Java's primitive typer: int, char, boolean, double osv. Erklærer man f.eks. en integer variabel:
int x=5;
ligger der et problem og lurer. x er hverken et objekt eller en reference til et objekt - den er bare en variabel, der kan antage en talværdi. I de fleste situationer er det ikke noget problem, og flere vil endog betragte det som objektorienteret hysteri at gøre det til et problem. Desværre er det et temlig upraktisk problem når det endelig viser sig.
Container Behovet for at variable som x skulle være et objekt opstår primært i forbindelse med containere. F.eks. kan Collection-klasser i java.util kun arbejde med objekter, så en linket liste af heltal kan ikke umiddelbart lade sig gøre.
F.eks. kan man ikke placere tallene fra 1 til 10 i en linket liste med:
LinkedList list = new LinkedList();
for ( int i=1; i<=10; i++ )
  list.add( i );
da LinkedList's add-metode kun kan tage et Object som parameter.
Det er i sådanne situationer man kan bruge wrappere. Vi udskifter den sidste linie med:
list.add( new Integer( i ) );
Integer Vi anvender her set-konstruktoren for klassen Integer. Integer er en wrapper klasse, dvs. en klasse hvis instanser kun har til formål at indeholde noget andet (pakke det ind). Man kunne også kalde det en "single-container", fordi den kun kan indeholde ét element.
Mulighederne for at arbejde med en Integer er meget begrænsede - wrapper-klasserne er alle immutable. Integer-objektet er kun en indpakning, og vil man bruge talværdien til noget, må man hente den ud igen.

Antag f.eks. at vi ønsker at gennemløbe listen og inkrementere samtlige tal. Så kan man naturligvis godt glemme alt om:

for ( int i=1; i<=10; i++ )
  ((Integer) list.get( i ))++;
og der er som nævnt ingen metoder i Integer der kan hjælpe os. Så følgende er også udelukket:
for ( int i=1; i<=10; i++ )
  ((Integer) list.get( i )).inc();
Derimod skal vi igennem følgende for at få den ønskede inkrementering:
for ( int i=0; i<list.size(); i++ ) {
  int tal = ((Integer) list.get( i )).intValue();
  list.set( i, new Integer( tal+1 ) );
}
Først skal vi hente talværdien ud fra wrapper'en. Så skal der laves en ny wrapper til den nye værdi, og den sættes ind i listen hvor den gamle wrapper var.
Andet end wrappere Som man kan se har wrappere ikke det store at byde på, når det drejer sig om at arbejde med deres indhold. Dermed er historien om wrappere dog ikke slut. Klasserne har andre ting at byde på, vedrørende de primitive typer, de på sin vis repræsenterer.
Inden vi studerer disse muligheder vil vi først have et overblik over hvilke wrappere der findes, og hvilke primitive typer de repræsenterer:
Wrapper
Type
Boolean boolean
Character char
Byte byte
Short short
Integer int
Long long
Float float
Double double
Man bemærker at wrapper klasserne for char og int har typens uforkortede navn.
Klasserne befinder sig i java.lang, og kan som andre klasser indplaceres i et nedarvnings-hierarki:
Figur 1:
wrapper klasserne
Man kan her undre sig over, at det ikke er Number, men dens subklasser, der implementer Comparable. Selv om Number har andre subklasser end de her nævnte, realiserer de alle Comparable.
 
Alle wrappere har følgende konstruktorer:
Konstruktorer

En set-konstruktor, der tager den primitive type som parameter

En konstruktor, der tager en tekststreng som parameter, og konverterer denne tekst til den primitive datatype (Character har dog ikke denne konstruktor). Hvis det ikke er muligt at konvertere teksten kaster den en NumberFormatException.

Da wrappere er immutable har de naturligvis ikke nogen set-metoder, men de har alle en get-metode:
get-metode
<type> <type>Value()
hvor <type> er den primitive types navn. F.eks. har Integer følgende get-metode:
int intValue()

 

Number's subklasser

Alle de numeriske wrappere har følgende statiske metoder, der ofte bruges til at konvertere et tekst-input til en talværdi:
<type> parse<type>( String s )
F.eks. har Integer metoden:
int parseInt( String s )
idet man følger den normale navne-konvention med store og små bogstaver i metode-navne.
Alle numeriske wrappere har også to statiske konstanter:
<type> MAX_VALUE
<type> MIN_VALUE
som er henholdsvis den største og den mindste værdi for den pågældende primitive type.
 
Heltals-wrapperne: Integer og Long har nogle kraftfulde statiske toString-metoder der retter sig mod andre talsystemer:
Binær, octal og hex
String toBinaryString( <type> value )
String toOctalString( <type> value )
String toHexString( <type> value )
Mere generelt har Integer og Long en statiske metode, der tager grundtallet (kaldes radix), som parameter:
String toString( <type> value, int radix );
Der anvendes 2. komplement, idet der ved negative tal fyldes ud til den primitive types "binære bredde".
 
De numeriske wrappere har også andre statiske konstanter og metoder, men vi vil udelade dem her, da de enten er meget specielle eller redundante.

 

Character

Første og fremmest har Character to statiske metoder til at at konvertere et tegn til henholdsvis stort eller lille:
char toLowerCase()
char toUpperCase()
Dernæst har Character en lang række boolske metoder til klassifikation af tegn. Vi vil her nævne de mest relevante:
boolean isDigit( char c )
Om c er et ciffer ('0'...'9')
boolean isLetter( char c)
Om c er et bogstav
boolean isLetterOrDigit( char c )
Om c er et bogstav eller et ciffer
boolean isLowerCase( char c )
Om c er et lille bogstav
boolean isUpperCase( char c )
Om c er et stort bogstav
boolean isWhiteSpace( char c )
Om c er et mellemrum, tabulering er linieskift
 
Nødvendigt onde Set med objektorienterede øjne er Java's wrappere megen dårligdom samlet på et sted, men vil man skrive Java-programmer, er der ingen vej uden om at bruge dem. De er der for at løse nogle problemer der er reelle nok.