Java, Klassen

Klassen und Objekte


Unterprogramme, Methoden

Unterprogramme sind Prozeduren und Funktionen, in Java werden sie als Methoden bezeichnet.

   void prozedur( parameter ) block;

   typ funktion( parameter ) {
    ...
       return (typ) wert;
    ...
   }

   typ methode( typ_1 name_1, ..., typ_n name_n ) {
    ...
        int x = (int)name_1;
        int y = funktion( name_2, 4711 ); 
        int z = name_3 + name_n; 
   ...
   }

   public static void main(String[] args) { 
     // die Hauptprozedur, 
     // d.h. die erste die ausgeführt wird
   }

Beispiele:

public class Unterprogramme {

    void prozedur() {
    }

    int funktion() {
	return 4711;
    }

    int quadrat(int a) {
	return a*a;
    }

    double quadrat(double a) {
	return a*a;
    }

    int name(int a) {
	int b = quadrat( 2 );
	return b+a;
    }

    long fakultaet(long n) {
	if ( n <= 1l ) {
           return 1l;
	} else {
	   return n * fakultaet( n-1l);
	}
    }

    double summe(double[] a) {
	double sum = 0.0;
	for ( int i = 0; i < a.length; i++ ) {
	    sum += a[i];
	}
	return sum;
    }

   void main() { 
       prozedur();
       int n = funktion();
       int i = quadrat(n); 
       int j = name( 3 );
       long k = fakultaet( 10 );
       double[] z = { 1.0, 1.2, 3.2, 4.6, 9.2 };
       double s = summe( z );

       System.out.println("n = " + n);
       System.out.println("i = " + i);
       System.out.println("j = " + j);
       System.out.println("k = " + k);
       System.out.println("s = " + s);
   }

   public static void main(String[] args) { 
       // die Hauptprozedur, 
       (new Unterprogramme()).main();
   }
}
public class Ueberladen {

    void problem(int a, long b) { }

    void problem(long a, long b) { }

    void problem(long a, int b) { }

    void ratemal() {
	problem( 1, 2L ); // ok
	problem( 1L, 2 ); // ok
	problem( 1, 2 );  // fehler
    }

    long problem(long a, long b) { // fehler
	return a*b;
    }
}
public class Uebergabe {

    class Unter {
	int a = 0;
	int b = 1;
    }

    void wert( int c ) {
	c = c + 55;
    }

    void referenz( Unter u ) {
	int x = u.a * 3;
	u.b = x + 14;
    }

    void unveraendert( Unter u ) {
        u = new Unter();
	int x = u.a * 3;
	u.b = x + 14;
    }

    void ratemal() {
	int w = 3;
	wert( w );
	// w == 3

	Unter u = new Unter();
	referenz( u );
	// u.a == 0
	// u.b == 14

	unveraendert( u );
	// u.a == 0
	// u.b == 1
    }

}
public class Rekursion {

    long fakultaet(int n) {
	if ( n <= 1 ) {
           return 1L;
	} else {
	   return n * fakultaet( n-1 );
	}
    }

    double summe(double[] a) {
	double sum = 0.0;
	for ( int i = 0; i < a.length; i++ ) {
	    sum += a[i];
	}
	return sum;
    }

    double reksumme(double[] a) {
	return reksumme(a,a.length);
    }

    double reksumme(double[] a, int n) {
        if ( n == 0 ) return 0.0;
	return reksumme(a,n-1) + a[n-1];
    }

    long potenz(int b, int e) { // berechne b hoch e
	// if ( e < 0 ) { b = 1/b; e = -e; }
	if ( e == 0 ) return 1L;
        if ( e == 1 ) return (long)b;
        return b * potenz( b, e-1 );
    }

    long quadrat(long b) { // berechne b*b
	return b*b;
    }

    long potenzFast(int b, int e) { // berechne b hoch e
	// if ( e < 0 ) { b = 1/b; e = -e; }
	if ( e == 0 ) return 1L;
        if ( e == 1 ) return (long)b;
        if ( e % 2 == 0 ) 
           return quadrat( potenzFast( b, e/2 ) );
        return b * potenzFast( b, e-1 );
    }

    void main() { 
       long k = fakultaet( 10 );
       double[] z = { 1.0, 1.2, 3.2, 4.6, 9.2 };
       double s = summe( z );
       double r = reksumme( z );
       long p = potenz( 10, 15 );
       long f = potenzFast( 10, 15 );

       System.out.println("k = " + k);
       System.out.println("s = " + s);
       System.out.println("r = " + r);
       System.out.println("p = " + p);
       System.out.println("f = " + f);
    }

   public static void main(String[] args) { 
       // die Hauptprozedur, 
       (new Rekursion()).main();
   }
}
public class Summe {

    static double[] betrag = null;

    static double summe() {
        double s = 0.0;
        for (int i = 0; i < betrag.length; i++ ) {
	    s += betrag[i];
	}
        return s;
    }


    public static void main(String[] args) {
	betrag = new double[args.length];
	for (int i = 0; i < args.length; i++) {
	    betrag[i] = 0.0;
	    try {
	    betrag[i] = Double.parseDouble( args[i] );
	    // betrag[i] = Double.valueOf( args[i] ).doubleValue();
	    } catch (NumberFormatException e) { }
	}

        System.out.println("Eingegeben wurden " + args.length + " Zahlen");
        double s = summe();
        System.out.println("Die Summe ist " + s);
    }
}

Java Syntax aus der Sprachdefinition.

Klassen und Objekte

Klassen bieten die Zusammenfassung von Funktionen, Prozeduren und Variablen zu einem bestimmten Zweck. (Abstraktion von einzelnen Methoden zu Modulen oder Gruppen.)

Diagramme für Klassen in der Unified Modeling Language (UML):

Name
Zustand, Attribute
Funktionalität, Methoden
public class Klassen {

    static int klassen = 0;

    int meineNummer = 0;

    Klassen() {
	meineNummer = klassen++;
    }

    static String statistik() {
	return "Erzeugte Objekte = " + klassen;
    }

    public String toString() {
	return "Meine Nummer = " + meineNummer + " von " + klassen;
    }

    public static void main(String[] args) {
	System.out.println( Klassen.statistik() );
	Klassen einz = new Klassen();
	Klassen zwei = new Klassen();
	Klassen drei = new Klassen();
	Klassen vier = new Klassen();
	Klassen fuenf = new Klassen();
	System.out.println( statistik() );

	System.out.println("einz: " + einz.toString());
	System.out.println("zwei: " + zwei);
	System.out.println("vier: " + vier);
	System.out.println("drei: " + drei);
	System.out.println("fuenf: " + fuenf);
    }
}
Klassen UML Diagramm
Klassen UML Diagramm

Java-Programme werden mittels Klassen definiert. Jede öffentliche (d.h. als public deklarierte) Klasse muß in einer separaten Datei gespeichert werden. Der Name der Datei muß mit dem Namen der public-Klasse übereinstimmen (z.B. muß die Klasse public class Test in der Datei Test.java gespeichert werden).

Der Speicherbereich für das Objekt wird automatisch allokiert. Wenn das Objekt nicht mehr gebraucht wird (d.h. keine Variable referenziert mehr das Objekt), wird der Speicherbereich während eines Garbage-Collection-Vorganges wieder freigegeben (Speicherrecycling). Das heißt, daß im Gegensatz zu C/C++ kein expliziter `delete'-Operator benötigt wird.

In Java können Prozeduren nur innerhalb von Klassen definiert werden. Prozeduren können zu einer Klasse oder zu Objekten gehören. Es gibt in Java keine freien / globalen Variablen oder Methoden.

   public class Card {
     int number;
     static int base = 5;
     public static String version = "1.0";
   
     public Card(int n) {
       number = n;
     }
   
     public int getNumber() {
       return number;
     }
   
     public static int getBase() {
       return base;
     }
   
     public int getDiff() {
       return number - base;
     }
   
     public static void main(String[] args) {
       Card c = new Card(7);
   
       System.out.println(c.version+":"+
              c.getNumber()+"-"+c.getDiff()+"="+
              Card.getBase());
     }
   }

Die Ausgabe dieses Programms ist 1.0:7-2=5.

Card UML Diagramm
Card UML Diagramm

Parameterübergabe von Objektreferenzen

Die Übergabe von Objektrefrenzen ermöglicht die Veränderung von übergebenen Objekten in der aufrufenden Methode.

public class Confuse {

    static class Reference {
	int val;
    }

    public int confuse( int a, int b ) {
        a = 1; 
        a = b + a;
	return a;
    }

    public Integer confuse( Integer a, Integer b ) {
        a = new Integer(1); 
        a = new Integer( b.intValue() + a.intValue() );
	return a;
    }

    public Reference confuse( Reference a, Reference b ) {
        a.val = 1; 
        a.val = b.val + a.val;
	return a;
    }

    public static void main(String[] args) {
	Confuse c = new Confuse();

	int m = 4;
	int n = c.confuse( m, m );
	System.out.println("m = " + m);
	System.out.println("n = " + n);

	Integer i = new Integer(4);
	Integer j = c.confuse( i, i );
	System.out.println("i = " + i);
	System.out.println("j = " + j);

	Reference k = new Reference();
        k.val = 4;
	Reference l = c.confuse( k, k );
	System.out.println("k = " + k.val );
	System.out.println("l = " + l.val );

    }
}
Confuse UML Diagramm
Confuse UML Diagramm

Das Problem kann durch Zugriffskontrolle gelöst oder beherscht werden.

Kapselung und Zugriffskontrolle

Klassen bzw. Objekte können ihre Variablen und Methoden in verschiedenen Abstufungen kapseln (einschliessen). Dabei werden nur die Variablen oder Methoden nach aussen, d.h. für andere Objekte sichtbar gemacht, die notwendig sind. Man spricht auch vom Geheimnisprinzip. Die öffentlich zugänglichen Variablen und Methoden werden meist noch durch Interfaces (s.u.) definiert. Vorteil: die Interna können beliebig modifiziert werden solange die Schnittstelle und deren Semantik erhalten bleibt.

Java unterschiedet public, private, protected und default Zugriffsrechte.

Beispiele siehe Abschnitt "Sichtbarkeit".

Der Kontrakt zwischen dem/der Entwicklerin einer Klasse und einem Anwender besteht aus der Syntax und Semantik der Aufrufschnittstelle.

Konstruktoren

Konstruktoren dienen der Initialisierung der Objekt-Variablen. Klassen-Variablen werden ein einziges mal vor der ersten Verwendung der Klasse initialisiert.

Beispiel für einen neuen Datentyp

Wir entwickeln eine Klasse Complex, die für die Arithmetik komplexer Zahlen verwendet werden kann.

Der Konstruktor soll aus einem Paar reeler Zahlen (a,b) eine komplexe Zahl a + i b machen.

Methoden und Konstanten:

Complex UML Diagramm
Complex UML Diagramm
/**
 * Klasse zum Rechnen mit Komplexen Zahlen
 * hk, 9.12.2001
 *
 **/

public class Complex {

    /* Die Datenstruktur */

    private double re;  // der Realteil
    private double im;  // der Imaginärteil


    /* Die Konstruktoren erzeugen aus einem Paar von 
       double Zahlen eine Komplexe Zahl */

    public Complex(double r, double i) {
        re = r;
        im = i;
    }

    public Complex(double r) {
        this(r,0.0);
    }

    public Complex() {
        this(0.0);
    }


    /* Konstanten: 1, 0 und i */

    public static final Complex ZERO = new Complex();

    public static final Complex ONE = new Complex(1.0);

    public static final Complex I = new Complex(0.0,1.0);


    /* Bestimmen des Real- und Imaginär-Teils */

    public double reTeil() { return re; }

    public double imTeil() { return im; }


    /* Darstellung als Zeichenkette */

    public String toString() {
        String s = "" + re;
        if ( im < 0 ) s += " - " + (-im) + "i";
           else s += " + " + im + "i";
        return s;
    }


    /* Vergleich zweier Komplexer Zahlen */

    public boolean equals(Complex b) {
	return ( re == b.reTeil() && im == b.imTeil() );
    }

    public boolean equals(Object b) {
        if ( ! ( b instanceof Complex ) ) {
            return false;
        }
        Complex c = (Complex)b;
	return ( re == c.reTeil() && im == c.imTeil() );
    }


    /* Arithmetische Operationen: +, -, - */

    public Complex add(Complex b) {
	return new Complex(re + b.reTeil(), im + b.imTeil());
    }

    public Complex subtract(Complex b) {
	return new Complex(re - b.reTeil(), im - b.imTeil());
    }

    public Complex negate() {
	return new Complex(-re,-im);
    }


    /* Arithmetische Operationen: Konjugierte, Absolut Betrag */

    public Complex conjugate() {
	return new Complex(re,-im);
    }

    public double abs() {
	return ( Math.sqrt( re * re + im * im ) );
    }


    /* Arithmetische Operationen: *, Inverse, / */

    public Complex multiply(Complex b) {
	return new Complex(re * b.reTeil() - im * b.imTeil(),
                           re * b.imTeil() + im * b.reTeil() );
    }

    public Complex inverse() {
        double a = re * re + im * im;
	return new Complex(re/a, -im/a); // Konjugierte
    }

    public Complex divide (Complex b) {
	return this.multiply( b.inverse() );
    }
}

Anwendungsbeispiel

/**
 * Testen der Klasse zum Rechnen mit Komplexen Zahlen
 * hk, 9.12.2001
 *
 **/

public class ComplexTest {

    public static void main(String[] args) {

        Complex a = new Complex(2.0,3.0);
        System.out.println("a(2,3) = " + a);

        System.out.println("Null(0,0) = " + Complex.ZERO);
        System.out.println("Eins(1,0) = " + Complex.ONE);

        Complex b = Complex.ONE;
        b = b.add(a);
        System.out.println("b(3,3) = " + b);

        Complex c = new Complex(3.0,3.0);
        System.out.println("c(3,3) = " + c);
        boolean t = c.equals(b);
        System.out.println("t(true) = " + t);

        Complex d = c.conjugate();
        System.out.println("d(3,-3) = " + d);

        double e = c.abs();
        System.out.println("e(18) = " + e);

        Complex f = c.multiply(d);
        System.out.println("f(18,0) = " + f);

        // c*conjugate(c) = abs(c)^2
        t = e == Math.sqrt( f.reTeil() );
        System.out.println("t(true) = " + t);

        // i*i = -1
        Complex g = Complex.I.multiply(Complex.I);
        System.out.println("g(-1,0) = " + g);

        // 1/i = -i
        Complex h = Complex.ONE.divide(Complex.I);
        System.out.println("h(0,-i) = " + h);


    }
}

© Universität Mannheim, Rechenzentrum, 1998-2008.

Heinz Kredel
Last modified: Sun Oct 5 15:20:37 CEST 2008