Objekte und Arbeitsspeicher Grundsätzliches: Im Arbeitsspeicher werden Daten gespeichert. Um auf die Daten eindeutig zugreifen zu können, werden diesen Daten Adressen zugeordnet. Diese sind fest eingebrannt und können nicht durch ein Programm verändert werden. Verändert werden können nur die Daten. Vergleich: Jedes Haus hat eine feste Adresse, die von einem Amt fest vorgegeben werden und vom Hauseigentümer nicht verändert werden dürfen. Nur die in jedem Haus wohnenden Menschen können geändert werden (z.B. Wohnungswechsel). Man kann sich einen Arbeitsspeicher schematisch wie folgt vorstellen: Ausschnitt aus einem Arbeitsspeicher Fest eingebrannte, unveränderliche Werte Adresse 0 1 2 3 4 ... ... Wert ... ... ... ... ... ... ... veränderliche Werte (die durch ein Programm geändert werden können). Wenn nichts anderes angegeben wird, besteht der Wert immer aus 1 Byte. Also ist 1 Byte die kleinste adressierbare Speichereinheit. Wann werden Variablen automatisch initialisiert (d.h. einer Variable das erste Mal ein Wert zugewiesen) d.h. wann werden Variablen automatisch initialisiert, wann nicht? 1) Jede lokale Variable (innerhalb einer Methode) hat - wenn ihr kein Wert zugewiesen wurde - einen unbestimmten, undefinierten, dem Programmierer nicht bekannten Wert. Deshalb muss sie vom Programmierer vor einer lesenden Verwendung initialisiert werden, da es sonst einen Fehler beim Kompilieren gibt. Beispiel public class MainKlassen1 { public static void main(String[] args){ int j; Dies sind die lokalen Variablen int i; System.out.println("i= "+i); i=j; Hund myh1; System.out.println("myh1= "+myh1); System.out.println("myh1.getGewicht()" +myh1.getGewicht()); i=5; Welches sind die lokalen Variablen des Programms j=7; (der Methode main)? } Welche Fehler hat also dieses Programm? } class Hund{ // wie vorher } public class MainKlassen1 { public static void main(String[] args){ int j; Fehler: i wird ausgelesen (ausgewertet), int i; ohne vorher initialisiert worden zu sein. System.out.println("i= "+i); i=j; Fehler: myh1 (exakter: Adresse) wird ausgelesen Hund myh1; (ausgewertet), ohne vorher initialisiert worden zu sein. System.out.println("myh1= "+myh1); System.out.println("myh1.getGewicht()" +myh1.getGewicht()); i=5; Fehler: auf getGewicht() wird zugegriffen; damit j=7; wird auch myh1 ausgelesen (ausgewertet), ohne } vorher initialisiert worden zu sein. } Fehler: j wird ausgelesen (ausgewertet), class Hund{ ohne vorher initialisiert worden zu sein und // wie vorher wird dann i zugewiesen. } 2) Wenn dagegen (mit new) ein Objekt einer Klasse erzeugt wird, werden automatisch (d.h. ohne Zutun des Programmierers) alle Attribute dieses gerade erzeugten Objekts wie folgt initialisiert: Datentyp boolean char byte short int long float double Referenz standardmäßige Vorbelegung false \u0000 0 0 0 0L 0.0f 0.0 null wird später erklärt Durch die Deklaration einer Variable (mit primitivem Datentyp) wird im Arbeitsspeicher an einer bestimmten Adresse Platz reserviert. Wird zusätzlich bei der Deklaration die Variable noch z.B. mit 5 initialisiert, bekommt der Wert an dieser Adresse 5 zugewiesen. Wird die Variable nicht initialisiert, ist der Wert an dieser Adresse unbestimmt (undefiniert). Beispiel einer Variablen mit primitivem Datentyp: Die unbekannte double Zahl braucht 8 Byte. public static void main(...){ double myGewicht; myGewicht //... } Was veranlasst diese Anweisung im Arbeitsspeicher ? Es wird im Arbeitsspeicher an einer bestimmten Adresse Platz für die double-Zahl mit Namen myGewicht reserviert, die einen dem Programmierer nicht bekannten Wert hat Auf die (Anfangs)Adresse dieses Speicherbereichs hat der Programmierer keinen Einfluß. Diese legt der Interpreter bzw. Programmlader fest. Adresse ... 0120 0121 0122 0123 0124 0125 0126 0127 ... Wert Noch ein Beispiel einer Variablen mit primitivem Datentyp: double braucht 8 Byte. Wie diese Zahl auf die 8 Byte verteilt wird, ist für uns uninteressant public static void main(...){ double myGewicht=3.14159; myGewicht //... } Was veranlasst diese Anweisung im Arbeitsspeicher ? Es wird im Arbeitsspeicher an einer bestimmten Adresse Platz für die double-Zahl mit Namen myGewicht reserviert und die Zahl 3.14159 der Variablen myGewicht zugewiesen. Auf die (Anfangs)Adresse dieses Speicherbereichs hat der Programmierer keinen Einfluß. Diese legt der Interpreter bzw. Programmlader fest. Adresse ... 0120 0121 0122 0123 0124 0125 0126 0127 ... Wert Beispiel einer Variablen mit einem Klassentyp: Adresse Wert ... myh1 0120 ... ? Ein Zeiger ist vergleichbar mit einer Verknüpfung auf dem Desktop, mit einem Link auf einer Website oder mit einer Hundeleine, die auf den Hund zeigt. Ein Zeiger ist eine Variable, deren Wert die Anfangsadresse eines Speicherplatzes (z.B. einer Variable oder Objekt) ist. Es wird im Arbeitsspeicher an einer public static void main(...){ bestimmten Adresse Platz für den Hund myh1; Zeiger (Referenz, Verweis, Pointer) myh1=new Hund(); mit Namen myh1 reserviert. myh1.setName("Goldi"); myh1.setGewicht(12); Was veranlasst diese Deklaration } im Arbeitsspeicher ? Adresse Wert ... myh1 0120 ... ? Weil myh1 eine lokale Variable ist, ist der Wert undefiniert. ? hat natürlich einen konkreten, uns unbekannten Wert, der mehrere Bytes groß ist (und nicht wie hier angedeutet nur 1 Byte verbraucht). Diese Interna brauchen uns nicht zu interessieren. Ein Zeiger ist eine Variable, deren Wert die Anfangsadresse eines Speicherplatzes (z.B. einer Variable oder Objekt) ist. Es wird im Arbeitsspeicher an einer Auf die (Anfangs)Adresse public static void main(...){ bestimmten Adresse Platz für den dieses Speicherbereichs hat Hund myh1; Zeiger (Referenz, Verweis, Pointer) dermyh1=new Programmierer keinen Hund(); mit Namen myh1 reserviert. Einfluß. Diese legt der myh1.setName("Goldi"); Interpreter bzw. myh1.setGewicht(12); Was veranlasst diese Deklaration Programmlader fest. } im Arbeitsspeicher ? Adresse Wert dieses Auf die (Anfangs)Adresse Speicherbereichs ... hat der Programmierer keinen Einfluß. Diese legt der Interpreter myh1 bzw. Programmlader ? 0120 fest. Adresse Wert ... 0470 ... Was veranlasst diese Anweisung im Arbeitsspeicher ? Es wird im Arbeitsspeicher an einer bestimmten Adresse Platz für das Objekt erzeugt, auf das myh1 zeigen soll. public static void main(...){ Hund myh1; Ausmyh1=new Platzgründen wird hier der Hund(); Arbeitsspeicher auf 2 Tabellen verteilt, myh1.setName("Goldi"); obwohl eigentlich der ganze Speicher myh1.setGewicht(12); durch eine Tabelle dargestellt wird! } ? Speicherbedarf für das Objekt (Näheres dazu gleich) MERKE Bei einer Variablen mit einem Klassentyp wird beim Zugriff auf diese Variable nicht das Objekt, sondern ein Zeiger auf dieses Objekt verwendet. Wie viel Byte Speicher ein Zeiger (=Adresse) benötigt ist in der JLS (Java Language Specification) nicht festgelegt und braucht uns nicht zu interessieren. Adresse Wert ... myh1 0120 ... Adresse Wert ... ? 0470 ? public static void main(...){ Hund myh1; myh1=new Hund(); myh1.setName("Goldi"); Welchen Wert muss myh1 myh1.setGewicht(12); bekommen, damit es auf das } gerade angelegte Objekt zeigt? Adresse myh1 Wert Adresse ... ... 0120 ... 0470 public static void main(...){ Hund myh1; myh1=new Hund(); myh1.setName("Goldi"); myh1.setGewicht(12); } ? Wert Adresse myh1 Wert Adresse ... ... 0120 0470 ... 0470 public static void main(...){ Hund myh1; myh1=new Hund(); myh1.setName("Goldi"); myh1.setGewicht(12); } ? Wert Adresse myh1 Wert Adresse ... ... 0120 0470 ... 0470 Wir erinnern uns... Die Klasse Hund hat die Attribute: private String name; private double gewicht; public static void main(...){ Hund myh1; myh1=new Hund(); myh1.setName("Goldi"); Aus was besteht dann dieser myh1.setGewicht(12); }Speicherbereich (Struktur)? ? Wert Adresse Wert Adresse ... ... 0120 0470 Da dem ... Attribut noch kein Wert myh1 zugewiesen wurde, bekommt es standardmäßig den Wert 0 (siehe Merksatz frühere Folie) Hier wird das Attribut gewicht vom Typ double abgespeichert. gewicht public static void main(...){ Hund myh1; myh1=new Hund(); myh1.setName("Goldi"); myh1.setGewicht(12); } 0470 ... 0473 0474 ... 0481 Wert Adresse Da für das Objekt noch kein Speicher angelegt wurde, hat der Adresse Wert Zeiger den Wert... ... ... myh1 0120 0470 ... Zeiger auf name ein Zeiger auf ein Objekt abgespeichert. ... eine Klasse ist. Bei Variablen gewicht mit einem Klassentyp wird nicht das Objekt, sondern ... public static void main(...){ Hund Hier wird myh1; nicht das Attribut name vom Typ myh1=new Hund(); String abgespeichert, weil String ... myh1.setName("Goldi"); Wasmyh1.setGewicht(12); steht als Wert in diesem } Speicherbereich? 0470 ... 0473 0474 ... 0481 Wert myh1 Adresse Adresse Wert ... 0120 0470 ... Was veranlasst diese Anweisung im Arbeitsspeicher ? Wert Adresse Wert ... 0470 ... 0473 0474 ... 0481 public static void main(...){ Hund myh1; myh1=new Hund(); myh1.setName("Goldi"); myh1.setGewicht(12); Wir erinnern uns... Adresse Adresse Wie viel ByteWert die Zeichenkette "Goldi" ... belegt, weiß ich nicht. Dies ist für0470 uns auch 0120 uninteressant. ... ... Die Zeichenkette (=Objekt) "Goldi" steht irgendwo im Arbeitsspeicher (wo, wissen wir nicht, dies legt Interpreter bzw. Programmlader fest. Speicherbereich für Objekt Goldi 0470 ... 0473 0474 ... 0481 Wert Adresse Wert 0800 ... ... Was geschieht beim Aufruf dieser Methode? public static void main(...){ Hund myh1; myh1=new Hund(); myh1.setName("Goldi"); myh1.setGewicht(12); Was geschieht jetzt? Der konkreteWert Wert des Adresse Input-Parameters ... die Adresse (nämlich des Objekts0470 "Goldi") 0120 wird in den formalen ... pName Parameter kopiert. Welchen Wert hat also pName? Adressehat pname Wert Warum nicht den Wert ... "Goldi"? Adresse Wert 0470 0800 ... MERKE ... Bei einer Variablen mit einem 0473 ... Klassentyp wird beim Zugriff 0474 auf diese Variable nicht das ... sondern ein Zeiger auf Objekt, dieses 0481Objekt verwendet. public void setName(String pName){ public static void main(...){ name = pName; 0800 Hund myh1; } 0800 0800 myh1=new Hund(); myh1.setName("Goldi"); myh1.setGewicht(12); Attribut name Adresse Adresse ... Wert ... 0120 0470 ... Welche Variable befindet sich hier? Wert 0470 0800 ... 0473 0474 ... 0481 Adresse Wert 0800 ... ... Welchen Wert hat also das Attribut name? public void setName(String pName){ public static void main(...){ name = pName; 0800 Hund myh1; } 0800 0800 myh1=new Hund(); myh1.setName("Goldi"); myh1.setGewicht(12); Was veranlasst diese Anweisung im Arbeitsspeicher ?Adresse Der konkrete Wert des Input-Parameters (nämlich 12) wird in den formalen Parameter pGewicht kopiert. Adresse Wert ... myh1 0120 0470 ... gewicht public static void main(...){ Hund myh1; myh1=new Hund(); myh1.setName("Goldi"); myh1.setGewicht(12); } ... 0470 ... 0473 0474 ... 0481 Wert public void setGewicht(double pGewicht){ Adresse gewicht = pGewicht; ... } Wir erinnern uns... Adresse Wert ... myh1 0120 0470 ... gewicht public static void main(...){ Hund myh1; myh1=new Hund(); myh1.setName("Goldi"); myh1.setGewicht(12); } 0470 ... 0473 0474 ... 0481 Wert public void setGewicht(double pGewicht){ Adresse gewicht = pGewicht; 12 ... 12 } 12 Welchen Wert hat also pGewicht? Adresse Wert ... myh1 0120 0470 ... gewicht public static void main(...){ Hund myh1; myh1=new Hund(); myh1.setName("Goldi"); myh1.setGewicht(12); } 0470 ... 0473 0474 ... 0481 Wert public void setGewicht(double pGewicht){ Adresse gewicht = pGewicht; 12 ... 12 } 12 Adresse Wert ... myh1 0120 0470 ... gewicht public static void main(...){ Hund myh1; myh1=new Hund(); myh1.setName("Goldi"); myh1.setGewicht(12); } 0470 ... 0473 0474 ... 0481 Welchen Wert hat also das Attribut gewicht? Wert public void setGewicht(double pGewicht){ Adresse gewicht = pGewicht; 12 ... 12 } 12 Adresse Wert ... myh1 0120 0470 ... gewicht public static void main(...){ Hund myh1; myh1=new Hund(); myh1.setName("Goldi"); myh1.setGewicht(12); } 0470 ... 0473 0474 ... 0481 Welchen Wert hat also das Attribut gewicht? Wert Wann werden Variablen automatisch initialisiert, wann nicht? Merke Lokale Variablen Jede lokale Variable (innerhalb einer Methode) hat (wenn ihr kein Wert zugewiesen wurde) einen dem Programmierer unbekannten, undefinierten Wert. Deshalb muss ihr vor einer lesenden Verwendung vom Programmierer ein Wert zugewiesen werden, da es sonst beim Kompilieren eine Fehlermeldung gibt. Attribute, Felder Wenn dagegen ein Attribut einer Klasse bzw. die Komponenten (Elemente, Zellen) eines mit new erzeugten Arrays (siehe später) vom Programmierer nicht initialisiert wird, dann werden das Attribut bzw. die Komponenten des Arrays automatisch (d.h. ohne Zutun des Programmierers) wie folgt initialisiert: Datentyp boolean char byte short int long float double Referenz standardmäßige Vorbelegung false \u0000 0 0 0 0L 0.0f 0.0 null