Java. Полное руководство. 8-е издание. С. Н. Тригуб Перевод с английского и редакция
Скачать 25.04 Mb.
|
import java.util.regex.*; class RegExpr5 { public static void main(String args[]) { Pattern pat = Pattern.compile("e.+d"); Matcher mat = p a t .m a tcher("extend cup end table"); while(mat.fi n d (Совпадение " + m a t .g r o u p (Результаты выполнения этой программы могут быть для вас неожиданными. Совпадение: extend cup Был найден только один случай совпадения — это самая длинная последовательность, которая начинается се и заканчивается d. Вы могли предположить, что в результате выполнения будет найдено два случая совпадения " e x t e n d " и "end". Более длинная последовательность была обнаружена по той причине, что по умолчанию метод f i n d ( ) осуществляет сопоставление с самой длинной последовательностью, которая соответствует всему шаблону. Это называется поглощающим поведением Можно задать принудительное поведение, если добавить в комбинацию квантификатор ?, как показано в следующем варианте программы. В результате будет получен более короткий шаблон для сопоставления Использование квантификатора ?. import java.util.regex.*; class RegExpr6 { public static void main(String a r g s []) { // Использование поведения принудительного сопоставления pat = Pattern.compile("e .+?d"); Matcher mat = pat.matcher("extend cup end Совпадение " + m a t .g r o u p (Ниже представлены результаты выполнения этой программы. Совпадение: extend Совпадение end } } Глава 28. Регулярные выражения и другие пакеты 9 2 Как можно заметить из результатов, шаблоне" будет совпадать с более короткой последовательностью, которая начинается се и заканчивается d. Таким образом, будет обнаружено два случая совпадения. Работа с классами символов Иногда возникает необходимость в сопоставлении в любом порядке состоящей из одного или нескольких символов какой-нибудь последовательности, которая будет частью набора символов. Например, чтобы сопоставить целые слова, вам потребуется сопоставить любую последовательность букв алфавита. Проще всего это сделать с использованием класса символов, определяющего набор символов. Напомним, чтобы сформировать класс символов, необходимых для сопоставления, их потребуется заключить в квадратные скобки. Например, чтобы сопоставить символы нижнего регистра от а до z, используется запись [ a - z ] . В следующей программе демонстрируется этот способ Использование класса символов import java.util.regex.*; class RegExpr7 { public static void main(String a r g s []) { // Сопоставление слов в нижнем регистре pat = Pattern.compile("[a-z]+"); Matcher mat = pat.matcher("this is a Совпадение " + m a t .g r o u p (Ниже показаны результаты выполнения этой программы. Совпадение: this Совпадение is Совпадение а Совпадение Использование метода r e p l a c e A l l ( С помощью метода r e p l a c e A l l (), определенного в классе M a t c h e r , можно выполнять полноценные операции поиска и замены, в которых используются регулярные выражения. Например, в следующей программе каждая последовательность " J o n " заменяется последовательностью " E r i c ". // Использование метода replaceAll(). import java.util.regex.* ; class RegExpr8 { public static void main(String a r g s []) { String str = "Jon Jonathan Frank Ken Todd"; Pattern pat = Pattern.compile("Jon.*? "); Matcher mat = p a t .m a Начальная последовательность " + str); str = m a t .replaceAll("Eric "Измененная последовательность " + str); 9 2 Часть II. Библиотека Ниже представлены результаты выполнения этой программы. Начальная последовательность Jon Jonathan Frank Ken Todd Измененная последовательность Eric Eric Frank Ken Поскольку регулярное выражение " J o n . *?" сопоставляет любую строку, начинающуюся с последовательности J o n , за которой больше нет символов или стоит несколько символов, заканчивающихся пробелом, его можно применить для сопоставления и замены имени именем Eric. Такую замену нельзя было бы выполнить, если бы не было возможности осуществить сопоставление с шаблоном. Использование метода s p l i t ( С помощью метода s p l i t () можно сократить входящую последовательность до ее индивидуальных лексем, разделяемых пробелами, запятыми, точками и знаками восклицания Использование метода split(). import java.util.regex.*; class RegExpr9 { public static void main(String a r g s []) { // Сопоставление слов в нижнем регистре pat = Pattern.compile("[ String strs[] = p a t .split("one two,alpha9 12!done."); for(int i=0; i < strs.length; Следующая лексема " + Ниже представлены результаты выполнения программы. Следующая лексема one Следующая лексема two Следующая лексема alpha9 Следующая лексема 12 Следующая лексема Как можно заметить из результатов, входная последовательность сокращается до ее индивидуальных лексем. Обратите внимание разделители не включаются. Два варианта сопоставления с шаблоном Хотя описанные методы сопоставления с шаблонами характеризуются высокой степенью гибкости и хорошей производительностью, существует два варианта, применение которых в некоторых обстоятельствах может быть очень полезным. Если вам необходимо только одноразовое сопоставление с шаблоном, можете использовать метод m a tc h e s ( ) , определяемый классом P a t t e r n , static boolean mat c h e s (String шаблон CharSequence строка ) Метод возвращает значение t r u e , если шаблон шаблон совпадает со строкой в параметре строка, в противном случае он возвращает значение false. Этот метод автоматически компилирует шаблон, после чего производит поиск совпадения. Если использовать один и тот же шаблон несколько раз подряд, то применение метода m a t c h e s () будет менее эффективным, чем компиляция шаблона и использование методов сопоставления с шаблонами, определяемых классом M a tc h e s , о чем было сказано ранее Глава 28. Регулярные выражения и другие пакеты 9 2 Сопоставление с шаблоном можно также выполнять с помощью метода m at c h - e s ( ), реализуемого классом S t r i n g . Этот метод показан ниже matches(String шаблон) Если вызывающая строка совпадает с регулярным выражением в параметре шаблон, то метод m a t c h e s () возвращает значение t r u e . В противном случае он возвращает значение f a l s e Изучение регулярных выражений Обзор регулярных выражений, предложенный в этом разделе, лишь отчасти раскрывает их настоящие возможности. Поскольку синтаксический анализ текста, манипулирование и разбиение на лексемы являются частью программирования, то вы, скорее всего, придете к выводу, что подсистема регулярных выражений в Java является хорошим инструментом, который можно использовать с большой пользой. Поэтому вам следует потратить некоторое время на изучение свойств регулярных выражений. Поэкспериментируйте с несколькими различными типами шаблонов и входящих последовательностей. После того как разберетесь стем, как осуществляется сопоставление с шаблонами в регулярных выражениях, вы поймете, что использование этого подхода будет очень полезным при решении многих задач программирования. Рефлексия Рефлексия (reflection) — это способность программного обеспечения к самоанализу. Эта способность обеспечивается пакетом j a v a . l a n g . r e f l e c t и элементами класса C l a s s . Рефлексия является важным свойством, особенно для Java Beans. С ее помощью вы сможете анализировать компоненты программного обеспечения и описывать их свойства динамически вовремя выполнения, а неком пиляции. Например, с помощью рефлексии можно определить, какие методы, конструкторы и поля поддерживает конкретный класс. О рефлексии мы начали говорить в главе 12. В настоящей главе продолжим эту тему. Пакет j a v a . l a n g . r e f l e c t имеет несколько интерфейсов. Особый интерес представляет интерфейс Member, определяющий методы, которые позволяют получить информацию о поле, конструкторе или методе класса. В этом пакете существует также еще восемь классов. Все они перечислены в табл. Таблица 28.3. Классы, определенные в пакете java. lang.reflect Класс Основное назначение Позволяет обходить стандартные проверки управления доступом Array Позволяет динамически создавать массивы и манипулировать ими Constructor Предлагает информацию о конструкторе Field Предлагает информацию о поле Method Предлагает информацию о методе Modifier Предлагает информацию о модификаторах доступа к классу и его членам Proxy Поддерживает динамические прокси-классы ReflectPermission Разрешает рефлексию закрытых или защищенных членов класса 9 2 8 Часть II. Библиотека Следующее приложение иллюстрирует простой вариант использования свойств рефлексии в Java. Оно выводит на экран конструкторы, поля и методы класса j ava. awt. Dimension. Программа начинается с использования метода forName () класса Class для получения объекта класса j ava. awt. Dimension. После того как он будет получен, используются методы getCons true tors ( ) , getFileds () и get- Methods () для анализа этого объекта класса. Они возвращают массивы класса Constructor, Field и Method, содержащие информацию об объекте. Классы Constructor, Field и Method определяют несколько методов, которые могут использоваться для получения информации об объекте. Вам придется изучить их самостоятельно. Однако каждый из них поддерживает метод to String () . Таким образом, использование объектов класса Constructor, Field ив качестве параметров метода println () не представляет сложности, что можно видеть из самой программы Демонстрация применения рефлексии java.lang.reflect.*; ' public class ReflectionDemol { public static void main(String a r g s []) { try { Class> с = Class.forName("java.a w t Конструкторы constructors[] = с .getConstructors(); f o r ( m t i = 0; i < constructors. length; i + +) { System.out.println(" " + constructors[i Поля fields[] = с .getFields(); for(int i = 0; i < fields.length; i++) { System.out.println(" " + Методы m e thods[] = с .getMethods(); for(int i = 0; i < methods.length; i++) { System.out.println(" " + methods[i]); } } catch(Exception e) Исключение " + e ) Ниже приводятся результаты выполнения этой программы (у вас они могут немного отличаться). Конструкторы: public java.a w t .Dimension(in t , int) public java.a w t .Dimension() public Поля Методы int java.awt.Dimension.hashCode() public boolean java.awt.Dimension.equals(java.lang.Object) public java.lang.String java.a w t .Dimension.toString() public java.a w t .Dimension java.a w t .Dimension.getSize() public void java.awt.Dimension.setSize(double, double) public void java.a w t .Dimension.setSize(java.a w t .Dimension) public void java.a w t .Dimension.setSize(in t , int) Глава 28. Регулярные выражения и другие пакеты 2 9 public double java.a w t .Dimension.getHeight() public double java.a w t .Dimension.getWidth() public java.lang.Object java.awt.geom.Dimension2D.clo n e () public void java.a w t .geom.Dimension2D.setSize(java.a w t .geom. Dimension2D) public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.w a i t (long) throws java.lang.InterruptedException public final void java.lang.Object.wait() throws j a v a .lang.InterruptedException public final void java.lang.Object.wait(long, int) throws java.lang.InterruptedException public final native void java.lang.Object.notify() public final native void В следующем примере используются особенности рефлексии в Java для получения открытых методов класса. Программа начинается с реализации класса А. Метод g e t C l a s s () применяется к этой ссылке на объект и возвращает объект класса C l a s s для класса А. Метод g e t D e c l a r e d M e t h o d s () возвращает массив объектов класса Method, который описывает только методы, объявленные в этом классе. Методы, унаследованные от суперклассов, например класса Object, не включают ся. После этого обрабатывается каждый элемент массива m e t h o d s . Метод g e t M o d i f i e r s () возвращает значение типа int, содержащее флаги, которые описывают, какие модификаторы доступа применимы к этому элементу. Класс M o d i f i e r предлагает набор методов isX, перечисленных в табл. 28.4, которые можно использовать для проверки этого значения. Например, статический метод i s P u b l ic () возвращает значение true, если параметр включает модификатор доступа public. В противном случае он возвращает значение Таблица 28.4. Методы класса M o d i f i e r , определяющие модификаторы доступа Методы Описание Возвращает значение true, если значение имеет установленный флаг abstract, в противном случае возвращает значение Возвращает значение true, если значение имеет установленный флаг final, в противном случае возвращает значение Возвращает значение true, если значение имеет установленный флаг interface, в противном случае возвращает значение Возвращает значение true, если значение имеет установленный флаг native, в противном случае возвращает значение Возвращает значение true, если значение имеет установленный флаг private, в противном случае возвращает значение Возвращает значение true, если значение имеет установленный флаг protected, в противном случае возвращает значение Возвращает значение true, если значение имеет установленный флаг public, в противном случае возвращает значение false______________________ 30 Зак. 303 0 static boolean i s A b s t r a c t (int значение значение значение значение значение значение значение Часть II. Библиотека Окончание табл. 28.4 Методы Описание static boolean isStatic(int значение значение (int значение значение знач ен и е) Возвращает значение true, если значение имеет установленный флаг static, в противном случае возвращает значение Возвращает значение true, если значение имеет установленный флаг strict, в противном случае возвращает значение Возвращает значение true, если значение имеет установленный флаг synchronized, в противном случае возвращает значение Возвращает значение true, если значение имеет установленный флаг transient, в противном случае возвращает значение f a l s Возвращает значение true, если значение имеет установленный флаг volatile, в противном случае возвращает значение В следующей программе, если метод является открытым, с помощью метода getName () будет получено его имя и выведено на экран Отображение открытых методов import java.lang.reflect.*; public class ReflectionDemo2 { public static void main(String a r g s []) { try { A a = new A (); Class> с = a .getClass(); . Открытые методы m e thods[] = с .getDeclaredMethods(); for(int i = 0; i < methods.length; i++) { int modifiers = methods[i].getModifiers(); if(Modifier.isPublic(modifiers)) { System.out.p r intln(" " + m e t hods[i ].getName()); } } catch(Exception e) Исключение A { public void a l () { } public void a 2 () { } protected void a 3 () { } private void a 4 () Открытые методы: al а2 Ниже приводятся результаты выполнения этой программы Глава 28. Регулярные выражения и другие пакеты 3 Начиная с JDK 7 класс Modifier содержит также ряд статических методов, которые возвращают тип модификаторов, которые могут быть применены к определенному типу программного элемента. Вот эти методы int classModifiers() static int constructorModifiers() static int fieldModifiers() static int interfaceModifiers() static int Например, метод methodModif iers () возвращает модификаторы, которые могут быть применены к методу. Каждый метод возвращает упакованные в переменную типа int флаги, которые указывают допустимые модификаторы. Значения модификаторов определяются константами PROTECTED, PUBLIC, PRIVATE, STATIC, FINAL итак далее, определенными в классе Дистанционный вызов методов Дистанционный вызов методов (Remote M ethod Invocation — RMI) позволяет объектам Java, выполняющимся на одном компьютере, вызывать методы объектов Java, которые выполняются на другом компьютере. Это важная возможность, поскольку она позволяет создавать распределенные приложения. Несмотря на то что обсуждение RMI выходит за рамки этой книги, в приведенном ниже упрощенном примере демонстрируются основные принципы этого подхода. Клиент-серверное приложение, использующее В этом разделе предложено поэтапное руководство для создания простого клиент-серверного приложения с использованием RMI. Сервер получает запрос от клиента, обрабатывает его и возвращает результат. В этом примере запрос состоит из двух чисел. Сервер суммирует их и возвращает полученный результат. Этап первый вводи компиляция исходного кода Это приложение использует четыре исходных файла. В первом файле, AddServerlntf . java, определяется дистанционный интерфейс, который будет предоставлен сервером. Он содержит один метод, принимающий два параметра double, и возвращает их сумму. Все дистанционные интерфейсы должны расширять интерфейс Remote, который является частью пакета j ava. rmi. Интерфейс не определяет членов. Он предназначен лишь для того, чтобы показать, что интерфейс использует дистанционные методы. Все дистанционные методы могут передать исключение RemoteExcept ion. |