410013796724260
• Webmoney
R335386147728
Z369087728698
Вопросы по Java на собеседовании (4)
Вопросы и ответы для собеседование по Java, Содержание. 1. Потоки ввода/выводаПоток ввода/вывода - это абстрактное понятие источника или приёмника данных, которые способны передавать информацию. Имеется два вида потоков ввода/вывода : байтовые и символьные. К байтовым потокам относятся java.io.InputStream, java.io.OutputStream. Символьные потоки – java.io.Reader, java.io.Writer. Данные потоки включены в пакет java.io. Базовый класс InputStream и его наследники получают данные из различных источников : массив байтов, строки (String), файлы, каналы pipe, у которых одна из сторон является входом, а вторая сторона играет роль выхода и т.д. Абстрактный класс OutputStream определяет байтовый поток вывода. К этой категории относятся классы, определяющие выходные данные, помещаемые в массив байтов, в файл или канал. Напрямую в объект String вывести данные из OutputStream нельзя, можно создать текстовую строку (String) из массива байтов. Символьные потоки включают два основных абстрактных класса Reader и Writer, управляющие потоками Unicode символов. Класс Reader определяет символьный поток ввода. Класс Writer определяет символьный поток вывода. При возникновении ошибки методы данных классов вызывают исключение IOException. Потоки ввода данных включают методы read () для чтения отдельных байтов или массива байтов. Потоки вывода данных включают методы write () для записи одиночных байтов или массива байтов. Классы-надстройки потоков ввода/выводаК классам-надстройкам относятся классы, наследующие свойства базовых классов и расширяющие их свойства. В качестве примеров можно привести классы BufferedOutputStream, BufferedInputStrem, BufferedWriter, BufferedReader, которые буферезируют поток, повышая, таким образом, производительность. 2. Байтовый поток ввода InputStreamОсновные методы класса InputStream
Полный список методов класса InputStream представлен здесь. Классы-надстройки базового байтового потока ввода :
Классы BufferedInputStream и DataInputStream, наследуют свойства FilterInputStream. BufferedInputStream используется для организации более эффективного "буферизованного" ввода данных. DataInputStream применяется для чтения байтовых данных (не строк). 3. Байтовый поток вывода OutputStreamКласс OutputStream – это абстрактный класс, определяющий байтовый поток вывода. К данной категории относятся классы, определяющие направление вывода данные: массив байтов, файл или канал. Классы-надстройки байтовых потоков вывода :
Основные методы класса OutputStream
4. Символьный поток чтения ReaderКласс Reader обеспечивает поддержку символьного потока чтения аналогично тому, как это делает InputStream, реализующий модель байтового потока ввода. Классы-надстройки символьных потоков чтения :
5. Символьный поток записи WriterАбстрактный класс Writer обеспечивает поддержку символьного потока записи подобно тому, как это делает OutputStream, реализующий модель байтового потока вывода. Классы-надстройки символьных потоков записи :
6. Преобразование байтовых потоков в символьные и обратноOutputStreamWriter является мостом между классом OutputStream и классом Writer. Записанные в поток символы OutputStreamWriter преобразовывает в байты. OutputStream os = new FileOutputStream("c:\\output.txt"); Writer wr = new OutputStreamWriter(os, "UTF-8"); wr.write("Hello World"); wr.close(); InputStreamReader является мостом между классом InputStream и классом Reader. При помощи методов класса Reader прочитанные байты из потока InputStream преобразуются в символы. InputStream is = new FileInputStream("c:\\input.txt"); Reader isr = new InputStreamReader(is, "UTF-8"); int data = isr.read(); while(data != -1){ char theChar = (char) data; data = isr.read(); } isr.close(); 7. Класс File для работы с файловой системойДля управления информацией о файлах и каталогах используется класс java.io.File. На уровне операционной системы файлы и каталоги имеют существенные отличия, но в Java они описываются одним классом File. В Java каталог трактуется как обычный файл, но с дополнительным свойством — списком имен файлов, который можно просмотреть с помощью метода list (). Класс File позволяет получить следующую информацию о файле: права доступа, время и дата создания, путь к каталогу. Также он используется для навигации по иерархиям подкаталогов. Для создания объектов File можно использовать один из следующих конструкторов :
Примеры создания File : // Объект каталога File File dir = new File("с:/dir"); // Объекты файлов File file1 = new File("c:/dir", "Hello1.txt"); File file2 = new File(dir, "Hello2.txt"); Свойства и методы класса File представлены здесь. 8. Символ-разделитель в определении пути файлаПолучить символ-разделитель, используемый в описании пути к файлу/директории можно с использованием статического поля File.separator типа String, либо File.separatorChar типа char. Символы-разделители в Windows ("\\") и Linux ("/") отличаются направлением наклона. Автор данных строк, как правило, использует linux'овый символ-разделитель '/' при работе в ОС Windows; JVM отрабатывает правильно. 9. Фильтрация списка файлов, FileFilterКласс File включает метод listFiles (FileFilter filter) , позволяющий прочитать список только определенных файлов. Параметр метода FileFilter предназначен для определения условия выбора файлов. FileFilter — являтся интерфейсом, который имеет всего один метод boolean accept (File pathname), возвращающий true, если файл удовлетворяет определенным условиям, и false в противном случае. Подробнее об описании интерфейса FileFilter и пример использования файловой фильтрации можно прочитать здесь. 10. Класс FileInputStream для чтения содержимого файлаКласс FileInputStream, являющийся наследником InputStream, предназначен для работы с двоичными файлами. Конструктор класса «FileInputStream (String fileName) throws FileNotFoundException» в качестве параметра получает путь к файлу. Если файл не может быть открыт, то генерируется исключение FileNotFoundException. Пример использования FileInputStream для чтения данных из файла и вывода содержимого в консоль : FileInputStream fis; try { fis = new FileInputStream("C:\\test_dir\\test.txt"); System.out.println("Размер файла: " + fis.available() + " байт(а)"); int i = -1; while(( i = fis.read()) != -1){ System.out.print((char)i); } fis.close(); } catch(IOException e){ System.err.println(e.getMessage()); } Пример можно немного изменить и сохранить данные в массив байтов : byte[] buffer = new byte[fis.available()]; // чтение файла в буфер fis.read (buffer, 0, fis.available()); System.out.println ("Содержимое файла :"); for(int i = 0; i < buffer.length; i++){ System.out.print((char)buffer[i]); } Дополнительно о FileInputStream можно прочитать здесь. 11. Класс записи содержимого в файл FileOutputStreamКласс FileOutputStream, являющийся наследником OutputStream, предназначен для работы с двоичными файлами. Конструктор класса «FileOutputStream (String fileName) throws IOException» в качестве параметра получает путь к файлу. Если файл невозможно будет создать, то генерируется исключение IOException. String text = "Hello world!"; // строка для записи try { FileOutputStream fos = new FileOutputStream("C:\\test.txt"); // перевод строки в байты byte[] buffer = text.getBytes(); fos.write(buffer, 0, buffer.length); } catch(IOException e){ System.out.println(e.getMessage()); } Дополнительно о FileOutputStream можно прочитать здесь. 12. Стратегии чтения XML документа : DOM и SAXJava использует 2 стратегии обработки XML документов: DOM (Document Object Model) и SAX (Simple API for XML). Отличие двух разных подходов к чтению XML документа связано с тем, что в первом случае (DOM) размер документа определен и он сразу же может быть разложен (распарсен). Во втором случае, например, при получении XML документа от WEB-сервиса, размер документа неизвестен, и он анализируется (раскладывается) в процессе поступления потока информации. То есть, при использовании стратегии DOM необходимо весь документ «заглотить» и проанализировать, а стратегия использования SAX основывается только на анализе содержимого XML-документа, не требующая дополнительной памяти. 13. Классы создания XML-объекта DocumentДля чтения или создания объекта Document используется 3 класса :
DocumentBuilderFactor содержит статический метод newInstance(), создающий экземпляр класса. Document создается одним из методов объекта DocumentBuilder : parse (File) или newDocument(). Пример : DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); // чтение из файла Document doc1 = db.parse(new File("data.xml")); // новый документ Document doc2 = db.newDocument(); Дополнительно о методах получения информации об узлах объекта Document и их атрибутах можно прочитать здесь. 14. Generic и его реализацииGeneric - это параметризованный тип, используемый для объявления классов, интерфейсов и методов, где тип данных указан в виде параметра. 2 примера использования коллекции : // вариант 1, приведение типа List intList = new LinkedList(); intList.add(new Integer(23)); Integer x = (Integer) intList.iterator().next(); // вариант 2, использование generic List<Integer> intList = new LinkedList<Integer>(); intList.add(new Integer(0)); Integer x = intList.iterator().next(); В первом варианте используется приведение типа (java casting), во втором – generic, не требующий java casting. Для определения параметризованного типа используются угловые скобки и символ (заполнитель), вместо которого будет подставлен реальный тип. Угловые скобки указывают, что параметр может быть обобщён. Сам класс (интерфейс, метод) при этом называется обобщённым или параметризованным. Пример определения и использования параметризированного класса : class GenericClass<T> { private T value; public GenericClass(T value) { this.value = value; } public T getValue() { return value; } public String toString() { return "{" + value + "}"; } } ... GenericClass<Integer> value1; GenericClass<String> value2; value1 = new GenericClass<Integer>(new Integer(10)); value2 = new GenericClass<String> ("Hello world"); System.out.println(value1); System.out.println(value2); Integer intValue1 = value1.getValue(); // Здесь возникает ошибка несоответствия типа Integer intValue2 = value2.getValue(); Generic работает только с объектом; нельзя использовать в качестве параметра элементарные типы int или char. Внутри generic'a класса информация о типе параметра не хранится. Это называется стиранием типов. На стадии компиляции происходит приведение объекта класса к типу, который был указан при объявлении. 15. Использование wildcardОбобщение wildcard, представляющий символ "?", используется в тех случаях, когда необходимо в качестве параметра указать соответствие любому типу. Так, например, Collection<Object> не является полностью родительской коллекцией всех остальных коллекций; то есть, Collection<Object> имеет ограничения. Но, если, использовать Collection<?>, то ограничений в использовании нет. void dump(Collection<?> c) { for (Iterator<?> i = c.iterator(); i.hasNext();) { Object o = i.next(); System.out.println(o); } } . . . List<Object> obj; List<Integer> lst; . . . dump(obj); dump(lst); В примере метод dump может быть вызван с любым типом коллекции. 16. Bounded wildcardBounded wildcard позволяет использовать наследование объектов при определении обобщенных типов. Допустим, фигуры Rectangle и Cycle наследуют свойство базового класса Shape. В этом случае можно указывать тип «? extends Shape», включающий класс Shape и его наследников, либо «? super Rectangle», включающий класс Rectangle и всех его предков вплоть до Object. Пример : void draw(List<? extends Shape> c) { for (Iterator<Shape> i = c.iterator(); i.hasNext(); ) { Shape s = i.next(); s.draw(); } } ... List<Shape> shapes; List<Circle> cycles; ... draw(shapes); draw(cycles); Процедуру draw можно можно вызывать с параметром Shape и его наследником. 17. Wildcard captureРассмотрим представленный в листинге метод : public void rebox(List <?> box) { box.add(box.get(0)); } Теоретически метод должен быть работающим : из коллекции извлекается элемент и повторно добавляется в эту же коллекцию. Таким образом, тип добавляемого объекта соответствует типу объектов коллекции. Однако среда разработки IDE (Eclipse), равно, как и компилятор, выдают сообщение об ошибке, связанное с несовместимостью типов : The method add(capture#1-of ?) in the type List<capture#1-of ?> is not applicable for the arguments (capture#2-of ?) Когда компилятор встречает переменную с wildcard'ом в ее типе, он знает, что здесь должен быть некий объект T. Тип объекта T ему неизвестен, и он может создать заглушку для данного типа, которая будет ссылаться на подставляемый T. Такое место вставки называется «capture» конкретного wildcard'а. В рассматриваемом случае компилятор назначил имя «capture#1-of ?» знаку wildcard в типе List сигнатуры метода. Но, каждое вхождение wildcard'а в переменные метода дает разные «capture». Поэтому, для метода get(0) была создана другая capture, отличающаяся от объявленного тип. Разнотипные «capture» блокируют компиляцию кода и выдают соответствующую ошибку. 18. Wildcard capture helperВ п.17 было сказано, что компилятор не пропустит метод rebox (см. листинг) и выдаст ошибку несовмещения типов. Данную проблему можно решить, используя механизм «capture helper», позволяющий вспомогательным методом предопределить тип wildcard'a. Рассмотрим следующий пример : public void rebox(List <?> box) { reboxHelper(box); } private<V> void reboxHelper(List <V> box) { box.add(box.get(0)); } Вспомогательный метод reboxHelper() использует дополнительный generic (<V>), помещаемый перед типом возвращаемого значения. Если его не указать, то IDE (Eclipse) и копмилятор сообщат об ошибке : The method reboxHelper(List<V>) from the type 'ClassName' refers to the missing type V Generic-метод reboxHelper не задействует параметр типа, а позволяет компилятору определить имя параметра типа переменной box. Таким образом, использование helper'а позволяет обойти ограничения компилятора на wildcard. Когда rebox() вызывает reboxHelper(), то ему уже известно, что это действие безопасно, поскольку его собственный параметр box должен иметь тип List<V>. Теперь выражение box.get(0) в reboxHelper() имеет тип не Object, а V, и можно передать параметр V в box<V>.add().
Вопросы и ответы для собеседование по Java, Содержание. |