Java Classes

Kleines Beispiel

Ein Interface, darf nur abstrakte Methoden und Konstanten enthalten

/**
 *  My Interface
 */

package mypackage;

/**
 * @author John Doe
 *
 */

public interface MyInterface
{

 /**
  * @param number The number which is added
  * @return The new sum
  */

 public double add(final int number);

 /**
   * The limit for the result after the mathematical operations
   */

 final static double maxValue=10000;
}

Eine abtrakte Klasse, enthält mindestens eine abstrakte Methode

/**
 * An abstract class which will be used for things which are
 * not allowed in an Interface
 */
package mypackage;

/**
 * @author John Doe
 *
 */

public abstract class MyAbstractClass
{

  /**
   * Constructor
   */

  public MyAbstractClass()
  {
    this.value=0;
  }

  /**
   * This is the current value which will be modified by the
   * mathematical operations which are offered
   */

  protected double value;

}

Eine normale Klasse, darf höchsten von einer anderen Klasse erben, aber von beliebig vielen Interfaces implementieren.

/**
 * This class shows that you can implement multiple Interfaces
 */

package mypackage;

/**
 * @author John Doe
 *
 */

public class MyClass extends MyAbstractClass
                     implements MyInterface, MyOtherInterface
{

        /* (non-Javadoc)
         * @see mypackage.MyInterface#add(int)
         */

        public double add(final int number)
        {
                System.out.println("The maxvalue is " + AdderInterface.maxValue);
                double res=this.value+=number;
                this.value=res;
                return res;
        }
}

instanceof

String str = "HELLO WORLD";
b = ( str instanceof String );  // (1)
b = ( str instanceof Object );  // (2)
b = ( str instanceof Foo );     // (3)

(1) und (2) sind beide wahr, (3) nicht

So kann man eine Objekt in eine gewünschte Klasse casten, falls möglich

public <T extends Foo, S extends Foo> Optional<T> getCastedIfPossible(Class<T> desiredClass, S object) {
 if(desiredClass.isAssignableFrom(object.getClass())) {
  @SuppressWarnings("unchecked")
  final T casted=(T) object;
  return Optional.of( casted );
 }
 return Optional.empty();
}

Clone

Flache Kopie von Objekten erzeugen:

Foo x,y;
x=new Foo();
y=x.clone();

Konstruktor

Anderen Konstruktor der eigenen Klasse aufrufen

this(5);

muss die erste Anweisung des Konstruktors sein, keine Objektvariablen übergebbar

Wenn man eine Klasse hat, von der es nur wenige Ausprägungen gibt, wie z.B. Boolean. Dann macht es oft keinen Sinn, dass man mit new beliebig viele verschiedene Objekte dieser Klasse erzeugen kann. Eine besser Variante ist es dann, statt einem Konstruktor eine valueOf() Methode anzubieten

public static valueOf(boolean b)
 

Diese liefert dann immer wieder die wenigen Objekte zurück die es geben kann, hier z.B. entweder Boolean.TRUE oder Boolean.FALSE. Es darf dann natürlich keine Methode geben, ob den Wert eines solchen Objektes zu verändern, weil sonst auch alle anderen Nutzer dieses Objektes davon betroffen wären.

Exemplarinitialisierern

Initialisieren von Variablen in allen Konstruktoren

class Foo
{
  int j=1; // (1)

  Foo()
  {
   this.k=0;
  }

  Foo( int i )
  {
    this.k = j;
  }
}

entspricht

class Foo
{
  int j;        // (1)

  Foo()
  {
   this.j=1;    // (1)
   this.k=0;
  }
  Foo( int i )
  {
    this.j = 1; // (1)
    this.k = i;
  }
}

Bei statischen Variablen

public class Foo
{
  static int x = 2;
}

entspricht

public class InitStaticVariable
{
  static int x;
  static
  {
    x = 2;
  }
}

Super

Konstruktor des Vaters aufrufen

super(5);

Methode des Vaters aufrufen

@Override
public void foo( int alter ) {
 super.foo();
 ...
}

Innere Klassen

Siehe auch Innere Klassen in Java mehr als eine Insel

class Foo
{
  class Bar
  {
  }
}

Zum Erzeugen eines Objekts der inneren Klasse, braucht man ein Objekt der äußeren Klasse (Ausnahme statische innere Klassen). Versucht man z.B. in einer statischen Methode der äußeren Klasse ein Objekt der inneren Klasse zu erzeugen würde das fehlschlagen

No enclosing instance of type foo is accessible. Must qualify the allocation with an enclosing instance of type foo (e.g. x.new Bar() where x is an instance of foo).

Nur innere Klassen dürfen Private oder Protected sein. Wenn sie es sind, hat es Einfluss darauf, wer sie benutzen darf.

Statische Klasse

Statische Klassen werden auch nested top-level class genannt. Sie benötigen kein Exemplare der äußeren Klasse, um erzeugt zu werden. Eine statische Klasse kann auf alle statischen Attribute und Methoden der umgebenden Klasse zugreifen. Auf nicht statische Attribute oder Methoden hingegen ist kein direkter Zugriff möglich.

public class Foo
{
  static String s = "HELLO WORLD";
  int i = 1;

  static class Bar
  {
    void test()
    {
      System.out.println(s);
      // System.out.println( i ); // (1)
    }
  }
}

Mitglieds- oder Elementklassen

Auch member class genannt. Kann auch alle Attribute (inklusiver privater) der äußeren Klasse zugreifen. Allerdings benötigt man ein Exemplar der äußeren Klasse, um ein Exemplar der inneren Klasse von außen zu erzeugen.

public class Foo
{
  String s = "Hello World";

  class Bar
  {
    void test1()
    {
      System.out.println( s );
    }

    //static void test2()  {  }   // (2)
  }
}

Von aussen erzeugen

Foo a = new Foo();
Bar b = a.new Bar();

Die Mitgliedsklasse darf selbst keine statischen Attribute oder Methoden haben.

Lokale Klassen

Klassen, die innerhalb von Methoden der äußeren Klasse definiert werden. Die lokalen Klassen können auf die Methoden der äußeren Klassen zugreifen und auf deren Elemente, die mit final markiert sind. Wird die lokale Klasse in einer static Methode definiert ist ein Zugriff auf nicht statische Elemente und Methoden hingegen nicht möglich.

public class Foo
{
  public static void main( String[] args )
  {
    int i = 1;
    final int j = 2;

    class Bar
    {
      Bar() {
        System.out.println( j );
        //System.out.println( i );    // (3) Fehler, da i nicht final
      }
    }
    new Bar();
  }
}

Anonyme innere Klassen

Anonyme innere Klassen erben entweder von einer anderen Klasse oder implementieren eine Schnittstelle

class Foo()
{
 // ...
}

interface Bar()
{
 // ...
}

class Blub{}
{
 new Foo()
 {
  ...
 }
 new Bar()
 {
  ...
 }
}

Serialisierung

Eine kleine Testklasse, die serialisiert werden soll:

package de.tgunkel.JavaDemo.Serialize;

import java.io.Serializable;

public class PersistMe implements Serializable
{
    private static final long serialVersionUID = 291L; // == 0x123

    byte    variableA=127;          // ==           0111 1111 == 0x7f
    int     variableB=1092;         // == 0000 1000 1000 1000 == 0x0444
    String  variableC="Hallo Welt";
}

So kann man ein Objekt der Klasse speichern:

private void saveObject(String pFileName, PersistMe pDemo) throws FileNotFoundException, IOException
{
  FileOutputStream fos = new FileOutputStream(pFileName);        
  ObjectOutputStream out = new ObjectOutputStream(fos);
  out.writeObject(pDemo);
  out.close();
}

So kann man ein Objekt der Klasse wiederherstellen:

private PersistMe readObject(String pFileName) throws FileNotFoundException, IOException, ClassNotFoundException
{
   FileInputStream fos = new FileInputStream(pFileName);
   ObjectInputStream in = new ObjectInputStream(fos);
   PersistMe d = (PersistMe) in.readObject();
   in.close();
   return d;
}

Mit einem Hexeditor kann man in der Datei

00000000: aced 0005 7372 0027 6465 2e74 6775 6e6b  ....sr.'de.tgunk
00000010: 656c 2e4a 6176 6144 656d 6f2e 5365 7269  el.JavaDemo.Seri
00000020: 616c 697a 652e 5065 7273 6973 744d 6500  alize.PersistMe.
00000030: 0000 0000 0001 2302 0003 4200 0976 6172  ......#...B..var
00000040: 6961 626c 6541 4900 0976 6172 6961 626c  iableAI..variabl
00000050: 6542 4c00 0976 6172 6961 626c 6543 7400  eBL..variableCt.
00000060: 124c 6a61 7661 2f6c 616e 672f 5374 7269  .Ljava/lang/Stri
00000070: 6e67 3b78 707f 0000 0444 7400 0a48 616c  ng;xp....Dt..Hal
00000080: 6c6f 2057 656c 74                        lo Welt

dann relativ leicht die Informationen des Objektes wiederfinden:

Klassenname:

6465 2e74 6775 6e6b 656c 2e4a 6176 6144 656d 6f2e 5365 7269 616c 697a
652e 5065 7273 6973 744d 65
d e  . t  g u  n k  e l  . J  a v  a D  e m  o .  S e  r i  a l  i z  e
.  P e  r s  i s  t M  e

serialVersionUID:

01 23
291

Variablennamen:

4200 0976 6172 6961 626c 6541
B      v  a r  i a  b l  e A

4900 0976 6172 6961 626c 6542
I      v  a r  i a  b l  e B  

4c00 0976 6172 6961 626c 6543 7400 124c 6a61 7661 2f6c 616e 672f 5374
7269 6e67
L      v  a r  i a  b l  e C         L  j a  v a  / l  a n  g /  S t  r
i  n g  

Variablenbelegung:

7f
127

0444
1092

48 616c 6c6f 2057 656c 7
H  a l  l o    W  e l  t

Serialisierung Links