22.3. Anonyme klasser

En anonym klasse er en klasse uden navn, som der oprettes et objekt ud fra der, hvor den defineres.

public class YdreKlasse
{
  public void metode()
  {

    // ... programkode for metode()

    X objektAfAnonymKlasse = new X()
    {
      void metodeIAnonymKlasse()
      {
        // programkode
      }
      // flere metoder og variabler i anonym klasse
    };

    // mere programkode for metode()

  }
}

Lige efter new angives det, hvad den anonyme klasse arver fra, eller et interface, der implementeres (i dette tilfælde X).

Fordelen ved anonyme klasser er, at det tillades på en nem måde at definere et specialiseret objekt præcis, hvor det er nødvendigt - det kan være meget arbejdsbesparende.

Man kan ikke definere en konstruktør til en anonym klasse (den har altid standardkonstruktøren). Angiver man nogen parametre ved new X(), er det parametre til superklassens konstruktør.

22.3.1. Eksempel - filtrering af filnavne

Følgende program udskriver alle javafiler i det aktuelle katalog. Det sker ved at kalde list()-metoden på et File-objekt og give det et FilenameFilter-objekt som parameter.

Interfacet FilenameFilter har metoden accept(File dir, String filnavn), som afgører, om en fil skal tages med i listningen (se evt. Javadokumentationen).

import java.io.*;
public class FilnavnfiltreringMedAnonymKlasse
{
  public static void main(String arg[])
  {
    File f = new File( "." );      // det aktuelle katalog

    FilenameFilter filter;

    filter = new FilenameFilter() 
        { // En anonym klasse
          public boolean accept( File f, String s) // En metode
          {
            return s.endsWith( ".java");  // svar true hvis fil ender på .java
          }
        } // slut på klassen
      ; // slut på tildelingen filter = new ...

    // brug objektet som filter i en liste af et antal filer
    String[] list = f.list( filter ); 

    for (int i=0; i<list.length; i=i+1) System.out.println( list[i] );  
  }
}

Resultatet bliver

YdreKlasseMedLokalKlasse.java
FilnavnfiltreringMedAnonymKlasse.java
LinjetegningAnonym.java
AnonymeTraade.java
A.java
BenytIndreKlasser.java

22.3.2. Eksempel - Linjetegning

Udviklingsværktøjer benytter ofte anonyme klasser i forbindelse med at lytte efter hændelser. Her er Linjetegning-eksemplet igen, hvor vi bruger en anonym klasse som lytter (sml. med det tidligere eksempel).

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class LinjetegningAnonym extends Applet
{  
  private Point trykpunkt = null;
  private Point slippunkt = null;

  public void init()
  {    
    this.addMouseListener(
      new MouseListener() 
      {
        public void mousePressed (MouseEvent event)
        {
          trykpunkt = event.getPoint();
        }

        public void mouseReleased (MouseEvent event)
        {
          slippunkt = event.getPoint();
          repaint();  
        }

        public void mouseClicked (MouseEvent event) {}
        public void mouseEntered (MouseEvent event) {}
        public void mouseExited (MouseEvent event) {}
      } // slut på anonym klasse
    ); // slut på kald til addMouseListener()

    System.out.println("Anonymt lytter-objekt oprettet");    
  }

  public void paint (Graphics g)
  {
    if (trykpunkt != null && slippunkt != null)
      g.drawLine (trykpunkt.x, trykpunkt.y, slippunkt.x, slippunkt.y);
  }
}

22.3.3. Eksempel - tråde

Her gennemløber vi en løkke, der i hvert gennemløb opretter et Runnable-objekt fra en anonym klasse og en tråd, der kører på det. Objekterne får hvert sit nummer fra 1 til 5, som de udskriver 20, gange før de slutter. For at få trådene til at kæmpe lidt om processortiden løber de i en anden løkke 1.000.000 gange mellem hver udskrivning.

public class AnonymeTraade
{
  public static void main(String arg[])
  {

    for (int i=1; i<=5; i=i+1)
    {
      // n bruges i den anonyme klasse
      final int n = i;

      Runnable r = new Runnable()
      {
        public void run()
        {
          for (int j=0; j<20; j=j+1) 
          {
            System.out.print(n);

            // Lav noget der tager tid
            int x = 0;
            for (int k=0; k<1000000; k=k+1) x=x+k;
          }
          System.out.println("Færdig med "+n+".");
        }
      };

      Thread t = new Thread(r);
      t.start(); 
    }
  }
}

Resultatet bliver:

111122221223311332441114433221144332211442255115544332115544332211Færdig med 1.
54442233332233Færdig med 2.
544335544Færdig med 3.
54Færdig med 4.
555555555Færdig med 5.

Man ser, hvordan objekt nummer 1, der blev startet først, også er det første, der afslutter.