Andreas Rozek Lesehinweise letzte Änderungen Gästebuch-Eintrag Mitteilungen an den Autor  English Version  zur Leitseite zum vorherigen Thema zum nächsten Thema  zur ersten Seite zur vorherigen Seite zur nächsten Seite

Enumerator

Die "Enumerator"-Klasse stellt unter JavaScript einen Aufzählungstyp zur Verfügung. Die Programmierschnittstelle ist in etwa eine Mischung aus der des von Microsoft's JScript bereitgestellten Datentyps "Enumerator" sowie der Java-Klasse java.util.Enumeration.

Es existieren drei Implementierungen der "Enumerator"-Klasse:

  • die erste, einfachste Variante nutzt die "LiveConnect"-Funktionalität von Rhino und implementiert Funktionen als gleichnamige Methoden bzw. Datenfelder über entsprechende get...- und set...-Methoden;

  • die zweite Variante implementiert ein Rhino "Host Object" und bedient sich bei der Implementierung von Konstruktor, Methoden und Datenfeldern der entsprechenden Namenskonventionen;

  • die dritte Variante erweitert das zuvor realisierte "Host Object" um eine explizit implementierte Methode der "Scriptable"-Schnittstelle und steuert so die Sichtbarkeit der eigenen Methoden und Datenfelder;

Alle Varianten bieten ungefähr dieselbe Funktionalität - Unterschiede ergeben sich erst bei einer genaueren Untersuchung von "Enumerator"-Instanzen unter JavaScript: während in der "LiveConnect"-Variante auch alle (von java.lang.Object) eingeerbten Methoden und Datenfelder sichtbar sind, tauchen in der ersten "Host Object"-Implementierung interessanterweise überhaupt keine sichtbaren Datenfelder auf. Erst nach einer kleinen Erweiterung werden die vom Objekt selbst bereitgestellten Slots (und nur diese) sichtbar.

Desweiteren unterscheiden sich die Varianten in der Art, wie sie unter Rhino eingesetzt werden: die beiden "Host Object"-Klassen müssen unter JavaScript erst mit "defineClass" angeschlossen werden (stehen anschließend aber wie eine JavaScript-"Klasse" zur Verfügung), während auf die "LiveConnect"-Implementierung direkt zugegriffen werden kann (wobei aber stets die Java-Herkunft der Klasse deutlich wird).

Objektbeschreibung (JavaScript)

Konstruktor

new Enumerator (Elements)

erzeugt ein neues "Enumerator"-Objekt mit allen im JavaScript-Array "Elements" enthaltenen Objekten. Diese werden in der (aufsteigenden) Reihenfolge ihrer Indizes in die Aufzählung eingetragen - "Lücken" (d.h. Elemente, die "null" oder "undefined" sind) werden dabei ebenfalls übernommen;

Datenfelder

actualElement
enthält das "aktuelle" Aufzählungsobjekt - oder "undefined", falls der interne Zeiger hinter dem letzten Element der Aufzählung steht;

Methoden

atEnd () -> Boolean

prüft, ob der interne Zeiger hinter dem letzten Element der Aufzählung steht - falls ja, liefert die Funktion den Wert true zurück, ansonsten ist das Ergebnis false;

equals (Object) -> Boolean

prüft, ob das "Enumerator"-Objekt mit dem angegebenen Objekt identisch ist bzw. diesem inhaltlich gleicht - falls ja, liefert die Funktion den Wert true zurück, ansonsten ist das Ergebnis false;

hasMoreElements () -> Boolean

prüft, ob die Aufzählung weitere Elemente enthält - falls ja, liefert die Funktion den Wert true zurück, ansonsten ist das Ergebnis false;

moveFirst ()

setzt den internen Zeiger auf das erste Element der Aufzählung;

moveNext ()

setzt den internen Zeiger auf das nächste Element der Aufzählung;

nextElement () -> Object

setzt den internen Zeiger auf das nächste Element der Aufzählung und liefert dieses zurück. Falls die Aufzählung keine weiteren Elemente mehr enthält, wird der interne Zeiger direkt hinter das letzte Element gesetzt und ein "undefined" zurückgeliefert;

toString () -> String

liefert eine literale Repräsentaton des "Enumerator"-Objektes;

Objektbeschreibung (Java)

Für die Verwendung von anderen Java-Klassen aus stehen weitere Konstruktoren und Methoden zur Verfügung - auf diese Weise wird insbesondere das Anlegen neuer Aufzählungen vereinfacht.

Konstruktoren

new Enumerator ()

legt eine neue, leere Aufzählung an. Mithilfe von add und addContents kann die Aufzählung mit Elementen gefüllt werden;

new Enumerator (ItemArray)

legt eine neue Aufzählung an und trägt die Elemente des angegebenen Feldes in der Reihenfolge aufsteigender (Feld-)Indices darin ein. Mithilfe von add und addContents kann die Aufzählung um zusätzliche Elemente erweitert werden;

Methoden

add (Item, [NullOrUndefinedAllowed])

fügt das angegebene Objekt als letztes in die aktuelle Aufzählung ein - Felder werden dabei als ein Objekt eingetragen und nicht aufgelöst. Das Hinzufügen von Objekten zu einer Auflösung ist jedoch nur möglich, wenn diese noch unbenutzt ist oder (mittels moveFirst) wieder zurückgesetzt wurde. Falls NullOrUndefinedAllowed angegeben und als true definiert ist, werden auch Null und Undefined als Argument akzeptiert und in die Aufzählung eingetragen - anderenfalls wird eine Ausnahme geworfen (Voreinstellung für NullOrUndefinedAllowed ist false);

addContents (ItemArray, [NullOrUndefinedAllowed])

fügt die Elemente des angegebenen Feldes in der Reihenfolge aufsteigender (Feld-)Indices als letzte in die aktuelle Aufzählung ein - Elemente, die ihrerseits ein Feld darstellen, werden nicht weiter aufgelöst, sondern als ein Objekt in die Aufzählung ünernommen. Das Hinzufügen von Objekten zu einer Auflösung ist jedoch nur möglich, wenn diese noch unbenutzt ist oder (mittels moveFirst) wieder zurückgesetzt wurde. Falls NullOrUndefinedAllowed angegeben und als true definiert ist, werden auch Elemente mit dem Wert Null und Undefined akzeptiert und in die Aufzählung eingetragen - anderenfalls wird eine Ausnahme geworfen (Voreinstellung für NullOrUndefinedAllowed ist false);

Verwendungshinweise (JavaScript)

Erzeugen eines neuen Aufzählungsobjektes

In den meisten Fällen dürften Aufzählungsobjekte das Ergebnis eines Funktionsaufrufes sein (wie z.B. bei der Aufzählung aller lokalen Dateisysteme). Bei Bedarf kann ein solches Objekt aber auch explizit erzeugt werden:

 var Enumeration = new Enumerator( new Array(1,2,3,4) );

Dem Konstruktur wird also ein Feld (Array) mit den aufzuzählenden Elementen übergeben.

Verwendung eines Aufzählungsobjektes innerhalb einer Schleife

Der typische Anwendungsfall einer Aufzählung besteht in dem Durchlaufen aller Elemente innerhalb einer for-Schleife:

  for (; !Enumeration.atEnd(); Enumeration.moveNext()) {
    passende Bearbeitung von Enumeration.actualElement
  };

Mithilfe von moveFirst() kann eine teilweise oder vollständig durchlaufene Aufzählung wieder auf das erste Element zurückgesetzt und von dort aus erneut durchlaufen werden.

Anwendungsbeispiel (JavaScript)

Das Rhino-Skript EnumeratorTest.js verdeutlicht das Anlegen eines Aufzählungsobjektes sowie dessen Verwendung. Zusätzlich werden alle Slots des Aufzählungsobjektes angezeigt - so werden die Unterschiede zwischen den beiden verfügbaren Implementierungen sichtbar.

Das Programm wird ohne Angabe von Kommandozeilen-Argumenten aufgerufen

  java Rhino EnumeratorTest.js

und liefert - abhängig von der verwendeten Implementierung - eine der nachstehend beschriebenen Ausgaben.

"LiveConnect"-Implementierung

Die einfachste der drei Implementierungen nutzt Rhino's "LiveConnect"-Eigenschaft für die Realisierung eines Aufzählungstyps unter Java. Das zuvor beschriebene Beispiel-Skript liefert folgende Ausgabe:
 

  EnumeratorTest - tests the "sunda.rhino.data.Enumerator" class

  constructing an enumeration...
  printing the enumeration's contents:
   - true (more to come...)
   - 2.0 (more to come...)
   - anything (final element)

  printing the enumeration itself:
    (true,2.0,anything)

  constructing another enumeration with the same content...
    Enumeration == equalEnumeration?     true

  constructing another enumeration with different content...
    Enumeration == differentEnumeration? false

  examining the enumeration's properties:
   - notifyAll: function notifyAll() {/* void notifyAll() */}
   - toString: function toString() {/* java.lang.String toString() */}
   - equals: function equals() {/* boolean equals(java.lang.Object) */}
   - class: class sunda.rhino.data.Enumerator
   - moveFirst: function moveFirst() {/* void moveFirst() */}
   - getActualElement: function getActualElement() {/* java.lang.Object getActualElement() */}
   - hasMoreElements: function hasMoreElements() {/* boolean hasMoreElements() */}
   - wait: function wait() {/* void wait() void wait(long,int) void wait(long) */}
   - atEnd: function atEnd() {/* boolean atEnd() */}
   - nextElement: function nextElement() {/* java.lang.Object nextElement() */}
   - actualElement: undefined
   - moveNext: function moveNext() {/* void moveNext() */}
   - hashCode: function hashCode() {/* int hashCode() */}
   - getClass: function getClass() {/* java.lang.Class getClass() */}
   - notify: function notify() {/* void notify() */}


Die Programmausgabe wird zweckmäßigerweise zusammen mit dem Quelltext des Beispiel-Skriptes analysiert und sollte dann keiner weiteren Erläuterung bedürfen. Etwas "unschön" ist das zusätzliche Auftauchen von Methoden der Klasse "java.lang.Object" in der Liste aufzählbarer Datenfelder (und Methoden) unter Rhino - dies ist ein "Seiteneffekt" der "LiveConnect"-Funktionalität und kann nur durch Implementieren eines "Host Object" vermieden werden.

Rhino "Host Object"-Implementierung I

Eine andere Variante implementiert den Aufzählungstyp als Rhino "Host Object" - unter Beachtung der Rhino-Namenskonventionen, mit deren Hilfe "defineClass" aus der Klasse ein "ScriptableObject" generieren kann. Das oben beschriebene Beispiel-Programm liefert in diesem Fall folgende Ausgabe:

  EnumeratorTest - tests the "sunda.rhino.data.Enumerator" class

  constructing an enumeration...
  printing the enumeration's contents:
   - true (more to come...)
   - 2 (more to come...)
   - anything (final element)

  printing the enumeration itself:
    (true,2,anything)

  constructing another enumeration with the same content...
    Enumeration == equalEnumeration?     true

  constructing another enumeration with different content...
    Enumeration == differentEnumeration? false

  examining the enumeration's properties:
  (no enumerable properties found)

Die gezeigte Programmausgabe entspricht größtenteils der der "LiveConnect"-Variante - allerdings fehlen diesmal jegliche aufzählbaren Datenfelder.

Rhino "Host Object"-Implementierung II

Die letzte Variante erweitert das zuvor beschriebene "Host Object" um die explizite Implementierung einer Methode der "Scriptable"-Schnittstelle, mit deren Hilfe die Liste der sichtbaren Datenfelder und Methoden kontrolliert werden kann. Das oben beschriebene Beispiel-Programm liefert in diesem Fall folgende Ausgabe:

  EnumeratorTest - tests the "sunda.rhino.data.Enumerator" class

  constructing an enumeration...
  printing the enumeration's contents:
   - true (more to come...)
   - 2 (more to come...)
   - anything (final element)

  printing the enumeration itself:
    (true,2,anything)

  constructing another enumeration with the same content...
    Enumeration == equalEnumeration?     true

  constructing another enumeration with different content...
    Enumeration == differentEnumeration? false

  examining the enumeration's properties:
   - actualElement: undefined
   - atEnd: function atEnd() {    [native code] }
   - equals: function equals() {  [native code] }
   - hasMoreElements: function hasMoreElements() {        [native code] }
   - moveFirst: function moveFirst() {    [native code] }
   - nextElement: function nextElement() {        [native code] }
   - toString: function toString() {      [native code] }

Wie aus der Programmausgabe ersichtlich, verhält sich diese Implementierung inzwischen praktisch genau so wie eine intrinsische Rhino-Klasse.

Quelltexte

Alle Java-Klassen und Rhino-Skripte sind auch im Quelltext verfügbar:

Literaturhinweise

[1]

Netscape
Tutorial: Embedding Rhino
(siehe http://www.mozilla.org/rhino/tutorial.html)
die angegebene Anleitung beschreibt Verfahren zur Verknüpfung von Java und JavaScript (Rhino);

[2]

Sun Microsystems, Inc.
java.util Interface Enumeration
(siehe http://java.sun.com/j2se/1.4/docs/api/java/util/Enumeration.html)
hinter der angegebenen URL verbirgt sich die im Netz verfügbare Beschreibung der Java-Klasse java.util.Enumeration;

[3]

Microsoft
JScript Documentation
(siehe http://msdn.microsoft.com/library/default.asp/?url=/library/en-us/script56/html/js56jsoriJScript.asp)
die Dokumentation zu Microsoft's JScript enthält nicht nur ein sehr schönes JScript-Tutorial, sondern beschreibt auch die Microsoft-spezifischen Erweiterungen des JavaScript-Standards (u.a. auch den Enumerator-Datentyp);

Haftungsausschluß

Bitte beachten Sie auch den Haftungsausschluß des Autors!

http://www.Andreas-Rozek.de/Rhino/Erweiterungen/Enumerator.html    (letzter Stand: 08.04.2002)