410013796724260
• Webmoney
R335386147728
Z369087728698
Вопросы по Java на собеседовании (2)
Вопросы и ответы для собеседование по Java, Содержание. 1. Сравнение объектов методом equals и оператором '=='Метод equas определен в Object и используется для сравнения объектов по значениям полей. При сравнении объектов при помощи оператора '==' выполняется сравнение по ссылкам. При использовании метода equals() определяется отношение эквивалентности объектов. Эквивалентным называется отношение, которое является симметричным, транзитивным и рефлексивным :
В методе equals() выполняется сравнение полей двух объектов. Ответственность за реализацию метода equals ложится на разработчика. При переопределении equals() обязательно нужно переопределить метод hashCode(), поскольку равные объекты должны возвращать одинаковые hash-коды. Следует помнить, что множество возможных hash-кодов ограничено примитивным типом int, а множество объектов – только фантазией программистов. Отсюда следует утверждение : «Множество объектов мощнее множества хеш-кодов». Из-за этого ограничения, вполне возможна ситуация, что хеш-коды разных объектов могут совпасть. Здесь надо понять, что если хеш-коды разные, то и входные объекты гарантированно разные. Но если хеш-коды равны, то входные объекты не всегда равны. Ситуация, когда разные объекты имеют одинаковые хеш-коды, называется — коллизией. Вероятность возникновения коллизии зависит от используемого алгоритма генерации hash-кода. Для определения hash-кода объекта следует использовать те поля, которые используются при сравнении в методе equals(). Подробное описание с примерами использования методов equals() и hashCode() представлено здесь. 2. Коллекции объектовКоллекции (Сollection) представляют хранилища или контейнеры, поддерживающие различные способы хранения и упорядочения объектов с целью обеспечения возможностей эффективного доступа к ним. Коллекции поддерживают три основные операции :
3. Основные интерфейсы коллекций и их реализацииНаборы данных (Сollection) реализуют три интерфейса: List, Set, Queue. List определяет упорядоченное хранение элементов, которые могут быть «одинаковыми». Основными реализациями интерфейса List являются ArrayList, LinkedList и Vector :
Vector по сравнению с ArrayList и LinkedList в однопоточном приложении работает медленнее, поэтому его целесообразнее использовать в многопоточном приложении. Set – это коллекции, которые не содержат повторяющихся элементов. Основными реализациями интерфейса Set являются HashSet, TreeSet, LinkedHashSet :
Подробное описание с примерами реализации набора данных интерфейса Set представлено здесь. Queue – это интерфейс для реализации однонаправленной очереди. Основными реализациями интерфейса Queue являются LinkedList, PriorityQueue. Однонаправленная очередь работает по принципу FIFO (first-in-first-out), согласно которому новые элементы размещаются в хвосте очереди, а операции извлечения получают элементы из головы очереди. Имеется интерфейс для двустороннего доступа к элементам очереди Deque. Подробное описание с примерами реализации неблокирующих очередей представлено здесь. Интерфейс Map также используется для формирования набора данных, но в формате «карты», где элементы хранятся в виде пары «ключ – значение». Основными реализациями интерфейса Map являются HashMap, TreeMap и LinkedHashMap :
Подробное описание с примерами реализации интерфейса Map представлено здесь. 4. Отличие коллекций ArrayList и LinkedListОтличие двух коллекций ArrayList и LinkedList связано со способом хранения данных. Реализация ArrayList хранит элементы в виде массива, а LinkedList - в виде списка (двунаправленного). Кроме этого, в ArrayList быстрее выполняется сортировка, поскольку для ее выполнения данные списка копируются в массив, а копировать из массива ArrayList в массив для сортировки быстрее. При большом количестве операций добавления и удаления элементов в коллекцию LinkedList должен быть более приемлемым, т.к. при этих операциях не приходится перемещать части массива. 5. Отличия коллекций ArrayList и VectorОтличия двух коллекций ArrayList и Vector связаны с принципом изменения размера массива при добавлении элементов в набор и с синхронизацией элементов набора данных. Класс Vector был введен в JDK 1.0 и он не является частью JCF (Java Collection Framework). Изменение размера массива Синхронизация данных 6. Отличия коллекций HashMap и HashtableHashMap и Hashtable являются реализациями одного интерфейса Map. Главное отличие данных классов связано с тем, что методы класса Hashtable синхронизированы, а HashMap - нет. Кроме этого класс Hashtable в отличии от HashMap не разрешает использование null в качестве ключей и значений. HashMap допускает хранение null ключей и значений, но не допускает дублирования ключей. Следует помнить, что hashCode() для null-ключа всегда равен нулю. Наличие синхронизации в Hashtable снижает производительность кода, использующего данный класс. Для синхронизации можно использовать методы класса Collections: Collections.synchronizedMap(map), Collections.synchronizedList(list) или Collections.synchronizedSet(set). Но необходимо помнить, что методы синхронизации класса Collections возвращают синхронизированный декоратор переданной коллекции, не обеспечивающий синхронизацию элементов коллекции в случае итерации элементов. Полную потокобезопасную синхронизацию набора данных обеспечивает класс ConcurrentHashMap из пакета concurrent. Описание ConcurrentHashMap с примером представлено здесь. 7. Почему интерфейс Map не относят к коллекцииРеализации интерфейса Map также, как и реализации коллекций (List, Set), используются для формирования набора данных. Однако, если в коллекции элемент данных представляет определенный Object, то в реализации Map элемент является совокупностью пары "ключ-значение". Соответственно, некоторые методы Collection нельзя использовать в Map. Например, метод remove(Object o) в коллекции предназначен для удаления элемента, в то время, как такой же метод remove(Object key) в интерфейсе Map предназначен для удаления элемента по заданному ключу. 8. Перевод набора данных из ArrayList в HashSet и обратноНабор данных ArrayList можно преобразовать в коллекцию HashSet и обратно. Примеры преобразования : List<String> list = new ArrayList <String>(); list.add ("Summer"); list.add ("Winter"); // Преобразование в Set Set<String> saison = new HashSet<String> (list); ------------------------------------------------------------ // Обратное преобразование Set<String> saison = new HashSet<String> (); set.add ("Summer"); set.add ("Winter"); // Преобразование в ArrayList List<String> list = new ArrayList <String>(saison); Следует обратить внимание, что преобразование типа коллекции выполняется в конструкторе при создании соответствующего нового объекта. 9. Использование Iterator'а коллекции для перебора элементовИнтерфейс Collection имеет метод iterator(), возвращающий объект-итератор, который используется для последовательного обращения к элементам набора данных. Этот итератор реализует интерфейс Iterator, который включает методы next(), hasNext() и remove(). C помощью вызова метода next() можно получить следующий элемент в наборе. Метод hasNext() позволяет проверить наличие следующего элемента. Данные методы следует использовать совместно при организации цикла перебора элементов коллекции. Метод remove() удаляет текущий элемент, который был получен при последнем вызове next(). Пример использования итератора : List<String> states = new ArrayList<String>(); states.add("Германия"); states.add("Франция"); states.add("Италия"); states.add("Испания"); Iterator<String> iter = states.iterator(); while(iter.hasNext()) System.out.println(iter.next());
Примечание : Порядок следования элементов в итератореПорядок получения элементов коллекции при переборе итератором зависит от типа и набора элементов. Если используется ArrayList, то итератор начинает с нулевого индекса и инкрементирует индекс на каждом шаге. Если объект имеет тип HashSet, то порядок следования элементов коллекции может оказаться случайным. При использовании Iterator'a, можно быть уверенным, что он переберет все элементы, но порядок элементов может быть случайным. Подробное описание и пример использования итератора коллекции представлены здесь. 10. Использование цикла for-eachЦикл перебора элементов коллекции for-each, появившийся в JDK 5.0, реализован с использованием Iterator'a. Компилятор преобразует цикл for-each в обычный цикл с итератором. Таким образом, цикл "for each" работает с любым объектом, реализующим интерфейс Iterable. Цикл из примера п.9. можно представить следующим образом : List<String> states = new ArrayList<String>(); states.add("Германия"); states.add("Франция"); states.add("Италия"); states.add("Испания"); for (String element : list) System.out.println(element.toString()); 11. Использование метода итератора removeМетод итератора remove() следует вызывать после вызова метода next(), иначе будет вызвано исключение IllegalStateException(). Метод remove() удаляет элемент, на который указывает итератор. Нельзя вызывать метод remove() два раза подряд для удаления элементов. Необходимо после первого удаления повторно вызвать метод next(). Если два потока паралельно вносят изменения (добавление, удаление) в набор данных, то необходимо либо синхронизировать коллекции, либо использовать потокобезопасные коллекции пакета Concurrent. В противном случае могут возникать исключения типа ConcurrentModificationException. 12. Итераторы Iterator и ListIteratorListIterator расширяет свойства интерфейса Iterator, позволяя перемещаться по коллекции в обоих направлениях, изменять содержимое коллекции и получать текущую позицию итератора. При этом следует помнить, что ListIterator не указывает на конкретный элемент коллекции и его текущая позиция определяется двумя элементами, которые возвращают методы previous() и next(). Таким образом, модификация коллекции осуществляется для последнего элемента, который был возвращен одним из методов previous() или next(). 13. Интерфейс Enumeration <E>Интерфейс Enumeration, также как и Iterator, предназначен для обхода коллекций. Он включает два метода : hasMoreElements(), возвращающий результат проверки наличия следующего элемента, и nextElement (), возвращающий следующий элемент перечисления. Пример использования Enumeration : for (Enumeration<E> e = v.elements(); e.hasMoreElements();) System.out.println(e.nextElement()); Интерфейс Iterator был введен несколько позднее, по сравнению с Enumeration, и он является частью JCF (Java Collection Framework), поэтому его использование предпочтительнее. Кроме этого, Iterator дополнительно включает метод удаления элемента из коллекции. 14. Метод коллекции toArray для получения массива элементовДля получения массива элементов из набора данных типа List, необходимо использовать метод toArray(). Следующий пример демонстрирует получение из набора данных List двух массивов разных типов. List<String> list = new ArrayList<String>(); list.add("Весна"); list.add("Лето"); list.add("Осень"); list.add("Зима"); String[] array = list.toArray (new String[list.size()]); Object[] objects = list.toArray (); 15. Использование утилиты ArraysСогласно документации утилита java.util.Arrays формирует список на основе массива. Массив, при этом, используется для внутреннего представления списка, т.е. сохраняется связь между списком и исходным массивом. Таким образом, изменение значения элемента в массиве отобразится в списке, и наоборот. Ниже представлен пример создания списка и внесение изменений. В качестве комментариев отображены выводимые в консоль значения : String[] a = {"one", "two", "three"}; List<String> list = Arrays.asList(a); System.out.println(list); // [one, two, three] a[0] = "111"; System.out.println(list); // [111, two, three] list.set(1, "222"); System.out.println(Arrays.toString(a)); // [111, 222, three] Если массив содержит объекты, то и созданный утилитой Arrays список будет содержать объекты. При этом, и массив, и список будут ссылаться на одни и те же элементы : Object[] a = {new Object(), new Object(), new Object()}; List<Object> list = Arrays.asList(a); System.out.println(a[0] == list.get(0)); // true Метод Arrays.asList() является параметризованным методом и работает только с объектами, т.е. автоматическую упаковку примитивных типов, например int, к классу-обёртке (Integer) метод не выполняет. Пример : // массивы из 10 элементов int[] i = new int [10]; Integer[] I = new Integer[10]; String[] s = new String [10]; // Вывод размеров массивов в консоль System.out.println(Arrays.asList(i).size()); // 1 System.out.println(Arrays.asList(I).size()); // 10 System.out.println(Arrays.asList(s).size()); // 10 16. Использование метода коллекции containsМетод коллекции contains() позволяет проверить наличие определенного элемента в наборе. Процесс проверки выполняется в цикле для всех элементов набора пока не будет найден соответствующий «эквивалент». При сравнении объектов используется метод equals() элемента набора. Поэтому, необходимо быть внимательным, если набор включает сложные объекты, для которых требуется метод equals() переписать. Следующий пример демонстрирует использование метода contains() для простых строковых объектов набора; в консоль будет выведено логическое значение 'true'. List<String> list = new ArrayList<String>(); list.add("Весна"); list.add("Лето"); list.add("Осень"); list.add("Зима"); System.out.println("" + list.contains("Лето")); Незначительно усложняем пример и создаем коллекцию из объектов Saison, который включает два поля : id и name. Теперь, чтобы метод (проверки наличия в коллекции элемента) contains() работал корректно необходимо в классе Saison переписать метод equals(), в котором выполнить соответствующее сравнение двух объектов. В примере сравнение объектов выполняется для целочисленных идентификаторов id, поэтому метод equals() вернет true для любых строковых значений name и в консоль будет выведено 'true'. class Saison { public int id; public String name; public Saison(int id, String name) { this.id = id; this.name = name; } @Override public boolean equals(Object obj) { return (id == ((Saison)obj).id); } } . . . List<Saison> list = new ArrayList<Saison>(); list.add(new Saison(1, "Весна")); list.add(new Saison(2, "Лето")); list.add(new Saison(3, "Осень")); list.add(new Saison(4, "Зима")); System.out.println("" + list.contains(new Saison(2, "Весна"))); Листинг метода contains() можно посмотреть здесь. 17. Методы коллекции MapСоздаем коллекцию типа TreeMap : TreeMap <Integer, String> map; map = new TreeMap<Integer, String>(); // Добавляем данные map.put(1, "Понедельник"); map.put(2, "Вторник" ); map.put(3, "Среда" ); map.put(4, "Четверг" ); map.put(5, "Пятница" ); map.put(6, "Суббота" ); map.put(7, "Воскресенье"); Следующие методы коллекции типа Map возвращают наборы определенных типов, которые можно перебрать по элементам, используя Iterator :
В примере для работы с коллекцией используем методы получения всех ключей и значений, получение ключа и значения определенного элемента коллекции, уделение элемента коллекции. // Получить все ключи System.out.println("Ключи : " + map.keySet()); /* Ключи : [1, 2, 3, 4, 5, 6, 7] */ ------------------------------- // Получить все значения System.out.println("Значения : " + map.values()); /* Значения : [Понедельник, Вторник, Среда, Четверг,\ Пятница, Суббота, Воскресенье] */ ------------------------------- // Первый ключ и его значение System.out.println("Первый ключ : " + map.firstKey() + ", значение : " + map.get(map.firstKey())); /* Первый ключ : 1, значение : Понедельник */ // Удаление первого элемента коллекции map.remove(map.firstKey()); Подробное описание коллекций типа Map с примерами их использования можно увидеть здесь.
Вопросы и ответы для собеседование по Java, Содержание. |