Erreichbarkeit von Exemplaren in Java
Um in einer Methode auf ein Objekt zugreifen zu können, muß dieses Objekt für die Methode irgendwie erreichbar sein. Das ist bei Sichtbarkeit eines Namens dieses Objekts oder einer anderen Form der Erreichbarkeit gegeben.
Probleme mit der Erreichbarkeit
Probleme mit der Erreichbarkeit sind allerdings oft ein Indiz dafür, daß einer Entwicklung kein objektorientierter Entwurf zugrunde liegt oder noch allgemeine Grundkenntnisse der objektorientierten Programmierung oder der Sprache Java fehlen, da die Erreichbarkeit selber kein Grundbegriff ist, sondern sich aus allgemeinen Grundkenntnissen über die Programmiersprache herleiten läßt und es sich aus einem objektorientierten Entwurf ohne weiteres ergibt, daß alle von einer Methode benötigten Objekte auch für diese erreichbar sind. Wenn ein Objekt ein anderes Objekt für seine Arbeit benötigt, dann erhält es dieses normalerweise während seiner Erzeugung im Konstruktor oder es erzeugt es selber—„global“ erreichbare Objekte sollten vermieden werden, da sie Quellcodeteile unnötig an eine bestimmte Umgebung binden.
Bereitet die Erreichbarkeit Kopfzerbrechen, sollte also besonders studiert werden, wie ein Programm objektorientiert aufgebaut wird. Dieser Artikel behandelt jedoch nicht dieses Thema, sondern schildert nur die programmiertechnischen Aspekte der Erreichbarkeit. Der objektorientierte Stil wird in anderen Texten behandelt. (In diesem Zusammenhang relevant ist unter anderem das “law of demeter ”.)
Einzelne Fälle der Erreichbarkeit
Im folgenden wird die Erreichbarkeit von Referenzen auf Exemplare eine Klasse behandelt. Die Situationen können aber meist auch auf die Erreichbarkeit von Werten primitiver Typen und teilweise auf die Erreichbarkeit von Methoden übertragen werden.
Sichtbarkeit als Feld der Klasse »M«
Ein Objekt einer Klasse »O« ist für die Methode »m« der Klasse »M« erreichbar, wenn eine Referenz auf dieses Objekt ein Feld »o« der Klasse »M« ist. Dieses Objekt ist dann über den Ausdruck »this.o« für die Methode »m« erreichbar.
Main.java
class M { final O o; M( final O o ){ this.o = o; }
void m(){ java.lang.System.out.println( this.o ); }}
class O {}
public class Main { public static void main( final java.lang.String[] args )
{ new M( new O() ).m(); }}
Es muß dann rechtzeitig vor der Verwendung, etwa im Konstruktor, sichergestellt sein, daß das Feld eine Referenz auf das zu erreichende Objekt als Wert hat. Dazu kann einem Initialisierer eines Exemplars der Klasse »M« solch eine Referenz in einem Exemplarerzeugungsausdruck als Argument übergeben werden (letzte Zeile des Beispielprogramms). Es ist auch möglich, daß eine Referenz, die zuvor auf einem der anderen Wege (etwa als Parameter einer Methode) erhalten wurde, dann in solch einem Felde gespeichert wird.
Parametersichtbarkeit
Ein Objekt einer Klasse »O« ist für die Methode »m« der Klasse »M« erreichbar, wenn eine Referenz auf dieses Objekt der Methode als Parameter »o« übergeben wird. Dann ist dieses Objekt für die Methode »m« über den Parameternamen »o« erreichbar.
Main.java
class M
{ void m( final O o )
{ java.lang.System.out.println( o ); }}
class O {}
public class Main { public static void main( final java.lang.String[] args )
{ new M().m( new O() ); }}
Exemplarerzeugung in der Methode »m«
Ein Objekt der Klasse »O« ist für die Methode »m« der Klasse »M« erreichbar, wenn es in dieser Methode durch einen Exemplarerzeugungsausdruck erzeugt wurde. Dazu muß der Name »O« der Klasse des zu erreichenden Objekts in »m« sichtbar sein. Dann ist das Objekt »o« für die Methode »m« als Wert dieses Exemplarerzeugungsausdrucks erreichbar.
Main.java
class M { void m(){ java.lang.System.out.println( new O() ); }}
class O {}
public class Main { public static void main( final java.lang.String[] args )
{ new M().m(); }}
Während bei den vorigen beiden Vorgehensweisen das Objekt von außen kam, wird es hier in der Methode erzeugt. Das bedeutet auch, daß das Exemplar in den beiden ersten Fällen noch weitere Informationen von außen mitbringen kann, was hier nicht möglich ist.
Wertausdruck in der Methode »m«
Ein Objekt der Klasse »O« ist für die Methode »m« der Klasse »M« erreichbar, wenn das Objekt der Wert eines Ausdrucks, wie beispielsweise »f()«, ist, der in der Methode »m« vorkommt.
Dazu muß der Bezeichner einer eventuell dabei verwendeten Methode sichtbar und deren Klasse bzw. Objekt erreichbar sein.
Diese Operation kann ein neues Objekt erzeugen oder eine Referenz auf ein schon vorhandenes vermitteln.
Das Objekt ist dann als Wert dieses Ausdrucks erreichbar.
Main.java
class M { void m(){ java.lang.System.out.println( F.f() ); }}
class O {}
class F { static O f(){ return new O(); }}
public class Main { public static void main( final java.lang.String[] args )
{ new M().m(); }}
Mit nichtstatischer Operation »f«:
Main.java
class M
{ void m()
{ java.lang.System.out.println( new F().f() ); }}
class O {}
class F { O f(){ return new O(); }}
public class Main { public static void main( final java.lang.String[] args )
{ new M().m(); }}
Ferne Attributsichtbarkeit
Ein Objekt der Klasse »O« ist für die Methode »m« der Klasse »M« erreichbar, wenn eine Referenz auf dieses Objekt in einem sichtbaren Felde »o« einer anderen Klasse enthalten ist.
Diese Struktur wird nicht empfohlen, da sie praktisch den berüchtigten „globalen Variablen“ entspricht.
Main.java
class M { void m(){ java.lang.System.out.println( G.o ); }}
class O {}
class G { public static O o = new O(); }
public class Main { public static void main( final java.lang.String[] args )
{ new M().m(); }}
Mit nichtstatischem Feld »o«:
Main.java
class M { void m(){ java.lang.System.out.println( new G().o ); }}
class O {}
class G { public final O o = new O(); }
public class Main { public static void main( final java.lang.String[] args )
{ new M().m(); }}
Indirekte Erreichbarkeit
Ein Objekt der Klasse »O« ist für die Methode »m« der Klasse »M« erreichbar, wenn ein Bezeichner sichtbar ist, über den eine Referenz auf dieses Objekt erreichbar ist. Dieser Bezeichner kann beispielsweise der Bezeichner einer Reihung sein, welche eine Referenz auf das zu erreichende Objekt enthält.
Main.java
class M
{ void m( final O[] a )
{ java.lang.System.out.println( a[ 0 ] ); }}
class O {}
public class Main { public static void main( final java.lang.String[] args )
{ final O a[] = new O[ 1 ]; a[ 0 ]= new O();
new M().m( a ); }}
Sichtbarkeit als lokale Variable eines Blocks der Methode »m«
Ein Objekt der Klasse »O« ist für die Methode »m« der Klasse »M« erreichbar, wenn eine auf einen der bisher geschilderten Wege erhaltene Referenz auf das zu erreichende Objekt für die weitere Verwendung durch einen lokalen Bezeichner benannt wurde.
Dann ist das zu erreichende Objekt über einen zu einem ihrer Blöcke lokalen Bezeichner (hier über den Bezeichner »o«) für die Methode »m« erreichbar.
Main.java
class M
{ void m()
{ final O o = new O();
java.lang.System.out.println( o ); }}
class O {}
public class Main { public static void main( final java.lang.String[] args )
{ new M().m(); }}
Erreichbarkeit von Feldern einer Oberklasse
Wenn ein Objekt einer Klasse angehört, die einer andere Klasse erweitert, so sind die Felder der erweiterten Klasse in Methoden des Objekts der erweiternden Klasse und in statischen Methoden der erweiternden Klasse sichtbar und damit erreichbar, wenn die Sichtbarkeit dieser Felder in der erweiterten Klasse »protected« oder »public« ist.
Erreichbarkeit von Feldern einer umgebenden Klasse
Wenn ein Objekt einer Klasse angehört, die innerhalb der Deklaration einer anderen Klasse deklariert wurde (als eine „innere Klasse“), kann eine Methode dieses Objektes auf die Felder der umgebenden Klasse zugreifen.