Namen in Java
Ein Name ist – etwas vereinfacht gesagt – ein Ausdruck, der mit einem Buchstaben beginnt und in der Regel – wie ein Wort – hauptsächlich oder ausschließlich aus Buchstaben besteht.
Ein Name ist ein Ausdruck. Er hat also einen Typ, kann ausgewertet werden, um einen bestimmten Wert zu erhalten und kann als Operand verwendet werden.
Ein Wertname kann fast jeden möglichen Datentyp haben, ohne daß dies am Namen selber ablesbar ist.
Das folgende Programm zeigt die Ausgabe des Wertes des Namens »java.lang.Math.PI«, einer Näherung des Wertes der Kreiszahl π. Der Datentyp dieses Wertnamens ist »double«.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.Math.PI ); }}java.lang.System.out
3.141592653589793
- Aussprachehinweise (englische Aussprache)
- »java.lang.Math.PI« ˈdʒɑvə læŋ mæθ paɪ
Man kann dies mit dem folgenden Programm vergleichen, welches ein Literal als Wertausdruck verwendet.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( 3.141592653589793 ); }}java.lang.System.out
3.141592653589793
Wir betrachten den gesamten Namen »java.lang.Math.PI« zunächst als eine Einheit und behandeln die Bedeutung der Punkte erst etwas später.
Sowohl Wertnamen als auch Literale sind Ausdrücke. Ein Wertname hat wie ein Literal einen bestimmten Typ und Wert. Dieser Typ und Wert eines Wertnamens ist aber in diesem Fall nicht schon durch die Programmiersprache Java (nach JLS ) bestimmt, sondern erst durch die Standardbibliothek (eine Sammlung vordefinierter Programmteile, die üblicherweise mit Java zusammen verwendet wird).
Das folgende Programm zeigt die Ausgabe des Wertes des Wertnamens »java.lang.Integer.MAX_VALUE«. Dieser Wertname hat den Datentyp »int«.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.Integer.MAX_VALUE ); }}java.lang.System.out
2147483647
Der Typ »int« umfaßt die ganzen Zahlen im Bereich von »java.lang.Integer.MIN_VALUE« (einschließlich) bis »java.lang.Integer.MAX_VALUE« (einschließlich).
Eine Auswertung eines als Ausdruck verwendeten Namens bezeichnet man auch als eine Verwendung jenes Namens. Der zuvor abgespeicherte Wert des Namens wird bei dieser Operation aus dem Speicher gelesen; es handelt sich also um eine Leseoperation.
Verallgemeinerung Stil _
Wenn man bei der Eingabe eines Numerales an einer Stelle eine falsche Ziffer verwendet, dann erhält man in der Regel keine Fehlermeldung. Schreibt man bei der Eingabe eines Namens einen Buchstaben falsch, so erhält man oft eine Fehlermeldung. Daher ist die Verwendung des Namens »java.lang.Math.PI« weniger fehlerträchtig als die Verwendung des Numerales »3.141592653589793«. Deswegen ist es besserer Stil, »java.lang.Math.PI« zu verwenden, wenn die Kreiszahl ‹ π › gemeint ist.
Man nennt ein Numerale, wie »3.141592653589793«, auch einen magischen Wert. Damit will man ausdrücken, daß dieser Wert – wie durch „Magie“ – von irgendwoher kommt, und keiner so recht versteht, wie er genau zustande kam. (Man kann ja nicht sicher wissen, ob er die Kreiszahl ‹ π › sein soll, oder ob es eine Zahl ist, die nur zufällig dieselben Anfangsziffern hat.)
Wenn man das folgende Programm liest, kann man beispielsweise nicht verstehen, was der Autor damit ausrechnen wollte und woher die beiden Werte »478« und »22« kommen.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( 478 + 22 ); }}
Einen Namen wie »java.lang.Math.PI« nennt man auch einen sprechenden Namen, weil er uns seine Bedeutung mitteilt. Man nennt ihn auch einen symbolischen Namen oder einen mnemonischen Namen, um auszudrücken, daß er eine bestimmte Bedeutung symbolisch darstellt beziehungsweise dabei hilft, sich den Namen zu merken und an seine Bedeutung zu erinnern.
ℛ Stilregel Sprechende Namen sollen gegenüber magischen Werten bevorzugt werden.
(Einige kleine ganzzahlige Numeralia, wie »0«, »1« oder »2«, sind oft schon ohne Benennung gut verständlich und daher nicht unbedingt immer magische Werte.)
Ein wichtigstes Kriterium für einen guten Programmierstil ist die Wartbarkeit der Software. Sie hängt wesentlich von der Verständlichkeit des Quelltextes ab. Weil sprechende Namen verständlicher sind als magische Werte, sind sie besserer Stil.
Wir erleben hier das wichtige Phänomen, daß zwei Programm dasselbe ausgeben können, aber trotzdem eines davon als besser gilt, weil es in besserem Stil geschrieben ist. Allgemeine kann man die Qualität eines Programmes nicht danach beurteilen, ob es das Gewünschte ausgibt ; es muß vielmehr ermittelt werden, ob der Quelltext des Programms gewissen Qualitätsanforderungen genügt.
Signifikanz der Groß- und Kleinschreibung
Die Groß- und Kleinschreibung von Quelltextzeichen ist in Java signifikant. Das heißt, daß ein kleiner Buchstabe (ein gemeiner Buchstabe, eine Minuskel) als ein anderes Zeichen gilt als der zu ihm gehörende große Buchstabe (als die zu ihm gehörige Majuskel). Wenn ein Name mit »PI« verwendet werden kann, so heißt dies daher beispielsweise im allgemeinen nicht, daß dann auch die Schreibweise mit »Pi« zulässig ist und dieselbe Bedeutung hat.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.Math.PI ); }}java.lang.System.out
3.141592653589793
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.Math.Pi ); }}- Konsole (übersetzt)
Main.java:3: Fehler: Symbol kann nicht gefunden werden
{ java.lang.System.out.println
( java.lang.Math.Pi ); }}
^
Symbol: Variable Pi
Ort: Klasse Math
1 Fehler- Aussprachehinweis
- variable ˈvɛɚ i ə bl
Zum Verständnis dieser Fehlermeldung muß man noch wissen, daß Namen von Werten vom Java -Compiler auch als „Variablen“ bezeichnet werden.
Namen als Operanden _
Wie Literale können auch Wertnamen als Operanden in einem Operatorausdruck verwendet werden.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.Math.PI/2 ); }}java.lang.System.out
1.5707963267948966
- Operationen bei der Auswertung von »java.lang.Math.PI/2«:
- Erste Operation Auslesen des Wertes »java.lang.Math.PI«.
_________________
java.lang.Math.PI/2 →
3.141592653589793/2- Zweite Operation Berechnung der Division.
___________________
3.141592653589793/2 →
1.5707963267948966
Wertausdrücke mit Literalen, Wertnamen und Operatoren dürfen praktisch beliebig groß und kompliziert werden, solange sie korrekt gebildet sind.
Typen von Namen _
Wertnamen haben einen Typ. Bei der Auflösung (= Ermittlung) der Bedeutung eines Operators kommt es nur auf den Typ der Operanden an und nicht auf deren Schreibweise.
So hat der Name »javax.swing.text.AbstractDocument.BidiElementName« beispielsweise den Typ »java.lang.String«. Deswegen wird in dem folgenden Programm der Operator »+« als eine Verkettung von Zeichenfolgen interpretiert (auch wenn der Name nicht mit Anführungszeichen geschrieben wird wie die bisher im Kurs vorgestellten Zeichenfolgenliterale.)
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( 123 + javax.swing.text.AbstractDocument.BidiElementName ); }}transcript
123bidi level
Ausdrücke _
Zusammenfassend sei festgehalten, daß nach dem bisher Gesagtem ein Ausdruck entweder
- ein Literal – wie »2« – oder
- ein Wertname – wie »java.lang.Math.PI« – oder
- ein Operatorausdruck – wie »java.lang.Math.PI/2« – ist
und daß solch ein Ausdruck in den Ausdruckrahmen eingesetzt werden kann.
In einer etwas genaueren Syntax wird ein Name in Java als ein sogenannter Postfixausdruck angesehen, den wir aber praktisch mit einem Primärausdruck gleichsetzen können. (Eine syntaktische Definition für einen Namen fehlt noch in dem folgenden Diagramm und folgt etwas später.)
- Syntax (Syntaxdiagramm) (vereinfacht)
Primaerausdruck
.-. .----------. .-.
--->.--->( ( )--->| Ausdruck |--->( ) )--->.--->
| '-' '----------' '-' ^
| .----------. |
'------------>| Literal |-------------'
'----------'Postfixausdruck
.-----------------.
--->.--->| Primaerausdruck |---.--->
| '-----------------' ^
| .-----------------. |
'--->| Name |---'
'-----------------'Vorzeichenausdruck
.--------------------.
---.------------>| Postfixausdruck |----.---->
| '--------------------' ^
| .-. .--------------------. |
'--->( - )--->| Vorzeichenausdruck |----'
| '-' '--------------------' |
| .-. .--------------------. |
'--->( + )--->| Vorzeichenausdruck |----'
'-' '--------------------'
Übungsaufgaben
/ Wertermittlung
Ermitteln Sie den Wert des Wertnamens »java.lang.Long.MAX_VALUE«, indem Sie den Ausdruckrahmen verwenden.
/ Refaktor „Eliminieren eines Wertnamens“ ⃗
Ein Refaktor ist eine Veränderung am Quelltext eines Programm, die man durch Ausführung des Programms (also „von außen“) nicht erkennen kann.
Beim Refaktor „Eliminieren eines Wertnamens“ wird der Wertname durch einen anderen Ausdruck ersetzt, der denselben Wert hat.
Ersetzen Sie den Wertnamen »java.lang.Short.MAX_VALUE« in dem folgenden Programm durch ein Numerale, das denselben Wert wie der Name hat.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( java.lang.Short.MAX_VALUE ); }}Protokoll
32767
/ Refaktor „Einführen eines Wertnamens“ ⃗
Ein Refaktor ist eine Veränderung am Quelltext eines Programm, die man durch Ausführung des Programms (also „von außen“) nicht erkennen kann.
Beim Refaktor „Einführen eines Wertnamens“ wird ein Ausdruck durch einen Wertnamen ersetzt, der denselben Wert hat.
Ersetzen Sie das Numerale »127« in dem folgenden Programm durch den Wertnamen »java.lang.Byte.MAX_VALUE«, der denselben Wert hat.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( 127 ); }}
Zusatzaufgaben *
/ Wertermittlung *
Rechnen Sie 30° (30 Grad, Winkelangabe in Grad [„Altgrad“]) in die Einheit „Radiant“ um, indem Sie 30 mit π/180 multiplizieren.
Hinweise *
In diesem Kapitel werden Namen, wie »java.lang.Math.PI« vorgestellt, ohne daß die als Beispiel gewählten speziellen Namen dabei im Vordergrund stehen sollen. Es geht vielmehr darum, das allgemeine Phänomen der Vergabe von Namen vorzustellen. Deswegen werden an dieser Stelle die Anwendungsmöglichkeiten des Wertes »java.lang.Math.PI« nicht weiter vertieft. Es geht hier nicht um die speziellen Möglichkeiten der Anwendung des Namens »java.lang.Math.PI«, sondern darum, daß es allgemein möglich ist, Namen für Werte einzuführen. »java.lang.Math.PI« dient dann lediglich als ein Beispiel dafür.
Beispiele *
● Berechnung des Umfangs eines Kreises mit Radius 3 Meter *
- r: Radius, hier nehmen wir als Beispiel an: r = 3
- U: Umfang
- π ≈ 3,14159265358979323846264338327950288419716939937510
- U = 2 π r ⇒ U = 2 π · 3
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "Umfang = " + 2 * java.lang.Math.PI * 3 + " Meter" ); }}java.lang.System.out
Umfang = 18.84955592153876 Meter
● Berechnung der Fläche eines Kreises mit Radius 3 Meter *
Einige Bezeichnungen dieses Beispiels werden aus dem vorigen Beispiel übernommen.
- F: Fläche
- F = π r² ⇒ F = π · 3²
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( "Flaeche = " + java.lang.Math.PI * 3 * 3 + " Quadratmeter" ); }}java.lang.System.out
Flaeche = 28.274333882308138 Quadratmeter
Die Bindung *
Eine Bindung ist die Zuordnung eines Wertes (aus dem Laufzeitmodell) zu einem Namen (aus dem Quelltextmodell).
- Beziehung zwischen Namen und Werten
Quelltextmodell Laufzeitmodell
Name ----------------------------------> Wert
Bindungbeispielsweise beispielsweise
java.lang.Math.PI 3.141592653589793
Trennende und halbtrennende Zeichen *
Wir hatten bisher schon die runden Klammern als trennende Zeichen kennengelernt, die nie durch zusätzlichen Leerraum abgegrenzt werden müssen.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( ( ( java.lang.Integer.MAX_VALUE ))); }}transcript
2147483647
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( ( ( 2 ))); }}transcript
2
Es gibt auch Zeichen, die zwar manchmal durch Leerraum abgegrenzt werden müssen, aber nicht bei Kontakt zu einem Wort oder einem Literal. Solche Zeichen nennen wir hier auch halbtrennend. Das Minuszeichen »-« ist solch ein halbtrennendes Zeichen. Es muß zwar manchmal mit Leerraum von einem anderen Minuszeichen abgegrenzt werden, aber dies kommt selten vor. Wenn es jedoch vor oder hinter einem Wort oder Literal steht, so ist keine Abgrenzung mit Leerraum nötig. Es kann also meistens wie ein trennendes Zeichen ohne Leerraum verwendet werden.
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( -java.lang.Math.PI-java.lang.Math.PI ); }}transcript
-6.283185307179586
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( -2-2 ); }}transcript
-4
Unterschiede zwischen Namen und Literalen *
Der Wert eines Namens wird dem Namen in der Regel ganz willkürlich zugeordnet, während der Wert eines Literals sich meist in regelhafter Weise aus den Zeichen des Literals ergibt (das Wort „Literal“ kommt vom lateinischen "littera" - „Schriftzeichen“).
Ersetzt man im Literal »11« das letzte Zeichen durch seinen Nachfolger, so ergibt sich wieder ein Literal, nämlich »12«, und dessen Wert ist um 1 größer. Ersetzt man hingegen im Namen »java.lang.Integer.MIN_VALUE« das letzte Zeichen durch seinen Nachfolger, so ergibt sich »java.lang.Integer.MIN_VALUF«, was in der Regel gar festgelegt wurde und daher gar keinen bestimmten Wert hat. Die Regel, die einem Literal seinen Wert zuordnet, ist auch meist in einem Programm überall gleich und wird oft durch die Programmiersprache festgelegt, während Namen in verschiedenen Programmteilen oft unterschiedliche Bedeutungen haben können, wie später gezeigt werden wird.
Zitat aus der Sprachnorm *
- 6.2 Names and Identifiers
- A name is used to refer to an entity declared in a program. There are two forms of names: simple names and qualified names. A simple name is a single identifier. A qualified name consists of a name, a "." token, and an identifier.