Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Java. Обобщения: понятие и синтаксис.




Простые generic-и

Начать работать с generic-ами в Java очень просто. Легче всего это показать на примере коллекций. Для начала сравним код без применения generic-ов и код с generic-ами. Вот пример кода без применения generic-ов:List strList = new ArrayList();

strList.add("some text");

// ОК, хотя коллекция предназначалась для хранения строк!

strList.add(new Integer(0));

String str = (String)strList.get(0);

// Ошибка приведения типов во время выполнения (ClassCastException)

Integer i = (Integer)strList.get(0);

Недостатки этого кода очевидны, и обидно, что язык позволял такое писать. В runtime подобный код приведет к генерации исключения ClassCastException.

А вот код с generic-ами:List<String> strList = new ArrayList<String>();

strList.add("some text");

strList.add(new Integer()); // сообщение об ошибке компилятора

String str = strList.get(0);

Integer i = strList.get(0); // сообщение об ошибке компилятора

Разница вполне очевидна, нет надобности в приведении типов, проводится проверка типов на этапе компиляции, и код стал более надежным – получить ClassCastException уже сложнее. У экземпляра ArrayList, параметризованного String, метод get() будет возвращать String, и методу put() в качестве аргумента ничего, кроме String, передать не удастся.

Объявить generic-класс совсем несложно. Вот пример такого объявления:class GenericList<E>

{

E getFirst() { ... }

void add(E obj) { ... }

}

Это пример generic-класса с одним параметром E, определяющим тип элементов списка, который реализует данный класс. Таких параметров может быть сколь угодно много.

Доступ к generic-параметру возможен в любом не статическом контексте параметризованного класса.

Хочется обратить внимание на такой момент:List<String> strList = new ArrayList<String>(); // 1

List<Object> objList = strList;             // 2

Строка 2 выдаст ошибку времени компиляции. Это может показаться неочевидным. String является наследником Object, и при приведении коллекций, казалось бы, все должно работать нормально, но на самом деле это не так. Если разрешить такое приведение, то после него можно будет добавить в List любой объект, унаследованный от Object. Такая ситуация легко может стать причиной проблем. Предположим, что у нас есть класс Car и два его наследника – SportCar и Truck. Если можно было бы преобразовать список со SportCar к списку Car, то мы бы смогли добавить туда экземпляр Truck, т.к. он является наследником Car. Получилось так, что в коллекцию с элементами одного типа мы добавили элемент другого типа, которой не является наследником первого. Это сводит на нет все преимущества generic-ов, ни о какой типобезопасности и речи быть не может (подобное поведение называется ковариантностью, ковариантность совершенно логична для неизменяемых коллекций, но, как показано выше, для изменяемых коллекций она не подходит – прим.ред.).

Если generic-классу вообще не передаются параметры, считается, что в качестве параметров переданы Object, т.е. строки 1 и 2 в следующем примере эквивалентны:List objList = new ArrayList();             // 1

List<Object> objList1 = new ArrayList<Object>(); // 2

Существуют не только generic-классы, но и generic-методы. Объявление generic-метода может выглядеть так:public static <T> T getFirst(Collection<T> col) {...}

Параметр типа generic-метода определяется до возвращаемого значения (выделено красным). Generic-методы могут быть как статическими, так и не статическими.

Синтаксис вызова generic-метода c явным указанием параметров может показаться несколько необычным тем, кто пользовался шаблонами С++. Generic-параметр в Java ставится перед именем функции, а не после:<Integer>swap(ints, 1, 3);

strings.<Integer>zip(ints);

Так сделано из-за того, что запись f(a<b, c>(d)) неоднозначна и может встретиться в коде не только как вызов generic-метода a, результат которого передается в функцию f.

Конструкторы также могут быть параметризованы. Синтаксис вызова и объявления такой же, как и у функций.

Параметрами типов могут быть только ссылочные типы, соответственно, примитивные типы не могут передаваться в качестве параметра.

Ограничения

В отличие от С++, generic-и в Java позволяют задать класс, от которого должен быть унаследован параметр generic-а, или интерфейс, который он должен реализовать. Это делается с помощью ключевого слова extends.

Предположим, у нас есть функция, которая находит ближайший к точке Glyph из заданной коллекции. Glyph – это базовый тип, и может иметься неограниченное количество потомков этого типа. Также может иметься неограниченное количество коллекций, хранящих элементы, тип которых соответствует одному из этих потомков. Хотелось бы, чтобы функция могла работать со всеми подобными коллекциями, и возвращала элемент, тип которого совпадал бы с типом элемента коллекции, а не приводился к Glyph. Возникает желание написать примерно такую функцию:<T> T findNearest(Collection<T> glyphs, int x, int y) { ... }

Функция выглядит неплохо, но, тем не менее, не лишена недостатков. Получается так, что функции можно передать коллекцию любого типа. Это усложняет реализацию функции, порождая необходимость проверки типа элемента. Будет гораздо лучше написать так:<T extends Glyph> T findNearest(Collection<T> glyphs, int x, int y) {...}

Теперь все встает на свои места – в функцию можно передать только коллекцию, элементы которой реализуют интерфейс Glyph. Generic-и сделали свое дело, код получился более типобезопасным.

Extends можно применять и для параметров generic-классов:class <T extends Glyph> GlyphsContainter

{

...

public void addGlyph(T glyph){...}

}

Как в методах, так и в классах можно задать более одного базового интерфейса, который должен реализовывать generic-параметр. Это делается при помощи следующего синтаксиса: class <T extends Glyph & MoveableGlyph> MoveableGlyphsContainter

{

...

public void addGlyph(T glyph){...}

}

Теперь generic-параметр должен реализовывать не только интерфейс Glyph, но и MoveableGlyph. Ограничений на количество интерфейсов, которые должен реализовывать переданный тип, нет. Но класс можно передать только один, т.к. в Java нет множественного наследования. Типы в этом списке могут быть generic-типами, но ни один конкретный интерфейс не может появляться в списке более одного раза, даже с разными параметрами:interface Bar<T> {...}

interface Bar1 {...}

public class Foo<T extends Bar<T> & Bar1> {...} // ok

public class Foo<T extends Bar<T> & Bar<Object> & Bar1> {...} // ошибка



C#. Коллекции.

Библиотека коллекций .NET размещается в пространстве имен System.Collections.Generic и содержит ряд обобщенных (generic) интерфейсов и классов (рис.). Интерфейс IEnumerable представляет коллекцию, позволяющую выполнять перебор своих элементов.

Интерфейс ICollection — это коллекция общего вида. Объявляет операции добавления, удаления элементов, проверки на принадлежность элементов коллекции.

Интерфейс IList представляет собой коллекцию-список, т. е. коллекцию элементов, упорядоченных в соответствии с их целочисленными индексами. Аналогичен интерфейсу List в Java Collections Framework.

Интерфейс IDictionary аналогичен интерфейсу Map в Java Collections Framework и представляет собой коллекцию-карту, т. е. коллекцию элементов, каждому из которых поставлен в соответствие некоторый ключ. Классы из библиотеки коллекций BCL являются скорее реализациями тех или иных структур данных, чем реализациями интерфейсов.

Класс List реализует список на основе динамического массива. Данный класс поддерживает порядок элементов на основе их индексов и обладает достаточно развитым интерфейсом.

Класс Dictionary реализует коллекцию-карту (т. е. коллекцию пар «ключ-значение»).

Класс HashSet реализует коллекцию-множество, т. е. коллекцию, которая не может содержать дублирующиеся элементы. Данный класс был добавлен в .NET Framework 3.5.

Классы Queue, Stack и LinkedList представляют структуры данных очередь, стек и двусвязный линейный список соответственно. Классы SortedDictionary и SortedList представляют коллекцию-карту, отсортированную по ключу. Они представляют собой деревья двоичного поиска. Отличия:

 • SortedList использует меньше памяти, чем SortedDictionary;

• SortedList медленнее выполняет операции вставки и удаления при работе с

неотсортированными данными (SortedList — O(n), SortedDictionary — O(log n));

• SortedList работает быстрее, если список сразу заполняется на основе отсортированных данных;

• SortedList поддерживает эффективное индексированное извлечение ключей и

значений.
29.Java. Коллекции.

Коллекция — это объект, являющийся контейнером для других объектов. Библиотеки классов Java и .NET содержат классы и интерфейсы, обеспечивающие работу с коллекциями.

Библиотека коллекций в Java расположена в пакете java.util и представляет собой набор

интерфейсов и реализаций этих интерфейсов (рис).

Все интерфейсы отражают следующие аспекты коллекций:

• может ли изменяться размер;

• имеет ли значение порядок элементов;

• уникальность элементов.

С коллекциями можно выполнять следующие основные операции:

• добавлять объекты; удалятьобъекты;определять, содержится ли объект в коллекции; получать объект из коллекции (не удаляя его); осуществлять итерационный проход по коллекции.

Можно выделить следующие виды коллекций:

• списки — представляют списки элементов (классы, реализующие интерфейс List);

• множества — коллекции уникальных элементов (классы, реализующие интерфейс  Set);

• карты — коллекции, представляющие отображение «ключ-значение» (классы, реализующие интерфейс Map);

• очереди — коллекции, для которых определен порядок обработки элементов (классы, реализующие интерфейс Queue).

Кроме того, существуют следующие подвиды коллекций:

• неупорядоченные (unordered);

• упорядоченные неотсортированные (ordered unsorted);

• упорядоченные отсортированные (ordered sorted).

Коллекция называется упорядоченной, если она осуществляет итерацию по своим элементам в некотором неслучайном порядке. Упорядоченная коллекция называется отсортированной, если порядок элементов в коллекции определяется свойствами самих элементов. Как правило используется т. н.  естественный порядок (natural order). Для строк это — алфавитный порядок, для чисел — расположение по возрастанию и т. п. Для некоторого произвольного класса Foo естественный порядок будет определен, если этот класс реализует интерфейс Comparable (этот интерфейс позволяет определить правила сравнения экземпляров класса друг с другом). Кроме того правила сравнения можно определить, реализуя интерфейс Comparator .


Интерфейс List

Классы, реализующие данный интерфейс, с каждым своим элементом ассоциируют некоторый индекс и определяют ряд операций, основанных на использовании индекса элементов: получение элемента по его индексу (get), получение индекса заданного элемента (indexOf), добавление элемента в указанную позицию (add) и т. п. Коллекции-списки являются упорядоченными по значениям индексов элементов.

Класс ArrayList. Этот класс можно рассматривать как динамический массив. Он обеспечивает быструю итерацию и быстрый доступ к элементам по их индексам (random access). Класс LinkedList реализует двусвязный линейный список. Итерация по данной коллекции может осуществляться медленнее, чем по ArrayList, а вот операции добавления и удаления элементов являются достаточно быстрыми. Данный класс реализует ряд методов для добавления и удаления элементов из начала и из конца списка (этих методов нет в интерфейсе List), что позволяет использовать этот класс как стек или очередь. Начиная с Java 5, класс LinkedList реализует интерфейс Queue. Класс Vector. Аналогичен классу ArrayList, за исключением того, что методы данного класса являются потокобезопасными. Данный класс присутствует в библиотеке Java с ранних версий и считается устаревшим. Сейчас рекомендуется использовать класс ArrayList, а для обеспечения безопасности в многопоточном приложении можно использовать утилитарные методы класса Collections.

Интерфейс Set

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

Класс HashSet. Этот класс реализует неупорядоченную коллекцию без дублирующихся элементов. Для повышения производительности класс использует хэш-коды объектов.

Класс LinkedHashSet представляет собой версию HashSet, которая поддерживает порядок элементов: проход по элементам осуществляется в порядке их добавления. Элементы этой коллекции объединены в линейный двусвязный список. Класс TreeSet. Является одной из отсортированных коллекций (другая — TreeMap). Этот класс основан на использовании красно-черных деревьев и обеспечивает проход по

элементам в порядке их возрастания.

Интерфейс Map

Классы, реализующие данный интерфейс, позволяют уникальным объектам-ключам ставить в соответствие объекты-значения. Данная коллекция позволяет осуществлять поиск значения по его ключу, получать коллекцию всех ключей или коллекцию всех значений. Для определения равенства ключей используется метод equal. Класс HashMap. Этот класс реализует неупорядоченную коллекцию-карту. Для размещения ключей в памяти и повышения производительности доступа класс использует хэш-коды объектов. В данной коллекции среди объектов-ключей может содержаться одно значение null, а среди объектов-значений — любое количество значений null. Класс LinkedHashMap поддерживает порядок элементов: проход по элементам осуществляется в порядке их добавления. При добавлении и удалении элементов данная коллекция работает медленнее HashMap, однако, она обеспечивает более быструю итерацию.Класс TreeMap представляет отсортированную (в естественном порядке) коллекцию-карту. Класс Hashtable. Данный класс присутствует в библиотеке с ранних версий и  представляет собой потокобезопасную версию класса HashMap. В отличие от HashMap, не позволяет использовать значения null ни в качестве ключей, ни в качестве значений.

 

Интерфейс Queue

Классы, реализующие данный интерфейс, представляют собой коллекцию элементов, которые должны обрабатываться в некотором порядке (обычно используется правило FIFO – First-In, First-Out). Класс PriorityQueue. В этой очереди обработка элементов осуществляется не в порядке добавления, а в порядке их относительных приоритетов. Приоритет определяется либо естественным порядком элементов, либо объектом Comparator .



C#. Dispose Pattern.

Foo foo = null;

try {

foo = new Foo();

foo.DoSomething();

} finally {

if(foo != null) foo.Dispose();

}

using(Foo foo = new Foo()) {

foo.DoSomething();

}

Шаблон удаления объекта упорядочивает жизненный цикл этого объекта.

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

Применение метода Dispose для типов, которые используют только управляемые ресурсы (например массивов) не ведет к повышению производительности, поскольку они автоматически утилизируются сборщиком мусора. Метод Dispose следует использовать для управляемых объектов, которые используют собственные ресурсы, а также в отношении COM-объектов, доступных в платформе .NET Framework. Управляемые объекты, которые используют собственные ресурсы (например класс FileStream), реализуют интерфейс IDisposable. Важное примечание.

Программистам, работающим с языком C++, не следует руководствоваться инструкциями, приведенными в этой теме. Вместо этого следует изучить тему Destructors and Finalizers in Visual C++. В версии платформы .NET Framework 2.0 компилятор C++ обеспечивает поддержку реализации детерминированной утилизации ресурсов и не позволяет реализовать метод Dispose непосредственно.

Метод Dispose должен вызвать для удаляемого им объекта метод SuppressFinalize. Если объект уже помещен в очередь завершения, метод SuppressFinalize блокирует вызов его метода Finalize. Следует помнить, что выполнение метода Finalize представляет собой дорогостоящую операцию с точки зрения производительности. Если метод Dispose уже завершил работу по очистке объекта, необязательно вызывать для сборщика мусора метод Finalize объекта.

В приведенном для метода GC.KeepAlive примере показано, как чрезмерно активная сборка мусора может привести к выполнению финализатора до завершения выполнения утилизируемого объекта. Рекомендуется вызывать метод KeepAlive в конце большого метода Dispose.

Пример

В следующем примере показан рекомендуемый шаблон реализации метода Dispose для классов, которые инкапсулируют неуправляемые ресурсы.

Ресурсные классы обычно являются производными от сложных внутренних классов или интерфейсов API и должны быть соответственно настроены. Этот шаблон кода можно использовать как отправную точку для создания ресурсного класса и проведения необходимой настройки в соответствии с инкапсулируемыми ресурсами.

Язык C#

using System;

using System.IO;

class Program

{

static void Main()

{

   try

   {

       // Initialize a Stream resource to pass

       // to the DisposableResource class.

       Console.Write("Enter filename and its path: ");

       string fileSpec = Console.ReadLine();

       FileStream fs = File.OpenRead(fileSpec);

       DisposableResource TestObj = new DisposableResource(fs);

       // Use the resource.

       TestObj.DoSomethingWithResource();

       // Dispose the resource.

       TestObj.Dispose();

   }

   catch (FileNotFoundException e)

   {

       Console.WriteLine(e.Message);

   }

}

}

// This class shows how to use a disposable resource.

// The resource is first initialized and passed to

// the constructor, but it could also be

// initialized in the constructor.

// The lifetime of the resource does not

// exceed the lifetime of this instance.

// This type does not need a finalizer because it does not

// directly create a native resource like a file handle

// or memory in the unmanaged heap.

public class DisposableResource : IDisposable

{

private Stream _resource; 

private bool _disposed;

// The stream passed to the constructor

// must be readable and not null.

public DisposableResource(Stream stream)

{

   if (stream == null)

       throw new ArgumentNullException("Stream in null.");

   if (!stream.CanRead)

       throw new ArgumentException("Stream must be readable.");

   _resource = stream;

   _disposed = false;

}

// Demonstrates using the resource.

// It must not be already disposed.

public void DoSomethingWithResource() {

   if (_disposed)

       throw new ObjectDisposedException("Resource was disposed.");

   // Show the number of bytes.

   int numBytes = (int) _resource.Length;

   Console.WriteLine("Number of bytes: {0}", numBytes.ToString());

}

 

public void Dispose()

{

   Dispose(true);

   // Use SupressFinalize in case a subclass

   // of this type implements a finalizer.

   GC.SuppressFinalize(this);     

}

protected virtual void Dispose(bool disposing)

{

   // If you need thread safety, use a lock around these

   // operations, as well as in your methods that use the resource.

   if (!_disposed)

   {

       if (disposing) {

           if (_resource != null)

               _resource.Dispose();

               Console.WriteLine("Object disposed.");

       }

       // Indicate that the instance has been disposed.

       _resource = null;

       _disposed = true;  

   }

}

}

 










Последнее изменение этой страницы: 2018-05-27; просмотров: 246.

stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...