Lecture11 (1133568), страница 4
Текст из файла (страница 4)
Такой элемент можетиспользоваться в типах того же пакета, ккоторому относится содержащий его тип.Именно пакетная доступность используется вJava по умолчанию.protected элементы в Java также доступны изтипов того пакета, в котором находитсясодержащий эти элементы тип, т.е.
protectedдоступность шире пакетной.Типы, не вложенные в другие, могут быть либоpublic (должно быть не более одного такоготипа в файле), либо иметь пакетнуюдоступность.В C# доступность элемента типа по умолчанию— private.Имеется дополнительный модификатордоступности — internal. Элемент, имеющийтакую доступность, может быть использованвсюду в рамках того же файла, где находитсяопределение этого элемента.Кроме того, в C# можно использоватькомбинированный модификатор protectedinternal для указания того, что к данномуэлементу имеют доступ как наследникисодержащего его типа, так и типы в рамкахсодержащего его файла.Типы, не вложенные в другие, могут быть либоpublic, либо иметь доступность по умолчанию— private, что означает, что они могутиспользоваться только в рамках содержащегоих пространства имен.В C# все элементы типов могут быть помеченымодификатором new для точного указания на то,что такой элемент — новый и никак несоотносится с элементами предков данного типас тем же именем или той же сигнатурой.Поля классов или структурных типов в C#могут иметь в качестве дополнительныхВ Java для полей классов дополнительно кмодификаторам доступности и контекста могутиспользоваться модификаторы final,transient и volatile.Модификатор final обозначает, что такое полене может быть изменено во время работы, носначала должно быть инициализировано:статическое — в одном из статическихинициализаторов, нестатическое — к концуработы каждого из конструкторов.
Винициализаторах или конструкторах такое полеможет модифицироваться несколько раз.Модификатор final у локальных переменных ипараметров методов может использоватьсяпримерно в том же значении — невозможностьмодификации их значений послеинициализации.Поля, помеченные модификатором transient,считаются не входящими в состояние объектаили класса, подлежащее хранению или передачепо сети.В Java имеются соглашения о том, как долженбыть оформлен интерфейс класса, объектыкоторого могут быть сохранены или переданыпо сети — эти соглашения можно найти вдокументации по интерфейсуjava.io.Serializable, который долженреализовываться таким классом.
Имеются идругие подобные наборы соглашений,привязанные к определенным библиотекам илитехнологиям в рамках Java.Стандартный механизм Java, обеспечивающийсохранение и восстановление объектов,реализующих интерфейсjava.io.Serializable, по умолчаниюсохраняет значения всех полей, кромепомеченных модификатором transient.Методы классов в Java могут бытьдополнительно помечены модификаторамиstrictfp (такой же модификатор могут иметьинициализаторы) и synchronized.Значение модификатора strictfp описано вЛекции 10, в разделе о типах с плавающейточкой.Значение модификатора synchronizedописывается ниже, в разделе, посвященноммногопоточным приложениям.модификаторов readonly и volatile.Модификатор readonly по своему значениюаналогичен модификатору final в Java.readonly поля должны инициализироваться кконцу работы конструкторов и дальше не могутбыть изменены.Такие поля используются для представленияпостоянных в ходе работы программы объектови значений, типы которых не допустимы дляподдерживаемых языком констант, а такжетаких, значение которых не может бытьвычислено во время компиляции.Шаблонные типы и операцииВ последних версиях обоих языков введены шаблонные, т.е.
имеющие типовые параметры,типы и операции.Ниже приводятся примеры декларации шаблонного метода и его использования в 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";Console.WriteLine( getTypeName(y) );Console.WriteLine( getTypeName(y.Length) );Console.WriteLine( getTypeName<char>(y[1]) );System.out.println( getTypeName(y) );System.out.println( getTypeName(y.length()) );System.out.println( A.<Character>getTypeName(y.charAt(1)) );}}}}В Java в качестве типовых аргументов могутиспользоваться только ссылочные типы.Примитивный тип не может быть аргументомшаблона — вместо него нужно использоватьсоответствующий класс-обертку.В Java типовые аргументы являютсяэлементами конкретного объекта — онифактически представляют собой набордополнительных параметров конструктораобъекта или метода, если речь идет ошаблонном методе.
Поэтому статическиеэлементы шаблонного типа являются общимидля всех экземпляров этого типа с разнымитиповыми аргументами.В C# любой тип может быть аргументомшаблона.В 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 —типом значений, а параметр U — наследоватьклассу A, реализовывать интерфейс IList<T> ииметь конструктор без параметров.public class A{public class A { ...
}public int m() { ... }}public interface B{public String n();}public class C<T extends A & B>{T f;public String k(){return f.n() + (f.m()*2);}}Кроме того, в Java можно использоватьнеопределенные типовые параметрыpublic class B<T, U, V>where T : classwhere U : A, IList<T>, new()where V : struct{ ... }(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){ ... }}Дополнительные элементы описания операцийВ обоих языках (в Java — начиная с версии 5) имеются конструкции, позволяющие описыватьоперации с неопределенным числом параметров (как в функции printf стандартной библиотекиC).
Для этого последний параметр нужно пометить специальным образом. Этот параметринтерпретируется как массив значений указанного типа. При вызове такой операции можноуказать обычный массив в качестве ее последнего параметра, но можно и просто перечислитьчерез запятую значения элементов этого массива или ничего не указывать в знак того, что он пуст.Детали декларации таких параметров несколько отличаются.В Java нужно указать тип элемента массива,многоточие и имя параметра.В C# нужно указать модификатор params, типсамого массива и имя параметра.using System;public class A{public int f(int ... a){return a.length;}public static void main(String[] args)public class A{public int f(params int[] a){return a.Length;}public static void Main{{A a = new A();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, превышениеограничений на размер стека или занятойдинамической памяти, и пр. Проверяемыеисключения предназначены для передачисообщений о возникновении специфическихситуаций и всегда явно создаются в такихситуациях.Непроверяемое исключение должно иметькласс, наследующий java.lang.Error, если онообозначает серьезную ошибку, которая неможет быть обработана в рамках обычногоприложения, или java.lang.RuntimeException,если оно может возникать при нормальнойработе виртуальной машины Java.