Die Array-Klasse ist eine der wenigen Hauptklassen, die nicht endgültig festgelegt („final“) ist. Dies bedeutet, dass Sie Unterklassen der Array-Klasse erstellen können. In diesem Abschnitt wird an einem Beispiel erläutert, wie eine Unterklasse der Array-Klasse erstellt wird. Darüber hinaus werden einige Probleme erörtert, die unter Umständen auftreten können.
Wie weiter oben erwähnt, sind Arrays in ActionScript nicht typisiert, Sie können jedoch eine Array-Unterklasse erstellen, die nur Elemente eines bestimmten Datentyps enthalten kann. In dem Beispiel in den folgenden Abschnitten wird eine Array-Unterklasse mit dem Namen „TypedArray“ erstellt, bei der die Elemente auf Werte des im ersten Parameter angegebenen Datentyps beschränkt sind. Die TypedArray-Klasse wird hier lediglich exemplarisch zur Erweiterung der Array-Klasse verwendet und eignet sich möglicherweise aus mehreren Gründen nicht für die Praxis. Erstens erfolgt die Typüberprüfung zur Laufzeit und nicht bei der Kompilierung. Zweitens werden Diskrepanzen ignoriert, die in der TypedArray-Methode auftreten können, und keine Ausnahmen ausgelöst. Die Methoden können jedoch auf einfache Weise so geändert werden, dass Ausnahmen ausgelöst werden. Mit der Klasse kann drittens nicht verhindert werden, dass über den Array-Zugriffsoperator Werte jedes Datentyps in das Array eingefügt werden. Darüber hinaus wurde beim Programmierstil auf Einfachheit statt auf Leistungsoptimierung gesetzt.
Hinweis:
Sie können ein Typ-Array mit den hier beschriebenen Techniken erstellen. Es empfiehlt sich jedoch, stattdessen ein Vector-Objekt zu verwenden. Eine Vector-Instanz ist ein Typ-Array in Reinform und bietet im Vergleich mit der Array-Klasse oder den Unterklassen Leistungssteigerungen und weitere Vorteile. In diesem Abschnitt soll die Erstellung einer Array-Unterklasse veranschaulicht werden.
Deklarieren der Unterklasse
Geben Sie mit dem Schlüsselwort
extends
an, dass es sich um eine Unterklasse der Array-Klasse handelt. Bei einer Array-Unterklasse sollte wie bei der Array-Klasse das
dynamic
-Attribut verwendet werden. Andernfalls kann die Unterklasse nicht ordnungsgemäß verwendet werden.
Im folgenden Code ist die Definition der TypedArray-Klasse dargestellt. Sie enthält eine Konstante für den Datentyp, eine Konstruktormethode und die vier Methoden zum Hinzufügen von Elementen zum Array. Der Code für die einzelnen Methoden ist im folgenden Codebeispiel nicht angegeben, er wird jedoch in den folgenden Abschnitten getrennt und vollständig erläutert.
public dynamic class TypedArray extends Array
{
private const dataType:Class;
public function TypedArray(...args) {}
AS3 override function concat(...args):Array {}
AS3 override function push(...args):uint {}
AS3 override function splice(...args) {}
AS3 override function unshift(...args):uint {}
}
Bei allen vier überschriebenen Methoden wird der AS3-Namespace anstelle des
public
-Attributs verwendet, da in diesem Beispiel davon ausgegangen wird, dass die Compileroption
-as3
auf
true
und die Compileroption
-es
auf
false
gesetzt ist. Dies sind die Standardeinstellungen für Adobe Flash Builder und AdobeFlashProfessional.
Erfahrene Entwickler, die die Verwendung der Prototypvererbung bevorzugen, können zwei kleine Änderungen an der TypedArray-Klasse vornehmen, sodass diese mit der auf
true
gesetzten Compileroption
-es
kompiliert werden kann. Entfernen Sie zunächst alle Vorkommen des
override
-Attributs und ersetzen Sie den AS3-Namespace durch das
public
-Attribut. Ersetzen Sie dann alle vier Vorkommen von
super
durch
Array.prototype
.
TypedArray-Konstruktor
Der Konstruktor der Unterklasse stellt eine interessante Herausforderung dar, da er eine Liste mit Argumenten beliebiger Länge annehmen muss. Die Herausforderung besteht in der Weise, auf die die Argumente an den Superkonstruktor übergeben werden, um das Array zu erstellen. Wenn Sie die Liste der Argumente als Array übergeben, wird sie im Superkonstruktor als einzelnes Argument des Array-Typs erkannt, und das resultierende Array hat immer die Länge eines Elements. Normalerweise werden übergebene Argumentlisten mithilfe der
Function.apply()
-Methode verarbeitet, bei der ein Array mit Argumenten als zweiter Parameter verwendet wird, das Array jedoch beim Ausführen der Funktion in eine Liste mit Argumenten konvertiert wird. Leider kann die
Function.apply()
-Methode bei Konstruktoren nicht verwendet werden.
Die einzige verbleibende Möglichkeit besteht darin, den Code des Array-Konstruktors im TypedArray-Konstruktor neu zu erstellen. Im folgenden Codebeispiel ist der im Konstruktor der Array-Klasse verwendete Algorithmus dargestellt, den Sie im Konstruktor der Array-Unterklasse wiederverwenden können:
public dynamic class Array
{
public function Array(...args)
{
var n:uint = args.length
if (n == 1 && (args[0] is Number))
{
var dlen:Number = args[0];
var ulen:uint = dlen;
if (ulen != dlen)
{
throw new RangeError("Array index is not a 32-bit unsigned integer ("+dlen+")");
}
length = ulen;
}
else
{
length = n;
for (var i:int=0; i < n; i++)
{
this[i] = args[i]
}
}
}
}
Für den TypedArray-Konstruktor wird im Wesentlichen der gleiche Code verwendet wie beim Array-Konstruktor, es werden nur vier Änderungen am Code vorgenommen. Die Parameterliste enthält erstens einen neuen erforderlichen Parameter des Class-Typs, mit dem der Datentyp des Arrays angegeben werden kann. Der an den Konstruktor übergebene Datentyp wird zweitens der
dataType
-Variablen zugewiesen. In der
else
-Anweisung wird drittens der Wert der
length
-Eigenschaft nach der
for
-Schleife zugewiesen, sodass
length
nur Argumente mit dem korrekten Datentyp enthält. Im Rumpf der
for
-Schleife wird viertens die überschriebene Version der
push()
-Methode verwendet, sodass ausschließlich Argumente mit dem korrekten Datentyp zum Array hinzugefügt werden. Im folgenden Beispiel ist die TypedArray-Konstruktorfunktion dargestellt:
public dynamic class TypedArray extends Array
{
private var dataType:Class;
public function TypedArray(typeParam:Class, ...args)
{
dataType = typeParam;
var n:uint = args.length
if (n == 1 && (args[0] is Number))
{
var dlen:Number = args[0];
var ulen:uint = dlen
if (ulen != dlen)
{
throw new RangeError("Array index is not a 32-bit unsigned integer ("+dlen+")")
}
length = ulen;
}
else
{
for (var i:int=0; i < n; i++)
{
// type check done in push()
this.push(args[i])
}
length = this.length;
}
}
}
Überschriebene Methoden der TypedArray-Klasse
Bei der TypedArray-Klasse werden die vier Methoden der Array-Klasse überschrieben, mit denen Elemente zu einem Array hinzugefügt werden können. Bei allen überschriebenen Methoden wird jeweils eine Typüberprüfung eingefügt, über die verhindert wird, dass Elemente mit einem ungültigen Datentyp hinzugefügt werden. Anschließend wird bei allen Methoden die Superclass-Version der jeweiligen Methode aufgerufen.
Die
push()
-Methode durchläuft die Liste der Argumente mit einer
for..in
-Schleife und führt für jedes Argument eine Typüberprüfung durch. Alle Argumente, die nicht den korrekten Datentyp aufweisen, werden mit der
splice()
-Methode aus dem
args
-Array entfernt. Nach Abschluss der
for..in
-Schleife enthält das
args
-Array nur Werte mit dem Typ
dataType
. Die Superclass-Version von
push()
wird dann mit dem aktualisierten
args
-Array aufgerufen, wie im folgenden Codebeispiel dargestellt:
AS3 override function push(...args):uint
{
for (var i:* in args)
{
if (!(args[i] is dataType))
{
args.splice(i,1);
}
}
return (super.push.apply(this, args));
}
Mit der
concat()
-Methode wird das temporäre TypedArray-Array mit dem Namen
passArgs
erstellt, in dem die Argumente nach erfolgreicher Typüberprüfung gespeichert werden. Dadurch kann der in der
push()
-Methode vorhandene Code für die Typüberprüfung erneut verwendet werden. Mit einer
for..in
-Schleife wird das
args
-Array durchlaufen. Anschließend wird
push()
für jedes Argument aufgerufen. Da
passArgs
als TypedArray typisiert ist, wird die TypedArray-Version von
push()
ausgeführt. Mit der
concat()
-Methode wird dann die zugehörige Superclass-Version aufgerufen, wie im folgenden Codebeispiel dargestellt:
AS3 override function concat(...args):Array
{
var passArgs:TypedArray = new TypedArray(dataType);
for (var i:* in args)
{
// type check done in push()
passArgs.push(args[i]);
}
return (super.concat.apply(this, passArgs));
}
Bei der
splice()
-Methode wird eine beliebig lange Liste mit Argumenten verwendet. Die ersten beiden Argumente verweisen jedoch immer auf eine Indexposition und die Anzahl der zu löschenden Elemente. Aus diesem Grund wird mit der überschriebenen
splice()
-Methode nur eine Typüberprüfung der Elemente des
args
-Arrays ab Indexposition 2 durchgeführt. Im Codebeispiel wird in der
for
-Schleife scheinbar ein rekursiver Aufruf von
splice()
ausgeführt. Es handelt sich jedoch um keinen rekursiven Aufruf, da
args
den Array-Typ und nicht den TypedArray-Typ aufweist. Dies bedeutet, dass beim Aufrufen von
args.splice()
die Superclass-Version der Methode aufgerufen wird. Nach Abschluss der
for..in
-Schleife enthält das
args
-Array ab Indexposition 2 nur Werte mit dem korrekten Datentyp. Mit
splice()
wird zudem die zugehörige Superclass-Version aufgerufen, wie im folgenden Codebeispiel dargestellt:
AS3 override function splice(...args):*
{
if (args.length > 2)
{
for (var i:int=2; i< args.length; i++)
{
if (!(args[i] is dataType))
{
args.splice(i,1);
}
}
}
return (super.splice.apply(this, args));
}
Bei der
unshift()
-Methode, mit der Elemente am Anfang eines Arrays hinzugefügt werden, kann ebenfalls eine beliebige Liste mit Argumenten übergeben werden. Bei der überschriebenen
unshift()
-Methode wird ein ähnlicher Algorithmus wie bei der
push()
-Methode verwendet, wie im folgenden Codebeispiel dargestellt:
AS3 override function unshift(...args):uint
{
for (var i:* in args)
{
if (!(args[i] is dataType))
{
args.splice(i,1);
}
}
return (super.unshift.apply(this, args));
}
}