Lecture11 (1133568), страница 2
Текст из файла (страница 2)
Вместо кода у таких методовсразу после описания полной сигнатуры идет точка с запятой. Они по определенным правиламреализуются в виде функций на языке C (или на другом языке, если можно в результатекомпиляции получить библиотеку с интерфейсом на C). Внешние методы, а также свойства,индексированные свойства, события и операторы, привязываемые по определенным правилам кфункциям, которые имеют интерфейс на C и не вложены в среду .NET, есть и в C# — там такиеоперации помечаются как extern.В Java, помимо перечисленных членов типов,имеются инициализаторы.
Их описаниеприведено ниже.Инициализаторы относятся только к томуклассу, в котором они определены, их нельзяперегрузить.В C# члены типов, помимо методов, полей,конструкторов и вложенных типов, могут бытьконстантами, свойствами, индексированнымисвойствами, событиями или операторами.Кроме этого, в типе можно определитьдеструктор и статический конструктор.Нестатические свойства, индексированныесвойства и события можно перегружать внаследниках. Остальные из перечисленныхэлементов относятся только к тому классу, вкотором описаны.Для многих из дополнительных разновидностей членов типов, имеющихся в C#, естьаналогичные идиомы в компонентной модели JavaBeans [8,9], предназначенной для построенияэлементов пользовательского интерфейса и широко используемой в рамках Java технологий длясоздания компонентов, структуру которых можно анализировать динамически на основепредлагаемых JavaBeans соглашений об именовании методов.
Далее вместе с примерами кода наC# в правом столбце в левом приводится аналогичный код, написанный в соответствии JavaBeans.Константы в Java принято оформлять в видеполей с модификаторами final static.Модификатор final для поля означает, чтоприсвоить ему значение можно только один рази сделать это нужно либо в статическоминициализаторе класса (см. ниже), если полестатическое, либо в каждом из конструкторов,если поле нестатическое.Константы являются единождывычисляемыми и неизменными далеезначениями, хранящимися в классе илиструктуре.Пример объявления константы приведен ниже.public class A2{public static final double PHI =1.61803398874989;}public class A2{public const double Phi =1.61803398874989;}Компонентная модель JavaBeans определяетсвойство (property) класса A, имеющее имяname и тип T, как набор из одного или двухметодов, декларированных в классе A — TgetName() и void setName(T), называемыхметодами доступа (accessor methods) ксвойству.Свойство может быть доступным только длячтения, если имеется лишь метод get, и толькодля записи, если имеется лишь метод set.Если свойство имеет логический тип, дляметода чтения этого свойства используется имяisName().Эти соглашения широко используются вразработке Java программ, и такие свойстваописываются не только у классов,предназначенных стать компонентамиJavaBeans.Они и стали основанием для введенияспециальной конструкции для описания свойствв C#.Свойства (properties) представляют собой«виртуальные» поля.
Каждое свойство имеетодин или оба метода доступа get и set,которые определяют действия, выполняемыепри чтении и модификации этого свойства. Обаметода доступа описываются внутридекларации свойства. Метод set используетспециальный идентификатор value для ссылкина устанавливаемое значение свойства.Обращение к свойству — чтение (возможно,только если у него есть метод get) илиизменение значения свойства (возможно, толькоесли у него есть метод set) — происходит также, как к полю.При перегрузке свойства в наследникахперегружаются методы доступа к нему.Пример объявления свойств и их использованияприведен ниже.using System;public class MyArrayList{private int[] items = new int[10];private int size = 0;public class MyArrayList{private int[] items = new int[10];private int size = 0;public int getSize(){return size;}public int Size{get { return size; }}public int getCapacity()public int Capacity{{return items.Length;get { return items.Length; }set{int[] newItems = new int[value];Array.Copy(items, newItems, size);items = newItems;}}public void setCapacity(int value){int[] newItems = new int[value];System.arraycopy(items, 0, newItems, 0, size);items = newItems;}}public static void Main(){MyArrayList l = new MyArrayList();Console.WriteLine( l.Size );Console.WriteLine( l.Capacity );l.Capacity = 50;Console.WriteLine( l.Size );Console.WriteLine( l.Capacity );}public static void main(String[] args){MyArrayList l = new MyArrayList();System.out.println(l.getSize());System.out.println(l.getCapacity());l.setCapacity(50);System.out.println(l.getSize());System.out.println(l.getCapacity());}}}JavaBeans определяет индексированноесвойство (indexed property) класса A, имеющееимя name и тип T, как один или пару методов TgetName(int) и void setName(int, T).Свойства могут быть индексированы толькоодним целым числом.
В дальнейшемпредполагалось ослабить это ограничение иразрешить индексацию несколькимипараметрами, которые могли бы иметь разныетипы. Однако с 1997 года, когда появиласьпоследняя версия спецификаций JavaBeans [9],этого пока сделано не было.Индексированное свойство или индексер(indexer) — это свойство, зависящее от наборапараметров.В C# может быть определен только одининдексер для типа и данного набора типовпараметров.
Т.е. нет возможности определятьсвойства с разными именами, но одинаковыминаборами индексов.Обращение к индексеру объекта (или класса,т.е. статическому) производится так, как будтоэтот объект (класс) был бы массивом,индексированным набором индексовсоответствующих типов.При перегрузке индексера в наследникахперегружаются методы доступа к нему.Индексеры должны быть нестатическими.Обращение к индексеру класса-предка виндексере наследника организуется с помощьюконструкции base[…].Пример декларации и использования индексераприведен ниже.using System;public class MyArrayList{int[] items = new int[10];int size = 0;public int getItem(int i){if (i < 0 || i >= 10) throw newIllegalArgumentException();else return items[i];}public class MyArrayList{int[] items = new int[10];int size = 0;public int this[int i]{get{if (i < 0 || i >= 10) throw newIndexOutOfRangeException();else return items[i];}set{if (i < 0 || i >= 10) throw newIndexOutOfRangeException();else items[i] = value;}public void setItem(int i, int value){if (i < 0 || i >= 10) throw newIllegalArgumentException();else items[i] = value;}}public static void main(String[] args){MyArrayList l = new MyArrayList();l.setItem(0, 23);l.setItem(1, 75);l.setItem(1, l.getItem(1)-1);l.setItem(0,l.getItem(0) + l.getItem(1));System.out.println (l.getItem(0));System.out.println (l.getItem(1));}public static void Main(){MyArrayList l = new MyArrayList();l[0] = 23;l[1] = 75;l[0] += (--l[1]);Console.WriteLine(l[0]);Console.WriteLine(l[1]);}}}События (events) в модели JavaBeans служатдля оповещения набора объектовнаблюдателей (listeners) о некоторыхизменениях в состоянии объекта-источника(source).При этом класс EventType объектов,представляющих события определенного вида,должен наследовать java.util.EventObject.Все объекты-наблюдатели должныреализовывать один интерфейс EventListener,в котором должен быть метод обработкисобытия (обычно называемый так же, как исобытие) с параметром типа EventType.Интерфейс EventListener должен наследоватьинтерфейсу java.util.EventListener.Класс источника событий должен иметь методыдля регистрации наблюдателей и их удаления изреестра.
Эти методы должны иметь сигнатурыpublic void addEventListener(EventListener)public void removeEventListener(EventListener).Можно заметить, что такой способ реализацииобработки событий воплощает образецпроектирования «Подписчик».В приведенном ниже примере все publicклассы и интерфейсы должны быть описаны вразных файлах.public class MouseEventArgs { ...
}public class MouseEventObjectextends java.util.EventObject{MouseEventArgs args;Событие (event) представляет собой свойствоспециального вида, имеющее делегатный тип. Усобытия, в отличие от обычного свойства,методы доступа называются add и remove ипредназначены они для добавления илиудаления обработчиков данного события,являющихся делегатами (это аналоги различныхреализаций метода обработки события винтерфейсе наблюдателя в JavaBeans) припомощи операторов += и -=.Событие может быть реализовано как поледелегатного типа, помеченное модификаторомevent. В этом случае декларироватьсоответствующие методы add и removeнеобязательно — они автоматическиреализуются при применении операторов += и-= в к этому полю как к делегату.Если же программист хочет реализовать какоето специфическое хранение обработчиковсобытия, он должен определить методы add иremove.В приведенном ниже примере одно из событийреализовано как событие-поле, а другое — припомощи настоящего поля и методов add иremove, дающих совместно тот же результат.При перегрузке события в наследникахперегружаются методы доступа к нему.public class MouseEventArgs { ...
}MouseEventObject(Object source, MouseEventArgs args){super(source);this.args = args;}}public interface MouseEventListenerextends java.util.EventListener{void mouseUp(MouseEventObject e);void mouseDown(MouseEventObject e);}public delegate void MouseEventHandler(object source, MouseEventArgs e);import java.util.ArrayList;public class MouseEventSource{private ArrayList<MouseEventListener>listeners = new ArrayList<MouseEventListener >();public class MouseEventSource{public event MouseEventHandler MouseUp;private MouseEventHandler mouseDown;public eventMouseEventHandler MouseDown{add{lock(this){ mouseDown += value; }}remove{lock(this){ mouseDown -= value; }}}public synchronized voidaddMouseEventListener(MouseEventListener l){ listeners.add(l); }public synchronized voidremoveMouseEventListener(MouseEventListener l){ listeners.remove(l); }protected void notifyMouseUp(MouseEventArgs a){MouseEventObject e =new MouseEventObject(this, a);ArrayList<MouseEventListener> l;synchronized(this){l =(ArrayList<MouseEventListener>)listeners.clone();for(MouseEventListener el : l)el.mouseUp(e);}}protected voidOnMouseUp(MouseEventArgs e){MouseUp(this, e);}protected void notifyMouseDown(MouseEventArgs a){MouseEventObject e =new MouseEventObject(this, a);protected voidOnMouseDown(MouseEventArgs e){mouseDown(this, e);}}ArrayList<MouseEventListener> l;synchronized(this){l =(ArrayList<MouseEventListener>)listeners.clone();for(MouseEventListener el : l)el.mouseDown(e);}}}public class HandlerConfigurator{MouseEventSource s =new MouseEventSource();public class HandlerConfigurator{MouseEventSource s =new MouseEventSource();MouseEventListener listener =new MouseEventListener(){public void mouseUp(MouseEventObject e) { ...
}public void mouseDown(MouseEventObject e) { ... }};public void UpHandler(object source, MouseEventArgs e){ ... }public void DownHandler(object source, MouseEventArgs e){ ... }public void configure(){s.addMouseEventListener(listener);}public void Configure(){s.MouseUp += UpHandler;s.MouseDown += DownHandler;}}}Методы доступа к свойствам, индексерам илисобытиям в классах-наследниках могутперегружаться по отдельности, т.е., например,метод чтения свойства перегружается, а методзаписи — нет.В C# 2.0 введена возможность декларацииразличной доступности у таких методов.Например, метод чтения свойства можносделать общедоступным, а метод записи —доступным только для наследников.Для этого можно описать свойство так:public int Property{get { … }protected set { … }}В Java никакие операторы переопределитьнельзя.Вообще, в этом языке имеются толькооператоры, действующие на значенияхпримитивных типах, сравнение объектов наравенство и неравенство, а также оператор + длястрок (это объекты класса java.lang.String),обозначающий операцию конкатенации.Оператор + может применяться и к другимтипам аргументов, если один из них имеет типString.