Руководство по actionscript. часть 1, стр. 137

Приведение типов

В предыдущем разделе рассказывалось, что в строгом режиме компилятор сообщает об ошибках обращения на этапе компиляции. Для выявления ошибок обращения

компилятор полагается на аннотации типов. Предположим, что компилятор встретил обращение к методу, выполненное через типизированную переменную. Чтобы выяснить, является ли данное обращение корректным, компилятор проверяет наличие описания вызываемого метода в классе или интерфейсе, указанном в аннотации типа данной переменной. Если метод, к которому происходит обращение, не определен в указанном классе или интерфейсе, компилятор генерирует ошибку обращения.

Обратите внимание, что необходимость генерации ошибки обращения определяется исходя из класса или интерфейса, указанного в аннотации типа, а не фактического класса значения, хранящегося в данной переменной.

Рассмотрим следующий код, в котором метод hasWorm ( ) вызывается над объектом Apple через переменную типа Food:

var meal:Food = new Apple( ):

meal. hasWorm( ); // Попытка вызвать метод hasWorm( ) над объектом, // хранящимся в переменной meal

При компиляции предыдущего кода в строгом режиме компилятор должен решить, может ли метод hasWorm ( ) быть вызван над значением переменной meal. Для этого компилятор проверяет, определен ли в классе Food (то есть в классе, который указан в аннотации типа переменной meal) метод hasWorm ( ). В этом классе определение данного метода отсутствует, поэтому компилятор генерирует ошибку обращения. Конечно, глядя на этот код, мы знаем, что значение переменной meal (объект Apple) поддерживает метод hasWorm ( ). Однако этого не знает компилятор. Среда выполнения Flash только на этапе выполнения узнает, что значением переменной на самом деле является объект Apple.

Каково же решение? Использовать операцию приведения типов, чтобы заставить компилятор разрешить предыдущий вызов метода hasWorm ( ). Операция приведения типов приказывает компилятору рассматривать данное значение как принадлежащее указанному типу данных. Эта операция имеет следующий обобщенный вид:

тип{выражение)

В этом коде тип — это любой тип данных, а выражение — любое выражение. Говоря простым языком, эта операция «приводит выражение к указанному типу тип». Например, следующий код приводит выражение meal к типу данных Apple перед вызовом метода hasWorm ( ) над значением переменной meal: Apple(meal).hasWorm( )

Руководство по actionscript. часть 1, стр. 138

Независимо от действительного значения переменной meal компилятор верит, что типом данных выражения meal является тип Apple. По этой причине, принимая решение о возможности вызова метода hasWorm ( ) над значением переменной meal, компилятор проверяет, определен ли метод hasWorm ( ) в классе Apple, но не в классе Food. Метод hasWorm ( ) определен в классе Apple, и следовательно, компилятор не генерирует никаких ошибок.

Однако операция приведения типов используется не только на этапе компиляции. На этапе выполнения программы ей также присуще определенное поведение: если выражение выражение преобразуется в объект, который принадлежит указанному типу

тип, то среда Flash просто возвращает этот объект. Однако если выражение выражение преобразуется в объект, который не принадлежит указанному типу тип, возможен один из двух вариантов завершения операции приведения типов. Если указанный тип тип не является примитивным, операция приведения типов вызовет ошибку на этапе выполнения; в противном случае значение объекта преобразуется в указанный тип (в соответствии с правилами, перечисленными в разд. «Преобразование в примитивные типы»), и результатом операции будет преобразованное значение.

Например, в следующем коде значение переменной meal, сформированное на этапе выполнения программы, принадлежит типу данных Apple, поэтому операция приведения типов во второй строке просто вернет объект Apple, на который ссылается переменная meal:

var meal:Food = new Applet );

Apple(meal); // На этапе выполнения вернет объект Apple

Для сравнения, в следующем коде значение переменной meal, сформированное на этапе выполнения программы, не принадлежит типу данных VirtualPet, и, поскольку тип данных VirtualPet не является примитивным, операция приведения типов во второй строке вызовет ошибку типа:

var meal:Food = new Apple( );

Vi rtualPet(meal); // На этапе выполнения будет вызвана ошибка типа

Наконец, в следующем коде значение переменной meal, сформированное на этапе выполнения программы, не принадлежит типу данных Boolean, но, поскольку тип данных Boolean является примитивным, операция приведения типов во второй строке преобразует значение переменной meal в указанный тип и вернет результат данного преобразования (true):

Руководство по actionscript. часть 1, стр. 139

Var meal:Food = new Apple( );

Boolean(meal): // На этапе выполнения будет возвращено значение true

Избавление от нежелательных ошибок несоответствия типов

Как уже известно, операции приведения типов могут быть использованы для выявления нежелательных ошибок обращения на этапе компиляции. Подобным образом операции приведения типов могут применяться для избавления от нежелательных ошибок несоответствия типов.

В качестве примера представьте программу, которая преобразует температуру, заданную по шкале Фаренгейта, в температуру по шкале Цельсия. Значение температуры по шкале Фаренгейта вводится в текстовое поле, представленное экземпляром внутреннего класса TextField. Для получения введенного значения мы обращаемся к переменной text экземпляра класса TextField, как показано в следующем коде:

var fahrenheit:Number = inputField. text;

В данных условиях такой код вызовет ошибку несоответствия типов, поскольку типом данных переменной text является String. Чтобы избавиться от этой ошибки, мы используем операцию приведения типов, как показано в следующем коде:

var fahrenheit:Number = NumberCinputField. text):

На этапе выполнения программы этот код преобразует строковое значение, хранящееся в переменной inputField. text, в тип Number и присвоит преобразованное значение переменной fahrenheit.

Восходящее и нисходящее приведения типов

Приведение типа объекта к одному из его супертипов (суперклассу или суперинтерфейсу) называется восходящим приведением типов. Например, следующая операция осуществляет восходящее приведение типов, поскольку тип данных Food является супертипом типа Apple:

Food(new Apple( ))

И наоборот, приведение типа объекта к одному из его подтипов (подклассу или подинтерфейсу) называется нисходящим приведением, поскольку эта операция выполняет приведение типа объекта к типу, который находится ниже текущего в иерархии. Следующая операция осуществляет нисходящее приведение типов, поскольку тип данных Apple является подтипом типа Food:

Apple(new Food( ))

Говорят, что восходящее приведение типов «расширяет» тип объекта, поскольку супертип является более обобщенным по сравнению с его подтипом. В то же время нисходящее приведение типов «сужает» тип объекта, поскольку подтип является более специализированным, чем его супертип.

Кроме того, восходящее приведение типов считается безопасным, поскольку оно никогда не вызывает ошибку на этапе выполнения. Как было сказано ранее, экземпляр подтипа можно всегда рассматривать как экземпляр любого из его супертипов, потому что он гарантированно (через наследование) обладает всеми методами и переменными экземпляра своих супертипов в том случае, если эти методы и переменные объявлены с использованием любых модификаторов управления доступом, кроме private.

Руководство по actionscript. часть 1, стр. 140

И наоборот, нисходящее приведение типов считается небезопасным, поскольку оно способно вызвать ошибку на этапе выполнения. Чтобы гарантировать, что операция нисходящего приведения типов не вызовет ошибку на этапе выполнения, перед приведением типов мы должны убедиться в фактической принадлежности рассматриваемого объекта к целевому типу данных. Для выполнения проверки типа данных объекта используется оператор is, имеющий следующий вид:

выражение is тип

В предыдущем коде выражение обозначает любое выражение, а тип — любой класс или интерфейс (тип не должен принимать значения undefined или null). Оператор i s возвращает значение true, если заданное выражение принадлежит указанному типу тип, в противном случае возвращается значение false.

В следующем коде используется оператор is, чтобы гарантировать, что нисходящее приведение типов не вызовет ошибку на этапе выполнения:

var apple:Food = new Apple( ); if (apple is Apple) {

Apple(apple).hasWorm( ):

}

В предыдущем коде блок условного оператора будет выполнен только в том случае, если переменная apple ссылается на объект, принадлежащий типу Apple. По этой причине операция приведения типов Apple (apple) никогда не вызовет ошибку.

Использование оператора as для приведения к типам Date и Array

По многим причинам, связанным с поддержкой старого кода в языке ActionScript 3.0, синтаксис приведения типов, описанный в предыдущих разделах, не может быть использован для приведения типа значения к внутренним классам Date и Array. Результат выражения Date (некотороеЗначение) идентичен результату выражения new Date ( ) . toString( ) (оно возвращает строковое представление текущего времени). Результат выражения Array (некотороеЗначение) идентичен результату выражения new Array (некотороеЗначение) (оно создает новый объект Array, первым элементом которого является значение некотороеЗначение).

Для приведения типа результата выражения либо к классу Date, либо к классу Array используется оператор as, который действует точно так же, как операция приведения типов, но с одним исключением — данный оператор возвращает значение null в тех случаях, когда операция приведения типов вызывает ошибку на этапе выполнения. Оператор as имеет следующий вид:

Руководство по actionscript. часть 1, стр. 141

Выражение as тип

В приведенном коде выражение представляет любое выражение, а тип — любой класс или интерфейс (тип не должен принимать значения undefined или null). Оператор as возвращает значение выражения выражение, если указанное выражение принадлежит указанному типу тип, в противном случае возвращается значение null.

Например, в следующем коде результат выражения (meal as Apple) идентичен результату операции приведения типов Apple (meal):

var meal:Food = new Apple( ); (meal as Apple).hasWorm( );

В следующем коде оператор as используется для «приведения» объекта Array к типу данных Array с тем, чтобы данный объект можно было присвоить переменной типа Array.

public function output (msg:Object):void { if (msg is String) { trace(msg);

}

if (msg is Array) { var arr:Array = msg as Array: // Приведение к типу Array

trace(arr. join(«\n»));

Следующий код демонстрирует результат передачи тестового объекта Array в метод output ( ):

var numbers:Array = [1,2,3] output(numbers):

// Вывод:

1

2

3

Преобразование в примитивные типы

В предыдущем разделе рассказывалось, что если выражение приводится к примитивному типу, к которому оно не принадлежит, то его значение будет преобразовано в указанный тип. Например, рассмотрим следующий код, который выполняет приведение объекта Date к примитивному типу данных Boolean:

Boolean(new Date( ))

Поскольку тип данных Boolean является примитивным типом, а объект Date не принадлежит типу Boolean, среда выполнения Flash преобразует значение объекта Date в тип Boolean. Результатом данного преобразования будет являться значение true типа Boolean.

Операции приведения типов иногда используются не для того, чтобы сообщить компилятору тип заданного выражения, а для того, чтобы преобразовать значение этого выражения в примитивный тип данных.

I Операция приведения типов может преобразовать любое значение в конкретный при-

ч?’ 4 , митивный тип.

_ Щ’-

Например, следующий код преобразует число с плавающей точкой (с дробной частью) в целое число (без дробной части):

int(4.93)

Результатом этой операции приведения типов является целое число 4. Подобным образом следующий код преобразует значение true типа Boolean в целое число 1, а значение false типа Boolean — в целое число 0:

int(true): // Возвращает 1 int(false); // Возвращает О

Такая методика может применяться для уменьшения размера передаваемых на сервер данных, включающих ряд значений типа Boolean.

В табл. 8.1 представлены результаты преобразования различных типов данных в тип Number.

Таблица 8.1. Преобразование в тип Number

Исходные данные Результат после преобразования

undefined NaN (специальное числовое значение «Не число» (Not a Number), представляющее некорректные числовые данные)

Исходные данные Результат после преобразования

null 0

int То же число

uint То же число

Boolean 1, если исходным значением является true; 0# если исходным значением является false

Numeric в строковом представлении Эквивалентное числовое значение, если строка состоит только из цифр десятичной или шестнадцатеричной систем счислений, пробела, экспоненты, десятичной точки, знаков + или — (например, строка («-L485e2″) превратится в число -148.5)

Пустая строка 0

«Бесконечность» Infinity

«Минус бесконечность» — Infinity

Другие строки NaN

Объект NaN

В табл. 8.2 представлены результаты преобразования различных типов данных в тип int.

Таблица 8.2. Преобразование к типу int

Исходные данные Результат после преобразования

undefined 0

null 0

Number или uint Целое число в диапазоне от -231 до 231-1; значения, превышающие диапазон представления, включаются в указанный диапазон с помощью алгоритма, описанного в разд. 9.5 третьей редакции стандарта ЕСМА-262

Boolean 1, если исходным значением является true; 0, если исходным значением является false

Numeric в строковом представлении Эквивалентное числовое значение, преобразованное в целочисленный знаковый формат

Пустая строка 0

«Бесконечность» 0

«Минус бесконечность» 0

Другие строки 0

Объект 0

В табл. 8.3 представлены результаты преобразования различных типов данных в тип uint.

Таблица 8.3. Преобразование в тип uint

Исходные данные Результат после преобразования

undefined 0

null 0

Number или int Целое число в диапазоне от 0 до 231-1; значения, превышающие диапазон представления, включаются в указанный диапазон с помощью алгоритма, описанного в разд. 9.6 третьей редакции стандарта ЕСМА-262

Продолжение ^

196 Глава 8. Типы данных и проверка типов

Таблица 8.3 (иродо. г/ксммс)

Исходные данные Результат после преобразования

Boolean 1, если исходным значением является true; 0, если исходным значением является false

Numeric в строковом представлении Эквивалентное числовое значение, преобразованное в целочисленный беззнаковый формат

Пустая строка 0

«Бесконечность» 0

«Минус бесконечность» 0

Другие строки 0

Объект 0

В табл. 8.4 представлены результаты преобразования различных типов данных в тип String.

Таблица 8.4. Преобразование в тип String

Исходные данные Результат после преобразования

undefined «undefined»

null «null»

Boolean «true», если исходным значением является true; «false», если исходным значением является false

NaN «NaN»

0 «0″

«Бесконечность» «Infinity»

«Минус бесконечность» «-Infinity»

Другое числовое значение Строковое представление указанного числа. Например, число 944.345 превратится в строку «944.345″

Объект Значение, полученное в результате вызова метода toString() над объектом. По умолчанию метод объекта toString() возвращает строку «[object имяКласса]«, где имяКласса представляет класс объекта. Метод toString() может быть переопределен для получения более полезной информации. Например, метод toString() объекта Date возвращает время в удобочитаемом формате наподобие «Sun May 14 11:38:10 EDT 2000″, а метод toString() объекта Array возвращает список элементов массива, разделенных запятыми

В табл. 8.5 представлены результаты преобразования различных типов данных в тип Boolean.

Таблица 8.5. Преобразование в тип Boolean

Исходные данные Результат после преобразования

undefined false

null false

NaN false

0 false

Infinity true

-Infinity true

Другое числовое значение true

Непустая строка true

Исходные данные Результат после преобразования

Пустая строка («») false

Объект true

Значения переменных по умолчанию

Когда переменная объявлена без аннотации типа и без указания исходного значения, в качестве исходного значения этой переменной автоматически присваивается значение undefined (единственное значение типа данных void). Когда переменная объявлена с аннотацией типа, но без указания исходного значения, в качестве ее исходного значения автоматически присваивается значение по умолчанию, соответствующее указанному типу данных.

Руководство по actionscript. часть 1, стр. 142

В табл. 8.6 перечислены значения по умолчанию для каждого конкретного типа данных в языке ActionScript, используемые при объявлении переменных.

Таблица 8.6. Значения переменных по умолчанию

Тип данных Значение по умолчанию

String null

Boolean false

int 0

uint 0

Number NaN

Все остальные типы null

Значения null и undefined

В одной из предыдущих глав рассказывалось, что каждый из типов данных — Null и void — включает по одному-единственному значению — null и undefined соответственно. Теперь, когда мы познакомились с типами данных и аннотациями типов, рассмотрим, чем же отличаются эти два значения.

Концептуально оба значения — null и undefined — обозначают отсутствие данных. Значение null обозначает отсутствие данных для переменных, параметров и возвращаемых значений, объявленных с использованием аннотаций типов, кроме типов Boolean, int, uint и Number. Например, следующий код создает типизированную переменную экземпляра pet типа VirtualPet. До тех пор пока переменной не будет явно присвоено значение в программе, ее значением будет являться null.

package { import flash. display. Sprite; import zoo.*;

public class VirtualZoo extends Sprite { private var pet:Virtual Pet;

public function VirtualZoo ( ) { trace(pet): // Выводит: null

}

}

}

Напротив, значение undefined обозначает отсутствие данных для переменных, параметров и возвращаемых значений, объявленных без использования аннотаций типов. Например, следующий код создает объект с двумя динамическими переменными экземпляра — city и country. Этот код использует значение undefined при присваивании переменной country исходного значения, чтобы показать, что она пока не имеет осмысленного значения.

var info = new Object( ): info. city = «Toronto»: info. country = undefined;

Кроме того, значение undefined обозначает полное отсутствие переменной или метода у объекта, чей класс объявлен с использованием атрибута dynamic. Например, в результате следующей попытки обратиться к несуществующей переменной объекта, на который ссылается переменная info, будет возвращено значение undefined:

Руководство по actionscript. часть 1, стр. 143

Trace(info. language); // Выводит: undefined

Более подробно динамические возможности языка ActionScript и значение undefined будут рассмотрены в гл. 15.

Типы данных в программе по созданию виртуального зоопарка

Теперь, когда мы получили всю информацию о типах данных, добавим аннотации типов в нашу программу «Зоопарк». В листинге 8.1 представлен измененный код класса VirtualZoo — основного класса программы.

Листинг 8.1. Класс VirtualZoo

package { import flash. display. Sprite; import zoo.*;

public class VirtualZoo extends Sprite { private var pet:VirtualPet;

public function VirtualZoo ( ) { pet = new VirtualPet(«Stan»); pet. eat(new Apple( )); pet. eat(new Sushi( ));

Листинг 8.2 демонстрирует код класса VirtualPet, экземпляры которого представляют животных в зоопарке. Обратите внимание на использование операции приведения типов в методе eat ( ), рассмотренной в подразд. «Восходящее и нисходящее приведения типов» разд. «Приведение типов».

Листинг 8.2. Класс VirtualPet

package zoo { import flash. utils. setlnterval; import flash. utils. clearInterval;

internal class VirtualPet { private static var maxNameLength:int = 20; private static var maxCalories:int = 2000; private static var caloriesPerSecond:int = 100;

private var petName:String;

private var currentCalories:int = Virtual Pet. maxCalories/2; private var digestlntervalID:int;

public function VirtualPet (name:String):void { setName(name);

digestlntervallD = setlnterval(digest. 1000);

}

public function eat (foodItern:Food):void { if (currentCalories == 0) { trace(getName( ) + » is dead. You can’t feed it.»); return;

}

if (foodltem is Apple) { // Обратите внимание на приведение к типу Apple if (Apple(foodltem).hasWorm( )) { traceCThe » + foodltem. getName( ) + » had a worm. » + getName( )

+ » didn’t eat it.»): return;

}

}

var newCurrentCalories:int = currentCalories + foodltem. getCalories( ); if (newCurrentCalories > Virtual Pet. maxCalories) {

currentCalories = Virtual Pet. maxCalories; } else {

currentCalories = newCurrentCalories;

}

trace(getName( ) + » ate some » + foodltem. getName( ) + «.»

+ » It now has » + currentCalories + » calories remaining.»);

}

public function getHunger ( ):Number { return currentCalories / Virtual Pet. maxCalories;

public function setName (newName:String):void { // Если длина заданного нового имени // больше maxNameLength символов… if (newName. length > Virtual Pet. maxNameLength) { // …обрезать имя

newName = newName. substr(0, VirtualPet. maxNameLength); } else if (newName == «») { // …в противном случае, если заданное новое имя является // пустой строкой, завершить выполнение метода, не изменяя // значения переменной petName return;

}

// Присвоить новое проверенное имя переменной petName petName = newName;

}

public function getName ( ):String { return petName;

}

private function digest ( ):void { // Если в результате потребления очередной порции калорий // значение переменной currentCalories животного // станет равным 0 или меньше…

if (currentCalories — Virtual Pet. caloriesPerSecond <= 0) {

// …прекратить вызов метода digest( )

clearlnterval(digestlntervalID);

// После чего очистить желудок животного

currentCalories = 0;

// и сообщить о смерти животного

trace(getName( ) + » has died.»); } else {

// …иначе употребить оговоренное количество калорий currentCalories -= Virtual Pet. caloriesPerSecond;

// и сообщить о новом состоянии животного trace(getName( ) + » digested some food. It now has » + currentCalories + » calories remaining.»);

}

}

}

}

Листинг 8.3 демонстрирует код класса Food, являющегося суперклассом для различных видов пищи, принимаемой животными.

Листинг 8.3. Класс Food

package zoo { public class Food { private var calories:int;

private var name:String; public function Food (initialCalories:int) { setCalories(initialCalories);

}

public function getCalories ( ):int { return calories;

}

public function setCalories (newCalories:int):void { calories = newCalories;

}

public function getName ( ):String { return name;

}

public function setName (newName:String):void { name = newName;

}

}

}

Листинг 8.4 демонстрирует код класса Apple, представляющего конкретный вид пищи, принимаемой животными.

Листинг 8.4. Класс Apple

package zoo { public class Apple extends Food { private static var DEFAULT_CALORIES:int = 100; private var wormlnApple:Boolean;

public function Apple (initialCalories:int = 0) { if (initialCalories <= 0) { initialcalories = apple.default_calories;

}

super(initialCalories); wormlnApple = Math. random( ) >= .5; setName(«Apple»);

}

public function hasWorm ( ):Boolean { return wormlnApple;

}

}

}

Наконец, листинг 8.5 демонстрирует код класса Sushi, представляющего конкретный вид пищи, принимаемой животными.

Листинг 8.5. Класс Sushi

package zoo { public class Sushi extends Food { private static var DEFAULT_CALORIES:int = 500:

public function Sushi (initialCalories:int = 0) { if (initialCalories <= 0) { initialcalories = sushi.default_calories:

}

super(i niti alCalories); setName(«Sushi»);

}

}

}

Далее: дополнительное изучение типов данных

В этой главе было рассказано, как использование типов данных помогает выявить и устранить потенциальные проблемы в программе. В следующей главе мы завершим наше обзорное изучение типов данных, рассмотрев интерфейсы. Интерфейсы, как и классы, применяются для создания пользовательских типов данных.

Зачем используется раскройка изображения в Photoshop и как ее сделать?

Разрезание изображения на части выполняют web-дизайнеры для того, чтобы изображения быстрее подгружались в Интернете.
Открываем изображение, которое нужно разрезать. Берем инструмент Раскройка и выделяем несколько однородных областей. С помощью инструмента Выделение фрагмента можно изменять размеры областей. Прочитать остальную часть записи »

Разница между растровым и векторным изображением

Растровое изображение состоит из пикселей (точек) разных цветов, векторное – из объектов (геометрических фигур).
Каждый из этих видов имеет свои плюсы и минусы.

Растровая графика Прочитать остальную часть записи »

Подбор цветовой палитры с помощью Color Scheme Designer

Почти каждый web-дизайнер ломал голову над разработкой цветовой гаммы для сайта. Благодаря развитию технологий этот мучительный процесс можно облегчить.
Color Scheme Designer является web-сервисом для подбора цветовой палитры. Он станет в помощь, как специалистам, так и начинающим web творцам. Достаточно простой интерфейс не составит труда в его понимании. Прочитать остальную часть записи »



Полезные ссылки
Случайные записи
  • 12.11.2011">Абстрактная иллюстрация в Фотошопе
  • 02.03.2011">Руководство по actionscript. часть 5, стр. 087
  • 17.05.2010">Самоучитель по креативному веб-дизайну. Книга 2, стр.126
  • 11.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.26
  • 23.01.2011">Руководство по actionscript. часть 1, стр. 043
  • 03.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.48
  • 11.03.2011">Руководство по actionscript. часть 4, стр. 005
  • 18.03.2011">Руководство по actionscript. часть 2, стр. 135
  • 09.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.159
  • 03.06.2010">Самоучитель по креативному веб-дизайну. Книга 3, стр.96
  • 10.05.2010">Самоучитель по креативному веб-дизайну. Книга 1, стр.63
  • 14.03.2011">Руководство по actionscript. часть 3, стр. 074
  • 16.03.2011">Руководство по actionscript. часть 3, стр. 017
  • 02.03.2011">Руководство по actionscript. часть 5, стр. 092
  • 23.02.2011">Руководство по actionscript. часть 7, стр. 028
Опрос

Какие цвета вы предпочитаете?

View Results

Loading ... Loading ...