1 / 22

Объектно-ориентированное программирование

Объектно-ориентированное программирование. Стандартные библиотеки ввода-вывода. В настоящее время используется 7 существенно разных типов кодировок: 1. Однобайтовые кодировки (256 символов , однобайтовые коды) а. семейство ASCII (коды 0-127 соответствуют таблице ASCII)

stacy
Télécharger la présentation

Объектно-ориентированное программирование

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Объектно-ориентированное программирование Стандартные библиотеки ввода-вывода

  2. В настоящее время используется 7 существенно разных типов кодировок: 1. Однобайтовые кодировки (256 символов, однобайтовые коды) а. семейство ASCII (коды 0-127 соответствуют таблице ASCII) б. семейство EBCDIC (применяются на мэйнфреймах) 2. Мультибайтовые одноязычные кодировки (применяются для кодирования иероглифов) а. префиксные (коды занимают 1 или 2 байта, разрядность кода определяется первым байтом) б. с переключением (коды занимают 1 или 2 байта, переключение разрядности производится специальными кодами shift-in и shift-out)3. Юникод (Unicode; 2 байтовый код, охватывает все действующие системы письменности) Важно! При чтении кода Unicode надо знать порядок следования байтов в коде (little endian / big endian) 4. UTF-8 (алгоритмическая трансформация Unicode; префиксный код с переменной длиной; совместима с кодом ASCII; обладает свойством синхронизации) 5. GB-18030 (4-байтовая кодировка для представления китайских иероглифов)

  3. UTF-8 (от англ. Unicode Transformation Format — формат преобразования Юникода) — кодировка, реализующая представление Юникода, совместимое с 8-битным кодированием текста (характерно для традиционных схем хранения строк в языках C/C++, Pascal и др.). Символы UTF-8 получаются из Unicode следующим образом: Unicode UTF-8 0x00000000—0x0000007F: 0xxxxxxx 0x00000080—0x000007FF: 110xxxxx 10xxxxxx 0x00000800—0x0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx 0x00010000—0x001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx (теоретически возможны, но не включены в стандарт также:) 0x00200000—0x03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 0x04000000—0x7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx

  4. Это один из способов для определения кодировки, используемой по умолчанию. public static void test7a() { try { String strEncoding = System.getProperty("file.encoding"); System.out.println("Input encoding is: "+strEncoding); System.out.print("Enter simple numeric expression: "); Scanner scanner = new Scanner( new InputStreamReader(System.in, strEncoding)); scanner.useDelimiter(""); String strVal1 = scanner.next("\\d+"); String strOp = scanner.next("[\\+\\-\\*/]"); String strVal2 = scanner.next("\\d+"); PrintWriter writer = new PrintWriter( new OutputStreamWriter( new BufferedOutputStream(System.out), strEncoding)); writer.println( MessageFormat.format("Parsed expression: {0} {1} {2}", new Object[]{strVal1, strOp, strVal2})); writer.flush(); } catch (IOException ex) { ex.printStackTrace(); } } Пример анализа входного потока:

  5. public static void test7a() { try { String strEncoding = System.getProperty("file.encoding"); System.out.println("Input encoding is: "+strEncoding); System.out.print("Enter simple numeric expression: "); Scanner scanner = new Scanner( new InputStreamReader(System.in, strEncoding)); scanner.useDelimiter(""); String strVal1 = scanner.next("\\d+"); String strOp = scanner.next("[\\+\\-\\*/]"); String strVal2 = scanner.next("\\d+"); PrintWriter writer = new PrintWriter( new OutputStreamWriter( new BufferedOutputStream(System.out), strEncoding)); writer.println( MessageFormat.format("Parsed expression: {0} {1} {2}", new Object[]{strVal1, strOp, strVal2})); writer.flush(); } catch (IOException ex) { ex.printStackTrace(); } } Пример анализа входного потока: Так инициализируется сканнер для синтаксического разбора входных данных

  6. public static void test7a() { try { String strEncoding = System.getProperty("file.encoding"); System.out.println("Input encoding is: "+strEncoding); System.out.print("Enter simple numeric expression: "); Scanner scanner = new Scanner( new InputStreamReader(System.in, strEncoding)); scanner.useDelimiter(""); String strVal1 = scanner.next("\\d+"); String strOp = scanner.next("[\\+\\-\\*/]"); String strVal2 = scanner.next("\\d+"); PrintWriter writer = new PrintWriter( new OutputStreamWriter( new BufferedOutputStream(System.out), strEncoding)); writer.println( MessageFormat.format("Parsed expression: {0} {1} {2}", new Object[]{strVal1, strOp, strVal2})); writer.flush(); } catch (IOException ex) { ex.printStackTrace(); } } Пример анализа входного потока: Так можно выделить во входном потоке лексемы по регулярному выражению

  7. public static void test7a() { try { String strEncoding = System.getProperty("file.encoding"); System.out.println("Input encoding is: "+strEncoding); System.out.print("Enter simple numeric expression: "); Scanner scanner = new Scanner( new InputStreamReader(System.in, strEncoding)); scanner.useDelimiter(""); String strVal1 = scanner.next("\\d+"); String strOp = scanner.next("[\\+\\-\\*/]"); String strVal2 = scanner.next("\\d+"); PrintWriter writer = new PrintWriter( new OutputStreamWriter( new BufferedOutputStream(System.out), strEncoding)); writer.println( MessageFormat.format("Parsed expression: {0} {1} {2}", new Object[]{strVal1, strOp, strVal2})); writer.flush(); } catch (IOException ex) { ex.printStackTrace(); } } Пример анализа входного потока: Так следует строить выходные сообщения программы

  8. Сериализация Практически все языки программирования предоставляют минимальный набор файловых операций, позволяющих работать с примитивными типами данных и со строками. В рамках ООП возникает вполне естественная задача: сохранения объекта в файл (или в какое-то иное хранилище) и последующее восстановление объекта из файла (хранилища). Процесс преобразования объекта в бинарный формат, пригодный для размещения в хранилище, называется сериализацией. Обратный процесс восстановления объекта из бинарного формата называется десериализацией. Способность к сериализации – это свойство конкретного класса. Для того, чтобы класс обладал этим свойством следует включить интерфейс Serializable в список интерфейсов, реализованных классом.

  9. class Person implements Serializable { private int m_iAge; private String m_strName; private Person() {} private Person(int iAge, String strName) { m_iAge = iAge; m_strName = strName; } public int getAge() { return m_iAge; } public void setAge(int age) { m_iAge = age; } public String getName() { return m_strName; } public void setName(String name) { m_strName = name;} } Минимальные требования к сериализуемому классу: реализация интерфейса Serializable и наличие конструктора (возможно, закрытого) без параметров. Пример использования сериализации (начало):

  10. public static void test8() { Person person = new Person(20, "Ivanov Ivan"); File file = new File("data.bin"); try { OutputStream os = new FileOutputStream(file); try { ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(os)); try { oos.writeObject(person); oos.flush(); } finally { oos.close(); } } finally { os.close(); } Пример использования сериализации (продолжение):

  11. InputStream is = new FileInputStream(file); try { ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(is)); try { Person restored = (Person)ois.readObject(); System.out.println(restored.getName()+": "+restored.getAge()); boolean bSame = (person == restored); System.out.println("Same object: "+bSame); } catch (ClassNotFoundException ex) { ex.printStackTrace(); } finally { ois.close(); } } finally { is.close(); } } catch (IOException ex) { ex.printStackTrace(); } } Пример использования сериализации (конец): Результат работы: Ivanov Ivan: 20 Same object: false

  12. По умолчанию процесс сериализации в JVM происходит следующим образом. 1. При вызове метода ObjectOutputStream.writeObject делается проверка, что параметр метода реализует интерфейс Serializable. Если проверка не проходит, то генерируется исключение. 2. JVM записывает имя и версию класса (версия получается из статического поля serialVersionUID, если таковое присутствует в классе; иначе версия строится автоматически по сигнатуре класса). 3. Если в сериализуемом классе присутствует метод writeReplace(), то он вызывается, и возвращенный им результат используется для сериализации. 4. JVM последовательно просматривает поля объекта. Поля примитивных типов записываются примерно тем же способом, как в рамках класса DataOutputStream. Поля объектных типов подвергаются записи путем рекурсивного вызова writeObject. Массивы обрабатываются специальным образом. 5. Получившийся в результате «пакет» информации передается в нижележащий бинарный поток.

  13. Процесс десериализации происходит аналогично: 1. Считывается пакет информации из нижележащего бинарного потока. 2. Из пакета выделяется имя класса, экземпляр которого следует реконструировать. Если описатель этого класса недоступен, генерируется исключение ClassNotFoundException (в этом случае, очевидно, десериализация невозможна). 3. JVM создает экземпляр класса путем особого (в обход обычных правил доступа к методам) вызова конструктора без параметров. 4. Считывается версия класса и делается проверка на совпадение с версией класса, созданного в п.3. 5. JVM последовательно просматривает поля объекта. Поля примитивных типов восстанавливаются путем чтения информации по аналогии с тем, как это делает DataInputStream. Поля объектных типов восстанавливаются путем рекурсивного вызова readObject. Массивы обрабатываются специальным образом. 6. Если в классе реализован метод readResolve(), то производится его вызов. Возвращенный им результат становится результатом десериализации.

  14. Сериализация позволяет полностью сохранить состояние объекта. Таким образом, сериализацию обычно применяют в следующих ситуациях: 1. при сохранении наборов данных во внешних хранилищах (фактически, это аналогично тому, как сохраняются документы в офисных программах) 2. При организации межпрограммного взаимодействия (в этом случае сериализованные классы передаются по сети между разными программами или даже разными системами).

  15. Программист имеет возможность явного управления процессом сериализации путем явного определения в своем классе следующих двух методов: private void writeObject(java.io.ObjectOutputStream out) throws IOException private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException; Метод writeObject должен обеспечить реализацию логики сериализации, а метод readObject должен обеспечить реализацию логики десериализации.

  16. private synchronized void writeObject(java.io.ObjectOutputStream s) throws IOException { s.defaultWriteObject(); s.writeChar(this.separatorChar); // Add the separator character } private synchronized void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); char sep = s.readChar(); // read the previous separator char if (sep != separatorChar) this.path = this.path.replace(sep, separatorChar); this.path = fs.normalize(this.path); this.prefixLength = fs.prefixLength(this.path); } Пример переопределения стандартной сериализации (класс File):

  17. объект - контейнер объект - контейнер Полностью процесс передачи данных при сериализации выглядит так: ObjectOutputStream ObjectInputStream BufferedOutputStream BufferedInputStream FileOutputStream FileInputStream файл Так собранный в одну цепочку набор фильтров называется стеком протоколов, поскольку каждый фильтр выполняет трансформацию данных в соответствии с некоторым протоколом. Наблюдение: аналогично устроен стек TCP/IP.

  18. Передача данных по сети. В процессе передачи данных по сети всегда принимают участие как минимум две системы: клиентская (инициирует соединение, как правило является активной стороной) и серверная (отвечает на соединение, как правило является пассивной стороной). Поэтому процесс организации соединения обычно является асимметричным: клиент сервер канал связи Межсетевой экран клиента позволяет открывать соединения лишь со стороны клиентской машины. Межсетевой экран сервера пропускает соединения лишь на определенные точки доступа (порты TCP/IP).

  19. Передача данных по сети. Чтобы организовать соединение по протоколу TCP/IP следует знать два идентификатора: идентификатор машины (IP-адрес) и идентификатор точки доступа к сервису (TCP-порт): 192.168.1.2 клиент 192.168.1.1 40000 сервер 192.168.1.3 клиент Для установления соединения на клиенте выделяется точка доступа (порт), соответственно, TCP/IP соединение возникает между двумя портами. К одному серверному порту может подключиться несколько клиентов.

  20. Передача данных по сети. Таким образом, для представления соединения по протоколу TCP/IP в программе следует иметь набор абстракций для представления объектов, участвующих в организации сетевого соединения. Какие абстракции нам нужны? 192.168.1.2 клиент 192.168.1.1 40000 сервер 192.168.1.3 клиент

  21. Передача данных по сети. Таким образом, для представления соединения по протоколу TCP/IP в программе следует иметь набор абстракций для представления объектов, участвующих в организации сетевого соединения. Какие абстракции нам нужны? окончание сетевого канала 192.168.1.2 адрес + порт клиент 192.168.1.1 сервер 40000 192.168.1.3 клиент серверная точка доступа

  22. В Java названные абстракции представляются следующими классами: InetAddress – представляет IP-адрес (позволяет определять свойства адреса, выполнять манипуляции с ним) ServerSocket – серверная точка доступа (отвечает за ожидание входящих соединения и создание окончания сетевого канала) Socket – представляет окончание сетевого канала (позволяет управлять соединением и получать бинарные потоки, связанные с сетевым каналом) SocketInputStream – представляет бинарный поток, через который можно извлекать данные, поступающие по сетевому каналу SocketOutputStream – представляет бинарный поток, через который можно отправлять данные в сетевой канал Все названные классы размещаются в пакете java.net, где собраны основные средства для работы с сетями.

More Related