В.В. Кулямин - Технологии программирования. Компонентный подход (1133554), страница 53
Текст из файла (страница 53)
Винициализаторах или конструкторах такое полеможет модифицироваться несколько раз.Модификатор final у локальных переменных ипараметров методов может использоватьсяпримерно в том же значении — невозможностьмодификации их значений послеинициализации.Поля, помеченные модификатором transient,считаются не входящими в состояние объектаили класса, подлежащее хранению или передачепо сети.В Java имеются соглашения о том, как долженбыть оформлен интерфейс класса, объектыкоторого могут быть сохранены или переданыпо сети — эти соглашения можно найти вдокументации по интерфейсуjava.io.Serializable, который долженреализовываться таким классом.
Имеются идругие подобные наборы соглашений,В C# доступность элемента типа по умолчанию— private.Имеется дополнительный модификатордоступности — internal. Элемент, имеющийтакую доступность, может быть использованвсюду в рамках того же файла, где находитсяопределение этого элемента.Кроме того, в C# можно использоватькомбинированный модификатор protectedinternal для указания того, что к данномуэлементу имеют доступ как наследникисодержащего его типа, так и типы в рамкахсодержащего его файла.Типы, не вложенные в другие, могут быть либоpublic, либо иметь доступность по умолчанию— private, что означает, что они могутиспользоваться только в рамках содержащегоих пространства имен.В C# все элементы типов могут быть помеченымодификатором new для точного указания на то,что такой элемент — новый и никак несоотносится с элементами предков данного типас тем же именем или той же сигнатурой.Поля классов или структурных типов в C#могут иметь в качестве дополнительныхмодификаторов readonly и volatile.Модификатор readonly по своему значениюаналогичен модификатору final в Java.readonly поля должны инициализироваться кконцу работы конструкторов и дальше не могутбыть изменены.Такие поля используются для представленияпостоянных в ходе работы программы объектови значений, типы которых не допустимы дляподдерживаемых языком констант, а такжетаких, значение которых не может бытьвычислено во время компиляции.190привязанные к определенным библиотекам илитехнологиям в рамках Java.Стандартный механизм Java, обеспечивающийсохранение и восстановление объектов,реализующих интерфейсjava.io.Serializable, по умолчаниюсохраняет значения всех полей, кромепомеченных модификатором transient.Методы классов в Java могут бытьдополнительно помечены модификаторамиstrictfp (такой же модификатор могут иметьинициализаторы) и synchronized.Значение модификатора strictfp описано вЛекции 10, в разделе о типах с плавающейточкой.Значение модификатора synchronizedописывается ниже, в разделе, посвященноммногопоточным приложениям.Шаблонные типы и операцииВ последних версиях обоих языков введены шаблонные, т.е.
имеющие типовые параметры,типы и операции.Ниже приводятся примеры декларации шаблонного метода и его использования в Java и C#. Впоследнем вызове в обоих примерах явное указание типового аргумента у метода getTypeName()необязательно, поскольку он вычисляется из контекста вызова. Если вычислить типовыеаргументы вызова метода нельзя, их нужно указывать явно.using System;public class A{public static <T> String getTypeName(T a){if(a == null) return "NullType";else returna.getClass().getName();}public class A{public static string getTypeName<T>(T a){if(a == null) return "NullType";else returna.GetType().FullName;}public static void Main(){string y = "ABCDEFG";public static void main(String[] args){String y = "ABCDEFG";}}System.out.println( getTypeName(y) );System.out.println( getTypeName(y.length()) );System.out.println( A.<Character>getTypeName(y.charAt(1)) );В Java в качестве типовых аргументов могутиспользоваться только ссылочные типы.Примитивный тип не может быть аргументомшаблона — вместо него нужно использоватьсоответствующий класс-обертку.Console.WriteLine( getTypeName(y) );Console.WriteLine( getTypeName(y.Length) );Console.WriteLine( getTypeName<char>(y[1]) );}}В C# любой тип может быть аргументомшаблона.191В Java типовые аргументы являютсяэлементами конкретного объекта — онифактически представляют собой набордополнительных параметров конструктораобъекта или метода, если речь идет ошаблонном методе.
Поэтому статическиеэлементы шаблонного типа являются общимидля всех экземпляров этого типа с разнымитиповыми аргументами.В C# каждый экземпляр шаблонного класса,интерфейса или структурного типа сопределенными аргументами имеет свой наборстатических элементов, которые являютсяобщими для всех объектов такого полностьюопределенного типа.using System;public class A<T>{public static int c = 0;public T t;}public class A<T>{public static int c = 0;public T t;}public class B{public static void main(String[] args){A.c = 7;public class B{public static void Main(){A<string>.c = 7;}}Console.WriteLine( A<int>.c );Console.WriteLine( A<string>.c );System.out.println( A.c );}}В C# можно определить и использоватьшаблонные делегатные типы.public delegate bool Predicate<T>(T value);public class I{public bool m(int i){ return i == 0; }}public void f(){Predicate<int> pi = m;Predicate<string> ps =delegate(string s){ return s == null; };}В обоих языках имеются конструкции для указания ограничений на типовые параметрышаблонных типов и операций.
Такие ограничения позволяют избежать ошибок, связанных сиспользованием операций типа-параметра, точнее, позволяют компилятору обнаруживать такиеошибки.Ограничения, требующие от типа-параметра наследовать некоторому другому типу, позволяютиспользовать операции и данные типа-параметра в коде шаблона.В Java можно указать, что тип-параметрданного шаблона должен быть наследникомнекоторого класса и/или реализовыватьопределенные интерфейсы.В приведенном ниже примере параметр Tдолжен наследовать классу A и реализовыватьинтерфейс B.В C# можно указать, что тип-параметр долженбыть ссылочным, типом значения, наследоватьопределенному классу и/или определенныминтерфейсам, а также иметь конструкторы сзаданной сигнатурой.В приведенном ниже примере параметр Tдолжен быть ссылочным типом, параметр V —192типом значений, а параметр U — наследоватьклассу A, реализовывать интерфейс IList<T> ииметь конструктор без параметров.public class A{public int m() { ...
}}public interface B{public String n();}public class A { ... }public class B<T, U, V>where T : classwhere U : A, IList<T>, new()where V : struct{ ... }public class C<T extends A & B>{T f;}public String k(){return f.n() + (f.m()*2);}Кроме того, в Java можно использоватьнеопределенные типовые параметры(wildcards) при описании типов.Неопределенный типовой параметр может бытьограничен требованием наследоватьопределенному типу или, наоборот, бытьпредком определенного типа.Неопределенные типовые параметрыиспользуют в тех случаях, когда нет никакихзависимостей между этими параметрами, междуними и типами полей, типами результатовметодов и исключений.
В таких случаяхвведение специального имени для типовогопараметра не требуется, поскольку оно будетиспользоваться только в одном месте — приописании самого этого параметра.В приведенном ниже примере первый методработает с коллекцией произвольных объектов,второй — с коллекцией объектов, имеющих (необязательно точный) тип T, третий — с такойколлекцией, в которую можно добавить элементтипа T.public class A{public void addAll(Collection<?> c){ ...
}public <T> void addAll(Collection<? extends T> c){ ... }}public <T> void addToCollection(T e, Collection<? super T> c){ ... }193Дополнительные элементы описания операцийВ обоих языках (в Java — начиная с версии 5) имеются конструкции, позволяющие описыватьоперации с неопределенным числом параметров (как в функции printf стандартной библиотекиC). Для этого последний параметр нужно пометить специальным образом.
Этот параметринтерпретируется как массив значений указанного типа. При вызове такой операции можноуказать обычный массив в качестве ее последнего параметра, но можно и просто перечислитьчерез запятую значения элементов этого массива или ничего не указывать в знак того, что он пуст.Детали декларации таких параметров несколько отличаются.В Java нужно указать тип элемента массива,многоточие и имя параметра.В C# нужно указать модификатор params, типсамого массива и имя параметра.using System;public class A{public int f(int ...
a){return a.length;}public class A{public int f(params int[] a){return a.Length;}public static void Main{A a = new A();public static void main(String[] args){A a = new A();}}System.out.println( a.f(new int[]{9, 0}) );System.out.println( a.f(1, 2, 3, 4) );}}Console.WriteLine( a.f(new int[]{9, 0}) );Console.WriteLine( a.f(1, 2, 3, 4) );В C# исключения, возникновение которыхВ Java требуется указывать некоторые типыисключений, возникновение которых возможно возможно при работе метода, никак неописываются.при работе метода, в заголовке метода.Точнее, все исключения делятся на два вида —проверяемые (checked) и непроверяемые(unchecked). Непроверяемыми считаютсяисключения, возникновение которых можетбыть непреднамеренно — обращение к методуили полю по ссылке, равной null, превышениеограничений на размер стека или занятойдинамической памяти, и пр.