programmera.net -> java -> normal     för utskrift      info@programmera.net

Datatyper

1. Nyckelord
2. Litterärer
3. Initiering
4. Explicit typkonvertering
5. Implicit konvertering
6. Speciella implicita konverteringar
7. Talbaser
8. Char

1. Nyckelord

Det finns 8 nyckelord som har att göra med typer. I Java finns det 8 primitiva typer, som alltså inte är klasser utan faktiskt minnesallokeringar. I tabellen nedan använder jag komma (,) mitt i stora tal för att man lättare ska kunna se hur stora de är (på amerikanskt vis):

Datatyp Bitar Default Beskrivning
boolean  -  false  true,false
byte  8  0 (noll)  -2^7 till 2^7-1 (-128 till 127)
short  16  0 (noll)  -2^15 till 2^15-1 (-32,768 till 32,767)
char  16  0 (noll)  0 till 2^16 (0 till 65,536)
int  32  0 (noll)  -2^31 till 2^31-1 (-2,147,483,648 till 2,147,483,647)
long  64  0 (noll)  -2^63 till 2^63-1 (-9,223,372,036,854,775,808 till 9,223,372,036,854,775,807)
float  32  0.0 (noll)  10^-45 till 10^38
double  64  0.0 (noll)  10^-324 till 10^308

Typen boolean kan anta true och false, som är reserverade ord.

2. Litterärer

En litterär är data som skrivs ut i klartext i programmet, t.ex. 17. Nedan ges exempel på olika litterärer och hur Java tolkar dessa literärer. Vi listar några olika litterärer och deras respektive typ:

Litterär Datatyp Beskrivning
17  int  Ett heltal blir automaitskt int.
017  int  Ett heltal som börjar på 0 tolkas med basen 8 (=15).
0x17  int  Ett heltal som börjar på 0x tolkas med basen 16 (=23).
17L  long  Vill man ha en long måste talet sluta på L/l.
0x17L  long  Ett heltal som börjar på 0x tolkas med basen 16 (=23). L/l förvandlar litterären till long.
17.0  double  Ett decimaltal blir automatiskt en double.
17.0F  float  Vill man ha en float måste talet sluta på F/f.
17F  float  Även heltal omvandlas med F/f.
0x17F  int  För heltal med basen 16 förvandlar F/f ej litterären till float (=383).
true  boolean  Detta nyckelord är en boolean.
false  boolean  Detta nyckelord är en boolean.
'a'  char  Tecken inom enkelfnuttar är char.
'\u00A0'  char  Detta representerar ett Unicodetecken.

Några regler som kan läggas på minnet är:

  • Heltal som slutar på L eller l omvandlas till typen long.
  • Tal (ej basen 16) som slutar på F eller f omvandlas till typen float.

3. Initiering

De primitiva typerna kan initieras på följande vis:

  • 1. Med en variabel eller ett uttryck.
  • 2. Med en litterär.
Följande exempel visar hur initiering med litterär kan gå till.
class TestLiteralInit{
  public static void main(String[] args){
    int i=4; 
    long l=4L, k=0xF2L; 	
    float f=4F; 
    double d=4.1; 
    char c='a'; 
    System.out.println("i="+i+" l="+l+" k="+k+" f="+f+" d="+d+" c="+c);
  } 
}
Vi får utskriften:
[olle@dev1]$ java TestLiteralInit
	i=4 l=4 k=242 f=4.0 d=4.1 c=a

4. Explicit typkonvertering

Om en typ ska konverteras till någon annan kan man göra det explicit, dvs. att man skiver ut den nya typen inom parantes precis efter likamedtecknet. Typer kan konverteras hur som helst sinsemellan, utom i fallet boolean. boolean kan inte konverteras till eller från någon annan typ. Här kommer ett exempel på en explicit konvertering:
class TestTypeConvert{
  public static void main(String[] args){
    int i=(int) 4.3; 
    System.out.println("i="+i);
  } 
}
Vi kör programmet och får följande:
[olle@dev1]$ javac TestTypeConvert
i=4
Här konverterades 4.3 till 4 och vi förlorade den data som kom efter decimaltecknet. Detta sker utan att JVM eller kompilatorn klagar. Ibland då man använder denna typ av konvertering försvinner information utan att man har tänkt på det:
class TestDataLoss{
  public static void main(String[] args){
    int i=257;
    byte b=(byte) i;
    i=(int) b;
    System.out.println("i="+i);
  } 
}
När vi kör programmet händer följande:
[olle@dev1]$ java TestDataLoss
i=1
Anledningen till dataförlusten är att talet 257 är större än 127 som är det största tal byte kan innehålla. Tänker man binärt har 257 den nionde biten satt till ett. Då int konverteras till en byte försvinner alla bitar utom de 8 minst signifikanta. Detta blir lättare att se om vi skriver ut bitarna:
class TestDataLoss2{
  public static void main(String[] args){
    int i=257;
    System.out.println("i binary="+Integer.toBinaryString(i));
    byte b=(byte) i;
    System.out.println("b binary="+Integer.toBinaryString(b));
    i=(int) b;
    System.out.println("i binary="+Integer.toBinaryString(i));
    System.out.println("i="+i);
  } 
}
Vi testkör programmet och får:
[olle@dev1]$ java TestDataLoss2
i binary=100000001
b binary=1
i binary=1
i=1

5. Implicit konvertering

Genomgående i Java är det alltid går att implicit konvertera till en typ med större räckvidd (fler bitar), en så kallad breddande konvertering. Dessa är reglerna för tillåtna implicita breddande konverteringar:

  • Heltal kan implicit breddas till ett annat heltal med större räckvidd.
  • Heltal kan implicit breddas till float.
  • float kan implicit breddas till double.
  • Ingenting kan implicit konverteras till char, eftersom andra typer kan vara negativa, men char kan implicit breddas till int eller större.
Då man breddar ett heltal förlängs den mest signifikanta biten så att den fyller upp alla nya bitar. Här går ingen information förlorad, men då man breddar ett heltal till ett flyttal kan information i de minst signifikanta bitarna försvinna. Nedan ges ett exempel på implicita breddningar:
class TestConvert{
  static void foo(float f){
    System.out.println("foo f="+f);
  }
  public static void main(String[] args){
    byte b=17;

    short s=b;
    int i=s;
    long l=i;
    foo(l);
    float f=l;
    double d=f;

    char c=12;
    i=c; //char to int
    f=2; //int to float
    d=2; //int to double
  }
}
Vi kör programmet:
[olle@dev1]$ java TestConvert
foo f=17.0

6. Speciella implicita konverteringar

När man initierar en primitiv typ med en litterär görs ofta konverteringar som normalt inte är tillåtna. Det är för att kompilatorn direkt kan avgöra om en konvertering kan ske utan att data förloras. De speciella implicita konverteringar som kan göras är:

  • En byte kan initieras med en litterär int.
  • En short kan initieras med en litterär int.
  • En char kan initieras med en litterär int.
Här kommer ett exempel:
class TestToPrimitive{
  public static void main(String[] args){
    byte b=17;
    char c=117;
    System.out.println("c="+c);
  }
}
Vi kör programmet:
[olle@dev1]$ java TestToPrimitive
c=u
När man försöker initiera en typ utanför dess räckvidd får man ett kompileringsfel:
class TestBound{
  public static void main(String[] args){
    byte b=128;
  }
}
Vid kompileringen sker följande:
[olle@dev1]$ TestBound.java:3: possible loss of precision
found   : int
required: byte
byte b=128;

1 error

7. Talbaser

När det gäller heltal används automatiskt talbasen 10, men om man vill kan man specifiera talbasen 16 (hexadecimalt) eller 8 (oktalt).

  • Oktala tal= Heltal som börjar med en nolla översätts till basen 8. Hela talet måste bestå av siffror mellan 0 och 7.
  • Hexadecimala tal= Tal som börjar med 0x översätts till basen 16. Hela talet måste bestå av "siffror" mellan 0 och F.
Ett exempel:
class TestBase{
  public static void main(String[] args){
    int okt=010;
    int hex=0x10;
    System.out.println("okt="+okt);
    System.out.println("hex="+hex);
  }
}
Kör man detta program får man följande resultat:
[olle@dev1]$ java TestBase
okt=8
hex=16

8. Char

Eftersom char är ett 16-bitars postivt heltal konverteras minustal till heltal. Klassen TestChar demonstrerar konvertering av negativa heltal till char.
class TestChar{
  public static void main(String[] args){
    int i=117;
    char c=(char) i;
    System.out.println("c="+c);

    int j=-117;
    char d=(char) j;
    j= (int) d;
    System.out.println("d="+d+" j="+j);
  }
}
Vid en körning av följande program får vi denna utskrift:
[olle@dev1]$ java TestChar
c=u
d=? j=65419
Alltså, -117 konverteras inte till 117 då det blir en char. Om du vill skriva ut W finns det 3 sätt:
class TestChar2{
  public static void main(String[] args){
    char c1='\u0057';
    char c2=(char) 87;
    char c3='W';
    System.out.println("c1="+c1);
    System.out.println("c2="+c2);
    System.out.println("c3="+c3);
  }
}
Vid en körning händer följande:
[olle@dev1]$ java TestChar2
c1=W
c2=W
c3=W
Det enklaste sättet att skriva en char är som i c3, att man skriver själva tecknet. Men vissa tecken är lite speciell måste skrivas på följande sätt:

Tecken Beskrivning
\b  backspace
\t  tab
\n  newline
\f  formfeed
\r  carriage return
\"  double quotation mark
\'  single quotation mark
\\  backslash
'\uXXXX'  Ett Unicodetecken. XXXX är hexadecimalt mellan 0000 och FFFF. Detta är det enda sättet att skriva in ett 16 bitars Unicodetecken.
\XXX  En char. XXX är oktalt mellan 000 och 377.