<?xml version="1.0"?>
<?xml-stylesheet type="text/css" href="http://wiki.linuxformat.ru/wiki/skins/common/feed.css?303"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki.linuxformat.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Maximax</id>
		<title>Linuxformat - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://wiki.linuxformat.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Maximax"/>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:Contributions/Maximax"/>
		<updated>2026-05-13T11:08:07Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.19.20+dfsg-0+deb7u3</generator>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF99:Java_EE</id>
		<title>LXF99:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF99:Java_EE"/>
				<updated>2008-03-19T07:15:02Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: Новая: {{Цикл/Java EE}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF98:Java_EE</id>
		<title>LXF98:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF98:Java_EE"/>
				<updated>2008-03-19T07:14:56Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: Новая: {{Цикл/Java EE}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF97:Java_EE</id>
		<title>LXF97:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF97:Java_EE"/>
				<updated>2008-03-19T07:14:17Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: Новая: {{Цикл/Java EE}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF95:Java_EE</id>
		<title>LXF95:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF95:Java_EE"/>
				<updated>2008-03-19T07:14:06Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: Новая: {{Цикл/Java EE}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF94:Java_EE</id>
		<title>LXF94:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF94:Java_EE"/>
				<updated>2008-03-19T07:14:00Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: Новая: {{Цикл/Java EE}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF93:Java_EE</id>
		<title>LXF93:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF93:Java_EE"/>
				<updated>2008-03-19T07:13:54Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: Новая: {{Цикл/Java EE}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF92:Java_EE</id>
		<title>LXF92:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF92:Java_EE"/>
				<updated>2008-03-19T07:13:47Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: {{Цикл/Java EE}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF91:Java_EE</id>
		<title>LXF91:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF91:Java_EE"/>
				<updated>2008-03-19T07:13:33Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: Новая: {{Цикл/Java EE}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF90:JavaEE</id>
		<title>LXF90:JavaEE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF90:JavaEE"/>
				<updated>2008-03-19T07:13:22Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: {{Цикл/Java EE}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF96:Java_EE</id>
		<title>LXF96:Java EE</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF96:Java_EE"/>
				<updated>2008-03-19T07:13:02Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: {{Цикл/Java EE}}&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java EE}}&lt;br /&gt;
== Java Enterprise Edition: Перекличка серверов ==&lt;br /&gt;
&lt;br /&gt;
''ЧАСТЬ 8, Отыскали пару лишних серверов и готовы написать настоящее распределенное приложение? '''Александр Бабаев''' подскажет подходящий способ.''&lt;br /&gt;
&lt;br /&gt;
На этом уроке наше приложение будет усложнено ровно в два раза. Раньше сервер был один (он обрабатывал запросы пользователей и менял список записей телефонной книги), теперь добавим ему напарника. Предположим, что это выделенный сервер, который хранит данные пользователей – имена, пароли, дополнительную информацию, и мы решили связать web-сервер с этим вторым, чтобы, например, можно было по имени пользователя получить дополнительную информацию о нем. &lt;br /&gt;
&lt;br /&gt;
Для удобства ссылок дадим серверам названия. Пускай наш старый называется Нео, а большой сервер с разной информацией – Матрица. &lt;br /&gt;
&lt;br /&gt;
Прикинем, как все устроить. Для тестов все программы (оба сервера) будут запускаться на одном компьютере. Но, поменяв соответствующие IP-адреса (ниже мы разберемся, какие именно), можно будет запускать Нео и Матрицу на разных компьютерах одной и той же подсети. Правда, если между ними есть всякие-разные устройства вроде маршрутизаторов, шлюзов и мостов, тесты могут и не заработать. Это предупреждение! Реализовать более сложную схему взаимодействия тоже можно, но на это нам, к сожалению, не хватит журнального места, которое вполне конечно. &lt;br /&gt;
&lt;br /&gt;
Итак, получается следующая топология сети: &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Изображение:LXF96-JavaEE_1.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Как докричаться? ===&lt;br /&gt;
Классический способ связи двух разных программ – через файлы:  одна пишет, другая читает. Например, можно сделать общий файл для записи команд, куда пишет Нео и откуда читает Матрица, и файл ответов, где запись/чтение происходят наоборот. &lt;br /&gt;
&lt;br /&gt;
Способ простой, но плохой: возникает огромное количество проблем, из которых падение производительности – самая маленькая. Рассматривать его не будем. &lt;br /&gt;
&lt;br /&gt;
Другой способ – связь через так называемый «сокет». Сокет – это такая штука, к которой можно присоединиться [англ. socket – «розетка»]. Сервер «открывает» сокет и «слушает» его. Клиент – подключается к серверному сокету, передает/получает данные, отключается. Затем подключается следующий клиент. &lt;br /&gt;
&lt;br /&gt;
Можно представить себе сокет как телефон. Вы получаете номер абонента (открываете сокет), подключаете телефон (теперь вы слушаете сокет), вам звонят – соединяются с вашим сокетом... Ну, вроде бы понятно? Примерно так же соединяются и компьютеры. А чтобы определить, к какому конкретно сокету присоединяться, нужно знать адрес IP-компьютера и номер порта, на котором открыт сокет. Номер порта необходим, потому что на одном и том же компьютере может быть запущено несколько «слушающих» программ (серверов), и нужно, чтобы они не мешали друг другу. А клиент, с другой стороны, должен точно указать, какой именно сервер ему нужен. &lt;br /&gt;
&lt;br /&gt;
Есть еще и третий способ, «каналы», но о нем мы поговорим несколько позже. &lt;br /&gt;
&lt;br /&gt;
=== Сокеты ===&lt;br /&gt;
Итак, общая схема работы с сокетами достаточно проста. Сервер создает сокет: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 ServerSocket serverSocket = new ServerSocket(); &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Дальше нужно открыть сокет для приема соединений. В Java это делается так: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 serverSocket.bind(new InetSocketAddress(“localhost”, 10000)); &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Здесь мы говорим, что сервер будет слушать соединения, в адресе назначения которых указано “localhost” и порт 10000. Сразу отметим: чтобы создать сервер на портах с номерами, меньшими 1024, обычно нужны права суперпользователя. &lt;br /&gt;
&lt;br /&gt;
Далее нужно ловить подключения. Обычно это делается в цикле (получили подключение, обработали, ждем следующее). Например, так: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 while (true) { &lt;br /&gt;
    Socket socket = serverSocket.accept(); &lt;br /&gt;
    int byteReceived = socket.getInputStream().read(); &lt;br /&gt;
    OutputStream outputStream = socket.getOutputStream(); &lt;br /&gt;
    outputStream.write(byteReceived + 1); &lt;br /&gt;
    socket.close(); &lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
serverSocket.accept() ждет подключения, блокируя текущий поток, и как только оно появится, создает так называемый клиентский сокет, продолжая выполнение потока. Я читаю из потока сокета один байт, записываю в сокет его же плюс единицу и закрываю сокет. &lt;br /&gt;
&lt;br /&gt;
Вот так все несложно. А как устроен клиент? Он создает сокет, пишет в него единицу, читает ответ (двойку) и выводит ее на экран. По Jav’овски это выглядит так: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 Socket socket = new Socket(“localhost”, 10000); &lt;br /&gt;
 socket.getOutputStream().write(1); &lt;br /&gt;
 int result = socket.getInputStream().read(); &lt;br /&gt;
 System.out.println(“Result is: “ + result); &lt;br /&gt;
 socket.close(); &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Здесь тоже все предельно просто, но тем не менее, работает. То есть, если создать два класса и в main первого поставить код сервера, запустить (он будет «висеть», слушая соединения), в main второго – код клиента, и запустить... Клиент выдаст 2. &lt;br /&gt;
&lt;br /&gt;
=== NIO ===&lt;br /&gt;
Проблемы начинаются, когда соединений больше одного, когда их одновременно больше одного, когда они достаточно длительные, когда нужно принимать/отсылать громадные файлы или протокол работы сложный. Если все делать вручную, как мы сейчас, то получается очень и очень трудоемко: огромное количество потоков (рекомендуется, собственно, по одному на каждый запрос), проблемы отсоединений клиентов, отслеживания этих событий, сериализация (запись в поток и обратно) объектов, и так далее. &lt;br /&gt;
&lt;br /&gt;
Еще один минус блокирующих сокетов в том, что они (простите за  тафтологию) блокируют поток в ожидании подключения. А если под ключения нет? Значит, поток заблокирован навсегда. И дело не только в подключениях, но и в записи/чтении в/из сокета: случись что во время этих операций – заблокируют навсегда. Вдобавок при большом количестве  соединений/потоков скорость работы сервера уменьшается гораздо быстрее, чем увеличивается количество соединений. То есть имеет место типичная ситуация плохой масштабируемости.&lt;br /&gt;
&lt;br /&gt;
И тут на помощь приходит новый способ обработки соединений – NIO (The new I/O API), хотя и более сложный, но гораздо более масштабируемый. Эта библиотека появилась в Java 1.4, и она позволяет создавать неблокирующие соединения. Рассмотрим тот же сервер и клиент в реализации NIO.. Сначала создадим так называемый «канал»:      &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  Selector acceptSelector = SelectorProvider.provider().openSelector(); &lt;br /&gt;
  ServerSocketChannel socketChannel = ServerSocketChannel.open(); &lt;br /&gt;
  socketChannel.configureBlocking(false); &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Мы не просто создали канал, но еще и объявили его неблокирующим (работа с блокирующими каналами ничуть не лучше работы с блокирующими сокетами). Теперь нужно «объяснить» каналу, какие события нам интересны (присоединение клиента, чтение, запись, отсоединение). Займемся подсоединением клиента:         &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  socketChannel.socket().bind(new InetSocketAddress(“localhost”,  10000)); &lt;br /&gt;
  socketChannel.register(acceptSelector, SelectionKey.OP_ACCEPT); &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Теперь начинаем волшебный цикл обработки. В цикле проверяем, есть ли интересующие нас события в «канале», и если есть, итерируем по ним, получая клиентский сокет. Дальше с сокетом работаем так же, как было описано выше.     &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  while (acceptSelector.select() &amp;gt; 0) { &lt;br /&gt;
    Set readyKeys = acceptSelector.selectedKeys(); &lt;br /&gt;
    Iterator i = readyKeys.iterator(); &lt;br /&gt;
    &lt;br /&gt;
   while (i.hasNext()) { &lt;br /&gt;
    SelectionKey key = (SelectionKey) i.next(); &lt;br /&gt;
    i.remove(); &lt;br /&gt;
    ServerSocketChannel nextReady = (ServerSocketChannel) key.  channel(); &lt;br /&gt;
    Socket socket = nextReady.accept().socket(); &lt;br /&gt;
    outputInputPlusOne(socket); &lt;br /&gt;
    } &lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Функция outputInputPlusOne(socket), как мы делали ранее, читает число, увеличивает его на 1 и записывает результат. При этом поток постоянно крутится в цикле, не блокируясь. Это позволяет использовать достаточно интересные методы обработки подключений: например, создавать только один поток для произволь ного количества подключений, и он один будет их все обрабатывать. Плюс, операции чтения и записи тоже можно сделать неблокирующими, и совсем будет сказка... Если бы не сложность. Переход на неблокирующую обработку подключений – увеличение объема программы в три раза. Неблокирующая запись и чтение – еще больше. В результате получается достаточно громоздкая схема. Увы, только так можно добиться хорошей производительности.   &lt;br /&gt;
&lt;br /&gt;
=== Минное поле ===&lt;br /&gt;
Но есть замечательная библиотека, где все это уже учтено. Внутри она использует NIO, поэтому отлично масштабируется. Зато наружу выходят очень простые и понятные методы, которые можно использовать, получая превосходный результат. Библиотека называется Apache Mina, она достаточно широко распространена (например, Jetty, который мы рассматривали в первой статье цикла, использует именно ее) и неплохо отлажена. Иными словами, ею можно пользоваться в «промышленных» масштабах, не особо беспокоясь о проблемах. &lt;br /&gt;
Сервер делается так: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  SocketAcceptorConfig acceptorConfig = new SocketAcceptorConfig(); &lt;br /&gt;
  acceptorConfig.getFilterChain().addLast(“Serializator”, new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); &lt;br /&gt;
  DataServerHandler handler = new DataServerHandler(); &lt;br /&gt;
  SocketAcceptor acceptor = new SocketAcceptor(); &lt;br /&gt;
  acceptor.bind(new InetSocketAddress(“localhost”, 10000), handler, acceptorConfig); &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
В первой строчке создается конфигуратор (через него задаются разные параметры подключения), затем в него вставляется фильтр, через который пройдут все данные (фильтр распаковывает объекты Java из потока). В третьей строке создается обработчик событий (о нем чуть ниже), который обрабатывает события Mina, и дальше – инициализируется сервер (опять тот же bind). &lt;br /&gt;
&lt;br /&gt;
Поскольку Mina использует NIO, сервер получается событийный. При подключении клиента вызывается обработчик (Handler), который обслуживает запрос. При поступлении данных – тоже вызывается Handler (уже другой метод). И так далее. Вот как выглядит обработчик  - (Handler) в нашем случае: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  public class DataServerHandler extends IoHandlerAdapter { &lt;br /&gt;
  public void messageReceived(IoSession session, Object message) &lt;br /&gt;
  throws Exception { &lt;br /&gt;
      if (message instanceof Integer) { &lt;br /&gt;
          session.write(((Integer) message) + 1); &lt;br /&gt;
          session.close(); &lt;br /&gt;
     } &lt;br /&gt;
   } &lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Мы переопредили только один метод, который отвечает за получе ние данных. Mina работает не с потоками, а с объектами (преобразованием занимается фильтр, который мы вставляли в конфигуратор). Поэтому наша задача упрощается: читаем Integer, прибавляем единицу, записываем обратно, закрываем сессию. Все. &lt;br /&gt;
&lt;br /&gt;
Предыдущий клиент, правда, не подойдет – нужно создавать другой. Но он не сложнее, чем был. Вот его код: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 SocketConnector connector = new SocketConnector(); &lt;br /&gt;
 SocketConnectorConfig config = new SocketConnectorConfig(); &lt;br /&gt;
 config.getFilterChain().addLast(“Serializator”, new ProtocolCodecFilter(new ObjectSerializationCodecFactory())); &lt;br /&gt;
 ConnectFuture connectFuture = connector.connect(new InetSocketAddress(“localhost”, 10000), new DataClientHandler(), config); &lt;br /&gt;
 connectFuture.join(); &lt;br /&gt;
 IoSession session = connectFuture.getSession(); &lt;br /&gt;
 session.write(new Integer(1)); &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Код клиента – практически точное повторение кода сервера. Даже обработчик есть. Только вместо Acceptor’а создаем Connector. connectFuture – это объект, который позволяет, во-первых, дождаться, пока присоединимся (.join()), а во-вторых, от него получается сессия, куда можно писать всякие объекты (в нашем случае – Integer). Обработчик, как и на сервере, простой: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  public class DataClientHandler extends IoHandlerAdapter { &lt;br /&gt;
  public void messageReceived(IoSession session, Object message) &lt;br /&gt;
  throws Exception { &lt;br /&gt;
  System.out.println(“Result is: “ + message.toString()); &lt;br /&gt;
  } &lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Все. Сложность в данном конкретном случае – четыре класса вместо двух. Но это оправданно. Mina позволяет гибко настраивать обработку данных, бегающих между клиентом и сервером: количество потоков, обрабатывающих каналы, и так далее. Все это позволяет создавать простые серверы буквально за минуты, а сложные – за считанные часы или за несколько дней. &lt;br /&gt;
&lt;br /&gt;
=== RMI ===&lt;br /&gt;
Еще один способ соединения двух Java-программ – RMI (Remote Method Invocation, удаленный вызов метода). Это несколько другой класс соединений, который скрывает сокеты и прочую внутреннюю механику от программиста, но требует понимания совершенно других принципов. &lt;br /&gt;
&lt;br /&gt;
Для работы RMI использует так называемый registry. Это специальная служебная программа, которая аккуратно регистрирует классы, желающие быть серверами. Например, там может зарегистрироваться наш сервер. После чего клиент, зная, где находится registry, подключается к нему и просит выдать ссылку на сервер – и получает ссылку на класс. &lt;br /&gt;
&lt;br /&gt;
После этих магических пассов методы сервера можно вызывать, как будто они находятся прямо в клиенте, в той же Java-машине. А RMI сам понимает, что вызван метод сервера, организует передачу/прием  данных, преобразования всего из всего и выдает результат. На Рис. 2 приведена схема работы RMI (исключая registry): &lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
[[Изображение:LXF96-JavaEE_2.png]]&lt;br /&gt;
&lt;br /&gt;
При создании класса, который может быть вызван удаленно (схема, когда обращаются непосредственно к методу, а он скрытыми путями вызывается на удаленной машине, называется удаленным вызовом, Remote Procedure Call), генерируются специальные классы-заглушки (stubs). Они-то и делают все «взмахи волшебными палочками». На самом деле, когда клиент выполняет удаленный вызов, вызывается аналогичный серверному метод заглушки. В этом методе параметры сериализуются и через сокет передаются на сервер, где вновь десериализуются, вызывается сервер, а ответ передается таким же образом (через заглушки) клиенту. &lt;br /&gt;
Чтобы RMI заработал, нужно сделать интерфейс для сервера и его реализацию, написать клиент, потом сгенерировать заглушки, все скомпилировать и запустить. &lt;br /&gt;
Интерфейс сервера прост: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  public interface IRMIServer extends Remote { &lt;br /&gt;
  public abstract int increment(int aValue) throws RemoteException; &lt;br /&gt;
  } &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Он должен наследоваться от интерфейса Remote, и все методы, вызываемые удаленно, должны выбрасывать исключение RemoteException. Реализация сервера не менее проста: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  public class RMIServer implements IRMIServer { &lt;br /&gt;
     public RMIServer() throws RemoteException { &lt;br /&gt;
  super(); &lt;br /&gt;
  } &lt;br /&gt;
      &lt;br /&gt;
  public int increment(int aValue) throws RemoteException { &lt;br /&gt;
    return aValue + 1; &lt;br /&gt;
   } &lt;br /&gt;
 } &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Реализация должна обязательно иметь конструктор по умолчанию, который выкидывает исключение RemoteException и вызывает super(). Метод реализуется как обычно. &lt;br /&gt;
Регистрация сервера может быть выполнена, например, в методе  main того же сервера: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  public static void main(String[] args) throws Exception { &lt;br /&gt;
    System.setSecurityManager(new RMISecurityManager()); &lt;br /&gt;
    RMIServer Server = new RMIServer(); &lt;br /&gt;
    Naming.rebind(“RMIServer” , Server); &lt;br /&gt;
    } &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Здесь устанавливается менеджер безопасности (иначе нам скажут, что нет прав для работы с RMI), создается сервер и регистрируется в registry (rebind). Есть и метод bind, но он выдаст ошибку, если такой сервер уже зарегистрирован. В целях экономии места используем rebind, который проверку на существование такого же сервера не выполняет. &lt;br /&gt;
&lt;br /&gt;
Клиент тоже устанавливает менеджер безопасности, после чего в registry ищет сервер (имя он знает). Как только найдет – просто вызывает метод, как если бы RMI не существовало. &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
  public class RMIClient { &lt;br /&gt;
    public static void main(String[] args) throws MalformedURLException,NotBoundException, RemoteException { &lt;br /&gt;
           System.setSecurityManager(new RMISecurityManager()); &lt;br /&gt;
           String url = “//localhost/RMIServer”; &lt;br /&gt;
           IRMIServer remoteObject = (IRMIServer) Naming.lookup(url); &lt;br /&gt;
           System.out.println(“Result is “ + remoteObject.increment(1)); &lt;br /&gt;
        } &lt;br /&gt;
     } &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Запуск сервера и клиента несколько более сложен, чем обычно. До сих пор мы компилировали и запускали классы «просто так». Теперь создадим заглушки и запустим registry. Это делается так: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
rmic RMIServer &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
создаст заглушку сервера (сначала нужно все скомпилировать, а потом выполнить эту команду с полным именем класса сервера). А команда &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
rmiregistry &amp;amp; &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
запустит RMI Registry с параметрами по умолчанию. Чтобы разрешить менеджеру безопасности делать все что угодно, нужно запустить клиент и сервер с параметром, указывающим на файл политики безопасности. Назовем этот файл open.policy и запишем в него следующее: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 grant { &lt;br /&gt;
    permission java.security.AllPermission; &lt;br /&gt;
   };&lt;br /&gt;
&amp;lt;/code&amp;gt; &lt;br /&gt;
Теперь запустим клиент и сервер: &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 java -Djava.security.policy=open.policy RMIServer &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
и &lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 java -Djava.security.policy=open.policy RMIClient &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Вот и все. Как можно заметить, чем проще и понятнее код клиента и сервера, тем больше телодвижений нужно сделать для запуска разных вспомогательных приложений. Это общая закономерность. Пока приложения простые, зачастую удобнее использовать просто сокеты; в более тяжелых случаях (например, для работы клиент-серверных приложений уровня предприятия, тех самых Enterprise Applications) проще один раз запустить что-то вроде registry, а потом пользоваться «благами цивилизации». &lt;br /&gt;
&lt;br /&gt;
Стоит отметить, что RMI, создаваемый «по умолчанию», в нормальных приложениях использовать нельзя. Слишком много ограничений, слишком много неразрешимых проблем (например, если клиент и сервер находятся в разных подсетях, соединение становится почти невозможным; или – невозможно внести в registry-сервер, который запущен не на той же машине, где и registry). Но реализации, которые предоставляют так называемые контейнеры приложений (GlassFish, Sun WebSphere, JBoss и другие) – это именно то, что используется для связи клиентов с сервером. Там это все работает, и работает отлично.&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF87-88:Java</id>
		<title>LXF87-88:Java</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF87-88:Java"/>
				<updated>2008-03-19T07:12:00Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: ссылка в конце статьи на следующий цикл статей по java&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java}}&lt;br /&gt;
&lt;br /&gt;
=== Потоки в Java ===&lt;br /&gt;
''ЧАСТЬ 4: Завершая курс молодого Java-бойца, '''Антон Черноусов''' научит вас управлять потоками… Жаль, что не денежными.''&lt;br /&gt;
&lt;br /&gt;
C каждым днем появляются все более мощные процессоры, многоядерная архитектура которых стала основной темой ушедшего года, поэтому двухядерный процессор в ноутбуке уже никого не удивляет. С одной стороны — это обстоятельство приближает возможности простого пользователя к возможностям «понастоящему» больших систем. С другой (и рекламные буклеты об этом обычно молчат) — для того, чтобы использовать весь потенциал современных компьютеров, приложение должно «уметь» просчитать задачу фактически на двух или более процессорах.&lt;br /&gt;
&lt;br /&gt;
Создание эффективных алгоритмов для работы на многопроцессорных станциях — это большая и сложная работа. Несмотря на это, для любого программиста актуальна задача организации взаимодействия с медленными ресурсами (например, чтения, записи или копирования файлов, работы с принтером, сетью), так как немногие пользователи смирятся с тем, что их любимая программа «замирает» в момент выполнения какой-либо операции.&lt;br /&gt;
&lt;br /&gt;
Во избежание описанных проблем программа должна использовать потоки или процессы. Под процессом понимается заявка на потребле-&lt;br /&gt;
ние всех видов ресурсов системы, кроме одного — процессорного времени, или иначе говоря, процесс — это запущенная на выполнение программа (такое определение дается в [[LXF87/88:Java#Литература|[1]]]). Поток рассматривается как самостоятельная активность внутри процесса, хотя существуют другие трактовки этого понятия, которые зависят от используемой операционной системы (см., например, [[LXF87/88:Java#Литература|[2]]]). Поток получил свое название по аналогии с потоком команд, поступающих в процессор; при выполнении потоки делят адресное пространство и выделенную память внутри одного процесса. Процессорное время распределяется между различными потоками операционной системой, точнее, одним из компонентов ее ядра — планировщиком. Более полно с понятием процессов и потоков и механизмов работы с ними с точки зрения операционной системы вы можете ознакомиться в книге [[LXF87/88:Java#Литература|[3]]].&lt;br /&gt;
&lt;br /&gt;
Давайте завершим наш экскурс в теорию и окунемся в реальность Java. Под процессом здесь принято понимать всеобъемлющий контекст выполнения, обеспечивающий высокий уровень изоляции охватываемых им данных от внешнего мира, а под потоком — более «легковесный» активный агент; в контексте одного процесса может функционировать целое множество потоков [[LXF87/88:Java#Литература|[4]]]. Планирование потоков в Java обеспечивается внутренними механизмами JVM.&lt;br /&gt;
&lt;br /&gt;
=== Поток, он же thread ===&lt;br /&gt;
В Java существует два способа работы с потоками: первый заключается в реализации интерфейса Runnable, второй связан с наследованием&lt;br /&gt;
класса Thread, который уже реализует данный интерфейс. В обоих случаях класс должен предоставлять реализацию метода run(). Ниже&lt;br /&gt;
приведен пример класса, реализующего поток через наследование класса Thread:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class FirstThread extends Thread {&lt;br /&gt;
  public void run(){&lt;br /&gt;
    for (int i = 1 ; i &amp;lt; 30; i++)&lt;br /&gt;
      System.out.println(&amp;quot;It is in thread &amp;quot;+ i);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Собственно, метод run() и должен содержать некоторый набор инструкций (разумеется, на языке Java), которые вы хотите выполнить&lt;br /&gt;
в отдельном потоке. Например, если вы реализуете функцию копирования файла (а пользователь, скажем, копирует ISO-образ объемом&lt;br /&gt;
600 Мб), желательно, чтобы эта операция выполнялась в отдельном потоке, запуск которого можно производить следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class ConsoleToThread {&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    FirstThread thread = new FirstThread();&lt;br /&gt;
    thread.start();&lt;br /&gt;
    for (int i = 1; i &amp;lt; 20; i++) {&lt;br /&gt;
      System.out.println(&amp;quot;It is in main &amp;quot; + i);&lt;br /&gt;
    }&lt;br /&gt;
    try {&lt;br /&gt;
      thread.join();&lt;br /&gt;
    } &lt;br /&gt;
    catch (InterruptedException ex) {&lt;br /&gt;
      System.out.println(&amp;quot;Exception in stop thread&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
При выполнении метода main() класса ConsoleToThread создается объект-поток FirstThread, который запускается на выполнение методом start() [заметьте — метод run() никогда не вызывается явно, — прим.ред.]. Метод join() используется в случае, когда необходимо «дождаться» завершения потока. Завершение работы потока происходит при выходе из метода run(), как явном (например, посредством return), так и неявном (если внутри метода возникло и не было обработано какое-то исключение).&lt;br /&gt;
&lt;br /&gt;
Имейте в виду (это важно!): повторный запуск уже отработавшего потока приведет к исключению IllegalThreadStateException.&lt;br /&gt;
&lt;br /&gt;
=== Реализация потока через Runnable ===&lt;br /&gt;
Давайте теперь рассмотрим пример работы с потоками через интерфейс Runnable. Если, допустим, класс SameRunnable реализует интерфейс Runnable, то запустить поток на основе этого класса на выполнение можно следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
Runnable run = new SameRunnable();&lt;br /&gt;
Thread thread = new Thread(run);&lt;br /&gt;
thread.start();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В следующем примере в методе main() класса ConsoleToThreadTwo создается массив threadArray, состоящий из объектов-потоков. При&lt;br /&gt;
этом используется конструктор класса Thread, принимающий два параметра: ссылку на объект, реализующий интерфейс Runnable и&lt;br /&gt;
имя потока:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
Thread thread = new Thread(Runnable, ThreadName);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Метод getName() объекта, реализующего поток, возвращает указанное при создании имя. Обратите внимание, что в нем используется&lt;br /&gt;
статический метод Thread.currentThread(), возвращающий ссылку на объект Thread, соответствующий выполняющемуся в текущий момент&lt;br /&gt;
потоку:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class SecondThread implements Runnable {&lt;br /&gt;
  public String getName() {&lt;br /&gt;
    return Thread.currentThread().getName();&lt;br /&gt;
  }&lt;br /&gt;
  public void run() {&lt;br /&gt;
    for (int i = 1; i &amp;lt; 100000; i++) {&lt;br /&gt;
      if ((i % 10000) == 0) {&lt;br /&gt;
        System.out.println(getName() + &amp;quot; counts &amp;quot; + i / 10000);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public class ConsoleToThreadTwo {&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    Thread[] threadArray = new Thread[3];&lt;br /&gt;
      for (int i=0; i&amp;lt;threadArray.length; i++){&lt;br /&gt;
        threadArray[i] = new Thread(new SecondThread(), &amp;quot;Thread &amp;quot; + i);&lt;br /&gt;
      }&lt;br /&gt;
      for (int i=0; i&amp;lt;threadArray.length; i++){&lt;br /&gt;
        threadArray[i].start();&lt;br /&gt;
        System.out.println(threadArray[i].getName() + &amp;quot; started&amp;quot;);&lt;br /&gt;
      }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Проследив за выводом этой программы, можно заметить, что процессорное время распределяется между потоками практически равномерно, однако порядок их выполнения во многом случаен.&lt;br /&gt;
&lt;br /&gt;
=== Приоритеты потоков ===&lt;br /&gt;
Для управления величиной процессорного времени, выделяемого потоку, можно воспользоваться приоритетами. Установка приоритетов происходит с помощью метода Thread.setPriority(), узнать текущий приоритет позволяет метод getPriority(). В классе Thread определены&lt;br /&gt;
три константы:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
MIN_PRIORITY = 1&lt;br /&gt;
NORM_PRIORITY = 5&lt;br /&gt;
MAX_PRIORITY = 10&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Важно понимать, что значение приоритета потока предназначено для Java-машины и не соответствует реальным приоритетам потоков&lt;br /&gt;
в операционной системе.&lt;br /&gt;
&lt;br /&gt;
Давайте немного изменим код метода main() класса ConsoleToThreadTwo:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public static void main(String[] args) {&lt;br /&gt;
  Thread[] threadArray = new Thread[3];&lt;br /&gt;
  int pr = 0;&lt;br /&gt;
  for (int i=0; i&amp;lt;threadArray.length; i++){&lt;br /&gt;
    threadArray[i] = new Thread(new SecondThread(), &amp;quot;Thread &amp;quot; + i);&lt;br /&gt;
    if (pr == 10) &lt;br /&gt;
      pr = 0; &lt;br /&gt;
    threadArray[i].setPriority(Thread.MIN_PRIORITY + pr);&lt;br /&gt;
    pr++;&lt;br /&gt;
  }&lt;br /&gt;
  for (int i=0; i&amp;lt;threadArray.length; i++){&lt;br /&gt;
    threadArray[i].start();&lt;br /&gt;
    System.out.println(threadArray[i].getName() + &amp;quot; started&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Анализ результатов работы класса показывает, что потоки, получившие более высокий приоритет, выполняются чаще. Также, благодаря&lt;br /&gt;
условию на значение переменной pr, setPriority() никогда не будет передан приоритет, превышающий 10 (MAX_PRIORITY). Если бы это про-&lt;br /&gt;
изошло, система выбросила бы исключение IllegalArgumentException.&lt;br /&gt;
&lt;br /&gt;
=== Потоки-демоны ===&lt;br /&gt;
Сделаем еще одно важное замечание: программа будет выполняться до тех пор, пока выполняется хотя бы один запущенный в ней поток;&lt;br /&gt;
единственным исключением являются потоки-демоны.&lt;br /&gt;
&lt;br /&gt;
Что же это такое? Демон отличается от «простого смертного» потока вызовом метода setDeamon(true), который необходимо сделать до&lt;br /&gt;
начала работы. Например, так:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
FirstThread thread = new FirstThread();&lt;br /&gt;
thread.setDeamon(true);&lt;br /&gt;
thread.start();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Узнать, является ли поток демоном, можно с помощью метода isDeamon(). Обычно потоки-демоны создаются для обслуживания&lt;br /&gt;
некритичных задач, так как при завершении работы программа не дожидается их остановки, а прерывает их самостоятельно.&lt;br /&gt;
&lt;br /&gt;
=== Где искать потоки? ===&lt;br /&gt;
В большинстве случаев бывает необходимо отслеживать ранее запущенные на выполнение потоки. Использование массива потоков,&lt;br /&gt;
как в предыдущем примере, не всегда оправданно. Для хранения и обработки потоков в Java существует класс ThreadGroup. Группа,&lt;br /&gt;
к которой принадлежит создаваемый поток, опять-таки передается конструктору Thread():&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
ThreadGroup tg = new ThreadGroup(&amp;quot;NameThreadGroup&amp;quot;);&lt;br /&gt;
Thread thread = new Thread(tg, new SecondThread(), &amp;quot;ThreadName&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Если группа не указана явно, поток будет помещен в тот же ThreadGroup, что и его родитель.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
ThreadGroup tg = new ThreadGroup(&amp;quot;NameThreadGroup&amp;quot;);&lt;br /&gt;
Thread thread = new Thread(tg, new SecondThread(), &amp;quot;ThreadName&amp;quot;);&lt;br /&gt;
Thread thread1 = new Thread(tg, new SecondThread(), &amp;quot;ThreadName2&amp;quot;);&lt;br /&gt;
Thread thread2 = new Thread(tg, new SecondThread(), &amp;quot;ThreadName3&amp;quot;);&lt;br /&gt;
System.out.println(&amp;quot;active thread in group &amp;quot; + tg.activeCount());&lt;br /&gt;
thread.start();&lt;br /&gt;
thread1.start();&lt;br /&gt;
System.out.println(&amp;quot;active thread in group &amp;quot; + tg.activeCount());&lt;br /&gt;
Thread[] threads = new Thread[tg.activeCount()];&lt;br /&gt;
int m = tg.enumerate(threads);&lt;br /&gt;
System.out.println(&amp;quot;taked threads from group : &amp;quot; + m);&lt;br /&gt;
for (int i = 0; i &amp;lt; threads.length; i++) {&lt;br /&gt;
  System.out.println(threads[i].getName());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В представленном выше примере в экземпляр класса ThreadGroup помещаются три потока, два из которых запускаются на выполнение.&lt;br /&gt;
Количество активных потоков в группе определяется с помощью метода activeCount(), а в результате выполнения метода enumerate() формируется перечень всех активных потоков.&lt;br /&gt;
&lt;br /&gt;
=== Управление потоками ===&lt;br /&gt;
При запуске потоков следует учитывать и то, что их иногда приходится останавливать, причем как штатно, так и экстренно. Для того, чтобы&lt;br /&gt;
приостановить работу потока изнутри, допустим, в тот момент, когда закончилась доступные для обработки данные, можно использовать&lt;br /&gt;
два метода: sleep() и wait().&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class ThirdThread extends Thread {&lt;br /&gt;
  public void run() {&lt;br /&gt;
    for (int i = 1; i &amp;lt; 110; i++) {&lt;br /&gt;
      if (i == 10) {&lt;br /&gt;
        try {&lt;br /&gt;
          sleep(10000);&lt;br /&gt;
        } &lt;br /&gt;
        catch (InterruptedException e) {&lt;br /&gt;
          System.out.println(&amp;quot;the thread was awaken there (just a moment ago)&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      if (i == 100) {&lt;br /&gt;
        try {&lt;br /&gt;
          synchronized (this) { wait();}&lt;br /&gt;
        }&lt;br /&gt;
        catch (InterruptedException e) {&lt;br /&gt;
          System.out.println(&amp;quot;the thread was awaken there (just a moment ago)again&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      } &lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Методу sleep() передается переменная типа long, соответствующая количеству миллисекунд, в течении которых поток будет «спать». В&lt;br /&gt;
случае wait() поток ждет пробуждения снаружи. Применение методов sleep() и wait() требует обработки исключительной ситуации, которая возникают при пробуждении потока. В представленном ниже классе ConsoleToThreadThree потоки пробуждаются с помощью метода interrupt():&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class ConsoleToThreadThree {&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    ThirdThread thread = new ThirdThread();&lt;br /&gt;
    thread.start();&lt;br /&gt;
    for (int i = 1; i &amp;lt; 20; i++) {&lt;br /&gt;
      System.out.println(&amp;quot;It is in main &amp;quot; + i);&lt;br /&gt;
    }&lt;br /&gt;
    thread.interrupt();&lt;br /&gt;
    for (int i = 1; i &amp;lt; 20; i++) {&lt;br /&gt;
      System.out.println(&amp;quot;It is in main &amp;quot; + i);&lt;br /&gt;
    }&lt;br /&gt;
    thread.interrupt();&lt;br /&gt;
    try {&lt;br /&gt;
      thread.join();&lt;br /&gt;
    } &lt;br /&gt;
    catch (InterruptedException ex) {&lt;br /&gt;
      System.out.println(&amp;quot;Exception in stop thread&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Отметим, что вызов метода wait() без блока синхронизации (synchronized), о котором мы поговорим чуть ниже, приводит к исключению IllegalMonitorStateException. Возникшая ошибка свидетельствует об отсутствии монитора у объекта (понятие монитора и синхронизация&lt;br /&gt;
тесно связаны, о чем мы тоже поговорим ниже). Если для приостановления потока был применен метод wait(), то для «пробуждения» потока&lt;br /&gt;
можно воспользоваться методом notify() или notifyAll(). Первый пробуждает один случайно выбранный спящий поток, а второй пытается&lt;br /&gt;
пробудить их всех.&lt;br /&gt;
&lt;br /&gt;
Кроме рассмотренных выше методов, иногда бывает целесообразно использовать метод yield(), который приостанавливает работу текущего потока. Метод yield() не переводит поток в режим ожидания, как wait(), но предоставляет другим потокам возможность начать работать&lt;br /&gt;
раньше, чем допустила бы Java-машина [фактически, поток, вызвавший yield() добровольно отдает свой квант процессорного времени, -&lt;br /&gt;
прим. ред.]. Метод yield() статичный, так что прекратить с его помощью работу другого потока не получится.&lt;br /&gt;
&lt;br /&gt;
Методов остановки потоков тоже нет (ранее присутствовали методы stop(), resume(), suspend(), но сейчас они объявлены как «deprecated» -&lt;br /&gt;
то есть нерекомендованными к использованию). На сегодня в Java принят уведомительный стиль остановки потока с помощью пары методов:&lt;br /&gt;
уже известного нам interrupt(), применяемого снаружи, чтобы выставить флаг завершения и метода isInterrupted(), вызываемого изнутри&lt;br /&gt;
потока, чтобы узнать состояние флага, свидетельствующего о том, что «пора закругляться».&lt;br /&gt;
&lt;br /&gt;
=== Мониторы и синхронизация ===&lt;br /&gt;
Что такое «монитор», о котором говорилось выше? Нет, это не дисплей, это — объект, используемый как защелка, то есть в данный момент&lt;br /&gt;
времени владеть монитором может только один поток. В случае, если поток завладел монитором, говорят, что он «вошел» в монитор, а все&lt;br /&gt;
остальные потоки, пытающиеся это сделать, будут заморожены (часто говорят, что они «ждут» монитора) до тех пор, пока владелец монитора&lt;br /&gt;
его не освободит, то есть не покинет.&lt;br /&gt;
&lt;br /&gt;
Если перейти к реалиям Java, то объектов типа монитор в явном виде просто нет! С каждым объектом связан неявный монитор, и чтобы&lt;br /&gt;
завладеть им, необходимо вызвать метод или блок, помеченный ключевым словом synchronized. Как только поток входит в такой блок, он&lt;br /&gt;
завладевает монитором объекта, переданного synchronized в качестве параметра. Так происходит и в классе ThirdThread, однако, в момент&lt;br /&gt;
вызова метода wait(), монитор отпускается. Пример synchronized-метода представлен ниже:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public synchronized boolean sameCheck() {&lt;br /&gt;
  if (a) {&lt;br /&gt;
    a = false; return true;&lt;br /&gt;
  } &lt;br /&gt;
  else {&lt;br /&gt;
    a = true; &lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В целом, синхронизация — это механизм, обеспечивающий монопольный доступ участка кода к некоторому объекту. Одним из первых&lt;br /&gt;
способов, предложенных для синхронизации работы потоков, были семафоры, концепцию которых описал Дейкстра [Dijkstra] в 1965 году&lt;br /&gt;
(часто говорят, что семафор — это классический синхронизированный примитив). Семафор используется для предоставления доступа к огра-&lt;br /&gt;
ниченному количеству ресурсов. Как правило, у семафора есть две операции: P — занять ресурс и V — освободить ресурс. Он может быть&lt;br /&gt;
реализован следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class SimpleSemaphore {&lt;br /&gt;
  int counter;&lt;br /&gt;
  public SimpleSemaphore() {&lt;br /&gt;
    this.counter = 1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public synchronized void p() throws InterruptedException {&lt;br /&gt;
    while (counter == 0) {&lt;br /&gt;
      wait();&lt;br /&gt;
    }&lt;br /&gt;
    counter = counter + 1;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public synchronized void v() throws InterruptedException {&lt;br /&gt;
    counter = counter - 1;&lt;br /&gt;
    notify();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Можно, конечно, реализовывать семафоры самостоятельно, но проще воспользоваться специальной библиотекой java.util.concurrent.&lt;br /&gt;
Кроме семафоров, она включает в себя еще много чего интересного.&lt;br /&gt;
&lt;br /&gt;
Отметим, что программа, в принципе, может не использовать ни один из методов синхронизации, обходясь методами wait() и notify().&lt;br /&gt;
&lt;br /&gt;
=== Взаимные блокировки ===&lt;br /&gt;
На этом наш рассказ можно было бы и завершить, но чтобы у вас не сложилось впечатление, что в мире многопоточных приложений все&lt;br /&gt;
так радужно, мы поговорим о неприятных последствиях синхронизации. Как только количество потоков начинает стремительно расти и&lt;br /&gt;
возникает необходимость синхронизированного доступа к ограниченному кругу объектов в различной последовательности, будьте готовы к&lt;br /&gt;
ошибкам типа deadlock — взаимным блокировкам.&lt;br /&gt;
&lt;br /&gt;
Взаимная блокировка — это ошибка, которая лучше всего описывается простой формулой: «Поток A держит монитор a и хочет захватить&lt;br /&gt;
монитор b, а поток B держит монитор b и хочет захватить монитор a». В результате оба засыпают «мертвым сном».&lt;br /&gt;
&lt;br /&gt;
Ошибка очень противная и возникает обычно в нетривиальных алгоритмах. Лечится взаимная блокировка грамотным проектированием и профилактическими мерами, вроде следующей: всегда захватывайте мониторы в одном и том же порядке.&lt;br /&gt;
&lt;br /&gt;
Сегодня мы поговорили о двух способах создания потоков Java, разобрались с приоритетами, познакомились со средствами управления работой потоков и демонами, а также сделали небольшой обзор методов синхронизации. Для того, чтобы начать практическую работу с потоками, этого вполне достаточно. Желающим разобраться во всем этом глубже я рекомендую ознакомится с книгой «Concurrent Programming in Java: Design Principles and Patterns», автором которой является Дуг Ли [Doug Lea] — она считается одной из лучших по данной тематике.&lt;br /&gt;
&lt;br /&gt;
На этом мы заканчиваем обзор основ программирования на Java и в [[LXF89:Java_EE|следующий раз]] поговорим о серверных приложениях — приготовьтесь&lt;br /&gt;
к Java Enterprise Edition!&lt;br /&gt;
&lt;br /&gt;
=== Литература ===&lt;br /&gt;
* 1. П. Кью «Использование UNIX», ISBN 5-8275-0019-4&lt;br /&gt;
* 2. В. Г. Олифер, Н. А. Олифер «Сетевые операционные системы», ISBN 5-272-00120-6&lt;br /&gt;
* 3. Д. Бэкон, Т. Харрис «Операционные системы», ISBN 5-94723-969-8&lt;br /&gt;
* 4. М. Фаулер «Архитектура корпоративных программных приложений», ISBN 5-8459-0579-6&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF86:Java</id>
		<title>LXF86:Java</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF86:Java"/>
				<updated>2008-03-19T07:03:42Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: ссылка в конце статьи на следующую статью&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java}}&lt;br /&gt;
&lt;br /&gt;
=== Хранение данных ===&lt;br /&gt;
''ЧАСТЬ 3: Даже самой замечательной программе надо откуда-то черпать данные для своей работы. Данные, как известно, хранятся в файлах. Тему продолжает '''Антон Черноусов'''.''&lt;br /&gt;
&lt;br /&gt;
В предыдущей статье из цикла, посвященного программированию на Java, были рассмотрены вопросы организации простых вычислений, ветвлений, циклов, а также генерации и обработки исключений.&lt;br /&gt;
&lt;br /&gt;
В течение третьего урока мы поговорим о работе с файлами, о протоколировании работы программы и коснемся методов работы с&lt;br /&gt;
XML-данными.&lt;br /&gt;
&lt;br /&gt;
=== Файлы — потоки ===&lt;br /&gt;
Сказочное королевство под руководством царевны Несмеяны (так как cупруг практически всегда отсутствовал), благодаря талантам и приобретенным навыкам, стало разрастаться, и результаты полюдья просто-напросто перестали помещаться в семейный чулан. Чтобы накапливать и хранить богатства, потребовались дополнительные помещения, роль которых для нас привычно играют файлы.&lt;br /&gt;
&lt;br /&gt;
Отношение к файлам в Java достаточно непростое: если рассматривать файл как устройство для ввода/вывода информации — с этой точ&lt;br /&gt;
ки зрения он подобен блоку памяти или экрану, интерфейс доступа к которому унифицирован: это поток. Но несмотря на унифицированный интерфейс, существует большое количество классов сходной функциональности, в которых легко запутаться.&lt;br /&gt;
&lt;br /&gt;
Поток можно представить в виде ленточного конвейера с последовательным размещением или извлечением данных, при использовании&lt;br /&gt;
которого задача программиста сводиться к осуществлению операций «поместить/читать» данные, а остальные детали реализации скрыты&lt;br /&gt;
от него.&lt;br /&gt;
&lt;br /&gt;
=== Чтение данных ===&lt;br /&gt;
Разнообразие классов для работы с файлами позволяет выбрать для себя ту связку, которая больше нравится. Лично я для чтения данных использую BufferedReader, InputStreamReader и FileInputStream. Собственно взаимодействие этих классов для программиста заканчивается в момент создания экземпляра BufferedReader, что делается следующим образом:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
BufferedReader br = null;&lt;br /&gt;
br = new BufferedReader(new InputStreamReader(new FileInputStream(pathToFile), encoding));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В процессе создания участвуют строковые переменные, содержащие путь к файлу и кодировку, в которой производится считывание&lt;br /&gt;
данных: pathToFile и encoding. В классах, работающих с файлами, считается обязательным создавать переменную для кодировки по умолчанию:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected static String DEFAULT_ENCODING = &amp;quot;UTF-8&amp;quot;;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Любой текстовый файл можно представить себе в виде набора строк, поэтому давайте реализуем метод для считывания содержимого&lt;br /&gt;
файла в массив String[]. Далее представлен метод rippedCurrentFile(path ToFile, encoding) класса FileRipper, который извлекает данные из файла с помощью метода readLine() экземпляра класса BufferedReader:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
protected boolean rippedCurrentFile(String pathToFile, String encoding) {&lt;br /&gt;
  // connecting to file&lt;br /&gt;
  BufferedReader br = null;&lt;br /&gt;
  try {&lt;br /&gt;
    br = new BufferedReader(new InputStreamReader(new FileInputStream(pathToFile),encoding));&lt;br /&gt;
  } &lt;br /&gt;
  catch (UnsupportedEncodingException e) {&lt;br /&gt;
    this.error = FILE_ERROR_UNSUPPORTED_ENCODING; return false;&lt;br /&gt;
  } &lt;br /&gt;
  catch (FileNotFoundException e) {&lt;br /&gt;
    this.error = FILE_ERROR_NO_FILE; return false;&lt;br /&gt;
  }&lt;br /&gt;
  // ripping the file&lt;br /&gt;
  String str = null;&lt;br /&gt;
  ArrayList allStrings = new ArrayList();&lt;br /&gt;
  try {&lt;br /&gt;
    while (!(str = br.readLine()).equals(null)) { allStrings.add(str); }&lt;br /&gt;
  } &lt;br /&gt;
  catch (IOException e) {&lt;br /&gt;
    this.error = FILE_ERROR_IO_READ; return false;&lt;br /&gt;
  } &lt;br /&gt;
  catch (NullPointerException e) {&lt;br /&gt;
    this.error = FILE_ERROR_END_OF_FILE;&lt;br /&gt;
  }&lt;br /&gt;
  // free the resources&lt;br /&gt;
  try {&lt;br /&gt;
    br.close();&lt;br /&gt;
  } &lt;br /&gt;
  catch (IOException e) {&lt;br /&gt;
    this.error = FILE_ERROR_IO_CLOSE; return false;&lt;br /&gt;
  }&lt;br /&gt;
  this.allStrings = (String[]) allStrings.toArray(new String[0]); &lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Полный код примера, в том числе код класса ConsoleToFileRipper, применяющий экземпляр класса FileRipper для извлечения данных из файла, можно найти на диске в каталоге '''examples 1'''.&lt;br /&gt;
&lt;br /&gt;
=== Запись данных ===&lt;br /&gt;
Процесс записи данных в файл хоть и отличается от чтения, но тоже достаточно похож на организацию конвейера. Для записи&lt;br /&gt;
я обычно использую связку BufferedWriter, OutputStreamWriter, FileOutputStream.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
BufferedWriter out;&lt;br /&gt;
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(pathToFile), encoding));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Для освобождения ресурсов, которые используют экземпляры классов BufferedReader и BufferedWriter, необходимо вызвать метод&lt;br /&gt;
close().&lt;br /&gt;
&lt;br /&gt;
Далее приведу простой пример метода, который записывает строковый массив в файл (полный код метода расположен на диске в&lt;br /&gt;
директории '''examples 2'''):&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public boolean createCurrentFile(String pathToFile, String[] allStrings, String encoding){&lt;br /&gt;
  try {&lt;br /&gt;
    BufferedWriter out;&lt;br /&gt;
    out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(pathToFile), encoding));&lt;br /&gt;
    for (int i = 0; i &amp;lt; allStrings.length; i++) {&lt;br /&gt;
      out.write(allStrings[i]); out.write(‘\n’);&lt;br /&gt;
    }&lt;br /&gt;
    out.close();&lt;br /&gt;
  } &lt;br /&gt;
  catch (IOException e) {&lt;br /&gt;
    e.printStackTrace(); &lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Свободный доступ ===&lt;br /&gt;
В представленных ранее примерах доступ к данным осуществляется последовательно, что не всегда удобно (хотя в большинстве случаев именно такой доступ и используется). Для осуществления чтения и записи данных из файла в произвольном порядке существует специальный класс RandomAccessFile, экземпляр которого создается следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
RandomAccessFile raf = new RandomAccessFile(pathToFile, mode);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
При этом pathToFile — путь до файла, а mode — режим работы. mode может принимать значения: r (только чтение), rw (чтение-запись), rws (чтение-запись с синхронным сохранением содержимого и метаданных), rwd (чтение-запись с синхронным сохранением содержимого файла). К сожалению, кодировку указать нельзя. Огромным преимуществом подхода является то, что с помощью метода getFilePointer() можно узнать текущее месторасположение указателя, а с помощью метода seek() можно передвинуть указатель в необходимое место в файле. Я предпочитаю не использовать данный класс — считайте это личным предубеждением.&lt;br /&gt;
&lt;br /&gt;
=== Протоколирование работы программы ===&lt;br /&gt;
Для контроля и анализа работы приложения существуют методы протоколирования. Популярным инструментом для этих целей в мире&lt;br /&gt;
Java является библиотека Log4j, которая разрабатывается в Apache Software Foundation. Текущую версию можно загрузить с [http://logging.apache.org/[http://logging.apache.org/]].&lt;br /&gt;
&lt;br /&gt;
Для использования библиотеки необходимо создать конфигурационный файл, который описывает, что, куда и как нужно протоколировать. Log4j имеет три базовые составляющие: logger, appender и layout.&lt;br /&gt;
&lt;br /&gt;
layout — это элементы, определяющие вид и содержание записей. Изначально имеется несколько заранее созданных layout-ов, а в случае необходимости можно создать свой собственный.&lt;br /&gt;
&lt;br /&gt;
Appender — это элемент, определяющий местоположение протокола, с его помощью задается тип протоколирования:&lt;br /&gt;
* файловое протоколирование (FileAppender);&lt;br /&gt;
* консольное протоколирование (ConsoleAppender);&lt;br /&gt;
* протоколирование в базы данных (JDBCAppender);&lt;br /&gt;
* протоколирование на SMTP-сервера (SMTPAppender) и др.&lt;br /&gt;
&lt;br /&gt;
Logger — это элемент, который обеспечивает протоколирование какого-либо события. Если обратиться к ранее приведенной аналогии&lt;br /&gt;
ленточного конвейера, logger — это и есть тот самый конвейер, вызывая методы которого, мы формируем протокол работы программы.&lt;br /&gt;
Элемент logger предусматривает следующие уровни протоколирования: DEBUG, INFO, WARN, ERROR, FATAL; уровням соответствуют методы класса org.apache.log4j.Logger: debug; info; warn; error; fatal.&lt;br /&gt;
&lt;br /&gt;
Ниже представлен пример записей для конфигурационного файла нашего приложения, которые нужно сохранить в файл с названием '''log.properties''' (название файла может быть любым).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
 log4j.logger.simple=DEBUG, nameLogAppender&lt;br /&gt;
 log4j.appender.nameLogAppender=org.apache.log4j.FileAppender&lt;br /&gt;
 log4j.appender.nameLogAppender.File=nameLogFile.log&lt;br /&gt;
 log4j.appender.nameLogAppender.layout=org.apache.log4j.SimpleLayout&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Первая строка указывает используемый уровень logger (DEBUG) и appender (nameLogAppender). Далее идут настройки appender: указание типа — FileAppender. В третьей строке указываем путь до файла журнала, а в последней — формат записи. Использовать экземпляр класса Logger можно примерно так (пример протоколирования приведен на диске в каталоге '''examples 3'''):&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
File propertiesFile = new File(&amp;quot;log.properties&amp;quot;);&lt;br /&gt;
PropertyConfigurator.configure(propertiesFile.toString());&lt;br /&gt;
Logger logger = Logger.getLogger(&amp;quot;simple&amp;quot;);&lt;br /&gt;
logger.info(&amp;quot;the program has started&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Документы XML ===&lt;br /&gt;
Проектируя и создавая ПО, невозможно не столкнутся с миром XML (Extensible Markup Language). XML был создан в недрах World Wide&lt;br /&gt;
Web Consortium (W3C) для преодоления ограничений языка HTML. Можно сказать, что HTML — один из самых успешных языков, область&lt;br /&gt;
его использования с каждым годом растет (в основном в объемах). Несмотря на это, почему же W3C создал XML, и зачем вам использовать этот язык? В чем ограниченность HTML? Ответ на эти вопросы один:XML был создан для обеспечения взаимодействия разнородных систем.&lt;br /&gt;
&lt;br /&gt;
HTML, как и любой другой текстовый язык, не позволяет перенести смысл тех данных, которые он хранит. XML был разработан для решения этой задачи с прицелом на Web, но получился таким удачным, что его стали использовать практически везде. Суть XML в том, что он хранит семантический смысл данных, поэтому выполнив анализ такого XML-документа, система может «понять» полученные данные. В Интернете существует большое количество информации, посвященной XML (например, [http://www.ibm.com/developerworks/xml/[www.ibm.com/developerworks/xml/]]), поэтому не будем подробно останавливаться на его преимуществах, а сразу приступим к использованию.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = &amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; ?&amp;gt;&lt;br /&gt;
&amp;lt;line name=&amp;quot;firstLine&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;point id=&amp;quot;1&amp;quot; theX=&amp;quot;1&amp;quot; theY=&amp;quot;1&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;point id=&amp;quot;2&amp;quot; theX=&amp;quot;2&amp;quot; theY=&amp;quot;2&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/line&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Выше приведен простой пример XML-документа, содержащего корневой элемент line, который, в свою очередь, содержит два узла с&lt;br /&gt;
тремя атрибутами (id, theX, theY) каждый.&lt;br /&gt;
&lt;br /&gt;
=== Создание XML-документа ===&lt;br /&gt;
Говоря про создание XML-документа, я подразумеваю создание дерева XML-документа в памяти системы, то есть объекта DOM (Document Object Model). DOM была создана W3C, и это — официальная Рекомендация консорциума. В противовес DOM существует SAX (Simple API for XML). С моделью SAX можно ознакомиться более подробно в&lt;br /&gt;
[http://www-128.ibm.com/developerworks/ru/views/xml/libraryview.jsp[http://www-128.ibm.com/developerworks/ru/views/xml/libraryview.jsp]]. Основная разница между методами заключается в том, что DOM обеспечивает виртуальное представление XML-файла в памяти системы, в то время как SAX — это событийная модель обработки, в которой в момент встречи определенного элемента вызывается соответствующее событие.&lt;br /&gt;
&lt;br /&gt;
Для создания «отображения» XML-файла в памяти системы необходимо воспользоваться классом Document, экземпляр которого можно получить следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();&lt;br /&gt;
DocumentBuilder db = dbf.newDocumentBuilder();&lt;br /&gt;
Document doc = db.newDocument();&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Создание корневого узла XML документа можно выполняется так:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
Element root = doc.createElement(&amp;quot;line&amp;quot;);&lt;br /&gt;
root.setAttribute(&amp;quot;name&amp;quot;, &amp;quot;firstLine&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
С помощью метода createElement(name) производится создание элементов, в то время как создание и установка значений атрибутов&lt;br /&gt;
элементов производится с помощью метода setAttribute(name, value), где name — имя атрибута, а value — его значение. С помощью метода appendChild можно добавить узел в элемент или произвести запись элемента в документ XML, например, так:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
root.appendChild(item);&lt;br /&gt;
doc.appendChild(root);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Более детально процесс создания XML документа на примере класса Line изложен в директории '''examples 4'''. При вызове метода&lt;br /&gt;
createDoc() этого класса создается экземпляр класса Document, идентичный приведенному ранее коду XML.&lt;br /&gt;
&lt;br /&gt;
=== Сохранение XML-документа ===&lt;br /&gt;
Для сохранения созданного в памяти документа предлагаю воспользоваться методом saveXML(docToSave, pathToFile, charSet). В процессе сохранения участвует уже знакомый нам OutputStreamWriter, а также экземпляр класса Transformer, который обеспечивает преобразование объекта DOMSource в выходной поток.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public void saveXML(Document docToSave, String pathToFile, String charSet) {&lt;br /&gt;
  try {&lt;br /&gt;
    Writer target = new OutputStreamWriter(new FileOutputStream(pathToFile), charSet);&lt;br /&gt;
    Source source = new DOMSource(docToSave);&lt;br /&gt;
    StreamResult dest = new StreamResult(target);&lt;br /&gt;
    Transformer t = TransformerFactory.newInstance().newTransformer();&lt;br /&gt;
    t.setOutputProperty(OutputKeys.ENCODING, charSet);&lt;br /&gt;
    t.setOutputProperty(OutputKeys.INDENT, &amp;quot;yes&amp;quot;);&lt;br /&gt;
    t.transform(source, dest);  &lt;br /&gt;
    target.flush();&lt;br /&gt;
    target.close();&lt;br /&gt;
  } &lt;br /&gt;
  catch (Exception ex) {&lt;br /&gt;
    ex.printStackTrace();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Реализация этого метода представлена на диске в директории '''examples 5'''.&lt;br /&gt;
&lt;br /&gt;
=== Загрузка XML-документа ===&lt;br /&gt;
Подобно сохранению XLM-документа, загрузка также достаточно просто выполняется с помощью экземпляра класса FileInputStream. Используя DocumentBuilderFactory, сгенерируем объект класса Document следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
FileInputStream fis = new FileInputStream(pathToFile);&lt;br /&gt;
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(fis);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Фактически, создание документа происходит вследствие выполнения метода parse. Для детально рассмотрения процесса загрузки&lt;br /&gt;
XML документа обратитесь к директории '''examples 6''', расположенной на диске.&lt;br /&gt;
&lt;br /&gt;
=== Извлечение данных из XML-документа ===&lt;br /&gt;
Итак, что же делать с Document? Работать, естественно! Прежде чем приступить к обработке XML-документа, хочу обратить внимание на одну неприятную особенность: почти всегда XML документ содержит пустые узлы или символы перевода каретки (неизбежное зло форматирования). К сожалению, такая особенность существенно затрудняет процесс обработки XML-документа. Поэтому следует всегда проводить нормализацию с помощью определенного в интерфейсе метода normalize(), или, если реализация Document не имеет такой возможности или нормализация выполняется некорректно — воспользуйтесь методом normalizeDocument класса FileXMLReader (вы найдете его все в той же директории '''examples 6'''). Вызвать данный метод можно следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
normalizeDocument(doc.getDocumentElement());&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Изложенный выше материал получился несколько другого формата, нежели предыдущие статьи. Статья содержит небольшие примеры&lt;br /&gt;
и отсылает на набор сознательно упрощенных готовых решений, благодаря которым вы сможете работать с файлами, производить прото-&lt;br /&gt;
колирование деятельности вашего приложения, начать работать с данными в формате XML. Цель приведенных примеров — обеспечить вас&lt;br /&gt;
необходимым минимумом информации и дать направление для поиска ответов на Ваши вопросы. В [[LXF88:Java|следующей статье]] мы расмотрим Потоки.&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF85:Java</id>
		<title>LXF85:Java</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF85:Java"/>
				<updated>2008-03-19T06:59:06Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: ссылка в конце статьи на следующую статью&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java}}&lt;br /&gt;
=== Считалочки ===&lt;br /&gt;
''ЧАСТЬ 2: Мало сыграть свадьбу — надо еще научиться вести семейный бюджет, выполнять одну и ту же работу каждый день и принимать судьбоносные решения. '''Антон Черноусов''' продолжает учить монархическую чету премудростям Java.''&lt;br /&gt;
&lt;br /&gt;
В предыдущей статье были рассмотрены основы объектно-ориентированного языка программирования Java: инкапсуляция,&lt;br /&gt;
наследование, полиморфизм. Мы создали простое приложение, в котором женили короля на царевне Несмеяне.&lt;br /&gt;
&lt;br /&gt;
Сегодня мы поговорим о простых типах (числах), о ветвлениях, циклах, а также об исключениях.&lt;br /&gt;
&lt;br /&gt;
=== Простые числа и их братья ===&lt;br /&gt;
Итак, мы оставили нашу царевну Несмеяну в семейном гнезде, где она в скором времени добралась до казны государства. Ей пришлось&lt;br /&gt;
освоить нехитрую математику — отнимать и делить: ведь казна требует строго учета, и никакая программа не обходится без вычислений. Без них невозможно создать даже самую простую систему учета и контроля, а мадам необходимо наладить нетривиальный учет бюджетных средств.&lt;br /&gt;
&lt;br /&gt;
Для реализации арифметических операций в Java существует семь арифметических операторов, которые работают с любыми числовыми типами: сложение +, вычитание -, умножение *, деление /, остаток %, унарный минус -val и унарный плюс +val, а также шесть примитивных типов переменных для выполнения арифметических операций:&lt;br /&gt;
{| border = &amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
 !Тип переменной&lt;br /&gt;
 !Разрядность&lt;br /&gt;
 !Описание&lt;br /&gt;
 |-&lt;br /&gt;
 |Byte||align=&amp;quot;center&amp;quot;|8||Целое со знаком&lt;br /&gt;
 |-&lt;br /&gt;
 |Short||align=&amp;quot;center&amp;quot;|16||Целое со знаком&lt;br /&gt;
 |-&lt;br /&gt;
 |Int||align=&amp;quot;center&amp;quot;|32||Целое со знаком&lt;br /&gt;
 |-&lt;br /&gt;
 |Long||align=&amp;quot;center&amp;quot;|64||Целое со знаком&lt;br /&gt;
 |-&lt;br /&gt;
 |Float||align=&amp;quot;center&amp;quot;|32||Число с плавающей точкой&lt;br /&gt;
 |-&lt;br /&gt;
 |Double||align=&amp;quot;center&amp;quot;|64||Число с плавающей точкой&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
Значение типов byte и short при выполнении вычислений переопределяется int, поэтому использование этих типов целесообразно для&lt;br /&gt;
хранения небольших значений для уменьшения объема используемой оперативной памяти.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
int iA = 10;&lt;br /&gt;
byte bB = 12;&lt;br /&gt;
int iC = iA + bB;&lt;br /&gt;
System.out.println(&amp;quot;Сумма А и B = &amp;quot; + iC);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Выше приведен пример выполнения арифметической операции с использованием переменных различных типов. Результат — целое число типа int. Для преобразования типа переменной, например, в тип с более низкой разрядностью, необходимо воспользоваться специальными языковыми конструкциями:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
double dD = 10.2;&lt;br /&gt;
double dE = 12.23;&lt;br /&gt;
float fF = (float) (dD + dE);&lt;br /&gt;
System.out.println(fF);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Логика и выбор ===&lt;br /&gt;
Чтобы провести ревизию налоговой службы правильно, Несмеяне пришлось разобраться с налоговым кодексом, а там без поллитра и знаний логических операций не обойтись.&lt;br /&gt;
&lt;br /&gt;
Для представления логических значений в Java присутствует простой тип boolean, который принимает значения true или false. Для проведения различных логических операций можно использовать ниже перечисленные операторы:&lt;br /&gt;
&lt;br /&gt;
{| border = &amp;quot;1&amp;quot; cellpadding=&amp;quot;2&amp;quot;&lt;br /&gt;
 !Тип операторов&lt;br /&gt;
 !Операторы&lt;br /&gt;
 |-&lt;br /&gt;
 |операторы отношений&lt;br /&gt;
 |align = &amp;quot;center&amp;quot;| &amp;lt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;gt; &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;gt;= &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; &amp;lt;= &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; instanceof&lt;br /&gt;
 |-&lt;br /&gt;
 |операторы равенства||align = &amp;quot;center&amp;quot;|== &amp;amp;nbsp;&amp;amp;nbsp;&amp;amp;nbsp; !=&lt;br /&gt;
 |-&lt;br /&gt;
 |поразрядное И||align = &amp;quot;center&amp;quot;|&amp;amp;&lt;br /&gt;
 |-&lt;br /&gt;
 |поразрядное исключающее ИЛИ||align = &amp;quot;center&amp;quot;|^&lt;br /&gt;
 |-&lt;br /&gt;
 |поразрядное включающее ИЛИ||align = &amp;quot;center&amp;quot;|&amp;amp;#448;&lt;br /&gt;
 |-&lt;br /&gt;
 |логическое И||align = &amp;quot;center&amp;quot;|&amp;amp;&amp;amp;&lt;br /&gt;
 |-&lt;br /&gt;
 |логическое ИЛИ||align = &amp;quot;center&amp;quot;|&amp;amp;#449;&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Пока Несмеяна разбирается в дебрях налогового кодекса, мы для иллюстрации работы с логическими выражениями обратимся к методу&lt;br /&gt;
primeNumberCheckUp(int numberForCheck), который выясняет, является ли переданное ему число простым.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
private boolean primeNumberCheckUp(int numberForCheck) {&lt;br /&gt;
  boolean result = true;&lt;br /&gt;
  if (numberForCheck != 1 || numberForCheck != 2 || numberForCheck != 3) {&lt;br /&gt;
    for (int currentNumber = 2; currentNumber &amp;lt; numberForCheck; currentNumber++) {&lt;br /&gt;
      if (numberForCheck % currentNumber == 0) {&lt;br /&gt;
        result = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В primeNumberCheckUp использованы две замечательные конструкции: оператор выбора по условию или условный оператор, и цикл.&lt;br /&gt;
Условный оператор if имеет следующий синтаксис:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
if (логическое выражение) {&lt;br /&gt;
           операторы группы 1;&lt;br /&gt;
}&lt;br /&gt;
else {&lt;br /&gt;
           операторы группы 2;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В вышеописанном методе использована упрощенная конструкция (без else), а для вычисления логического выражения использованы&lt;br /&gt;
операторы: != (не равно) и || (логическое «или»). В полной конструкции в случае истинности логического выражения выполняются операторы группы 1, иначе — группы 2.&lt;br /&gt;
&lt;br /&gt;
Вместо if для управления выполнением кода может быть использована специальная конструкция switch. В рамках этой конструкции&lt;br /&gt;
вычисляется целочисленное выражение, и в соответствии с полученным результатом ведется поиск соответствующего значения блока&lt;br /&gt;
case.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
int flag = 6;&lt;br /&gt;
switch (flag) {&lt;br /&gt;
  case 1: {&lt;br /&gt;
    System.out.println(&amp;quot;Царевна в спальне №1&amp;quot;);&lt;br /&gt;
    break;&lt;br /&gt;
  }&lt;br /&gt;
  case 5: {&lt;br /&gt;
    System.out.println(&amp;quot;Царевна в спальне №5&amp;quot;);&lt;br /&gt;
    break;&lt;br /&gt;
  }&lt;br /&gt;
  default: {&lt;br /&gt;
    System.out.println(&amp;quot;Кто тут знает, где царевна?&amp;quot;);&lt;br /&gt;
    break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Обратите внимание на оператор break, который обеспечивает немедленный выход из любого блока, а в примере выше прекращает дальнейшую обработку операторов конструкции switch, а также на блок операторов default — этот блок необязательный, он выполняется в случае, если выражение, удовлетворяющие условию, не было найдено среди case.&lt;br /&gt;
&lt;br /&gt;
=== Циклы ===&lt;br /&gt;
Разобравшись, как все устроено в королевстве, Несмеяна поняла, что все подчиняется принципу «Украл, выпил, в тюрьму» — точнее, во Дворец до следующего месяца. По кругу.&lt;br /&gt;
&lt;br /&gt;
Для реализации «кругового» процесса в Java существует три вида циклов: for, while и do-while. С циклом for мы уже вы встречались в методе primeNumberCheckUp, продемонстрированном ранее, синтаксис этой конструкции следующий:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
for (инициализация; логическое выражение; приращение) {&lt;br /&gt;
           операторы;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В рамках инициализации производится объявление и установка значений временных переменных. Цикл выполняется до тех пор, пока&lt;br /&gt;
логическое выражение истинно. На каждой итерации цикла производится приращение временных переменных.&lt;br /&gt;
&lt;br /&gt;
Две другие конструкции циклов можно назвать однояйцевыми близнецами, если бы не маленькое отличие в их использовании. При&lt;br /&gt;
использования цикла while проверка условия осуществляется до выполнения блока операторов, а в конструкции do-while — после него, то есть действия внутри цикла отрабатывают хотя бы раз. Например, процесс одиночной попойки короля от счастья, что он женат, на языке Java можно описать так:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
int i = 100;&lt;br /&gt;
while (i &amp;gt; 0) {&lt;br /&gt;
  System.out.println(i + &amp;quot; бутылок пива стояло на столе, одну уговорил&amp;quot;);&lt;br /&gt;
  i--;&lt;br /&gt;
}&lt;br /&gt;
System.out.println(&amp;quot;Все выпил, да!&amp;quot;);&lt;br /&gt;
int tankard = 1;&lt;br /&gt;
int allTankards = 10;&lt;br /&gt;
do {&lt;br /&gt;
  System.out.println(tankard + &amp;quot; стакан помыт&amp;quot;);&lt;br /&gt;
  tankard++;&lt;br /&gt;
}&lt;br /&gt;
while (tankard &amp;lt;= allTankards);&lt;br /&gt;
System.out.println(&amp;quot;Ну вот и все стаканы помыл&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Массивы ===&lt;br /&gt;
Для организации хранения однотипных данных в Java можно использовать массивы. Массивом называется структура данных, которая&lt;br /&gt;
позволяет хранить несколько значений в одной переменной (определение расплывчатое, но суть передает верно). Объявить массив можно несколькими способами, но я предпочитаю следующий как наиболее логичный:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
int[] arrayName = new int[length]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
При этом int — это тип переменных массива, а length — его размерность (число элементов). После того, как массив создан,&lt;br /&gt;
значения всех переменных равны null.&lt;br /&gt;
&lt;br /&gt;
Многомерный массив — это обыкновенный массив, элементами которого являются массивы, причем совсем не требуется, чтобы они&lt;br /&gt;
имели одинаковую размерность, например:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
int[][] arrayName = new int[2][];&lt;br /&gt;
arrayName[0] = new int[5];&lt;br /&gt;
arrayName[1] = new int[2];&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В некоторых задачах требуется создать массив, состоящий из произвольных чисел. Генерация произвольных чисел возможна благодаря&lt;br /&gt;
классу Random, который входит в пакет java.util. К слову, пакеты — это иерархически именованные контейнеры, применяемые для изолирования имен классов в некотором пространстве имен, то есть пакеты применяются во избежание конфликтов с именами классов.&lt;br /&gt;
&lt;br /&gt;
Подключение класса Random к программе происходит при использовании зарезервированного слова import и команды import java.util.Random; традиционно объявляемой в начале файла, содержащего разрабатываемый класс.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
import java.util.Random;&lt;br /&gt;
public class RandomGenerator {&lt;br /&gt;
  private static Random random = new Random();&lt;br /&gt;
  private int base;&lt;br /&gt;
  public RandomGenerator(int base) {&lt;br /&gt;
    this.base = base;&lt;br /&gt;
  };&lt;br /&gt;
  public RandomGenerator() {&lt;br /&gt;
    this.base = Math.abs(random.nextInt());&lt;br /&gt;
  };&lt;br /&gt;
  public int getInt(){&lt;br /&gt;
    return Math.abs(random.nextInt(this.base));&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Далее, приведенный код позволяет сгенерировать массив псевдослучайных чисел с использованием класса RandomGenerator, код&lt;br /&gt;
которого приведен выше:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
int[] newArray = new int[100];&lt;br /&gt;
RandomGenerator currentRG = new RandomGenerator(500);&lt;br /&gt;
for (int currentNumber = 0; currentNumber &amp;lt; 100; currentNumber++) {&lt;br /&gt;
  newArray[currentNumber] = currentRG.getInt();&lt;br /&gt;
  System.out.println(&amp;quot;newArray[&amp;quot; + currentNumber + &amp;quot;] = &amp;quot; + newArray[currentNumber]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Иногда невозможно установить точное количество элементов в массиве, в таком случае на помощь приходят динамические массивы ArrayList. ArrayList — это класс, который входит в Collection API. Объекты, созданные на основе ArrayList, более ресурсоемки. Давайте посмотрим на работу динамических массивов на примере задачи по поиску всех простых чисел в диапазоне от 1 до N:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
private Integer[] getAllPrimeNumbers (int numberForCheck){&lt;br /&gt;
  ArrayList primeNumbers = new ArrayList();&lt;br /&gt;
  for (int currentNumber = 1; currentNumber &amp;lt;= numberForCheck; currentNumber++) {&lt;br /&gt;
    if (this.primeNumberCheckUp(currentNumber)) {&lt;br /&gt;
      primeNumbers.add(currentNumber);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  Integer[] result = (Integer[]) primeNumbers.toArray(new Integer[0]);&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
public int[] getIntArray(){&lt;br /&gt;
  Integer[] arrayOfPrimeNumbers = (Integer[]) GetAllPrimeNumder(this.number);&lt;br /&gt;
    int[] result = new int[arrayOfPrimeNumbers.length];&lt;br /&gt;
    for (int currentNumber = 0; currentNumber&amp;lt;resault.length; currentNumber++){&lt;br /&gt;
      result[currentNumber] = arrayOfPrimeNumbers[currentNumber].intValue();&lt;br /&gt;
    }&lt;br /&gt;
    return resault;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
public Integer[] getIntegerArray(){&lt;br /&gt;
  return this.GetAllPrimeNumder(this.number);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В getAllPrimeNumder формируется динамический массив primeNumbers — объект класса ArrayList (для его использования необходимо подключить пакет java.util.ArrayList). Добавление нового объекта в динамический массив производится методом add(Object). После того, как динамический массив сформирован, из него извлекается простой массив методом toArray(Object[]). Обратите внимание, что из ArrayList извлекается массив объектов типа Integer, несмотря на то, что в него помещаются переменные типа int. Для получения массива состоящего из переменных типа int используется метод getIntArray().&lt;br /&gt;
&lt;br /&gt;
Динамические массивы, как правило, используют лишь до тех пор, пока не установлено точное количество элементов, так как скорость работы с простым массивом выше и обработка простого массива менее трудоемка.&lt;br /&gt;
&lt;br /&gt;
Для логического завершения работы с простыми числами включим ранее описанные методы (primeNumberCheckUp, getAllPrimeNumder,&lt;br /&gt;
getIntArray(), getIntegerArray()) в представленный далее класс ArrayOfPrimeNumbers.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
import java.util.ArrayList;&lt;br /&gt;
public class ArrayOfPrimeNumbers {&lt;br /&gt;
  private int number;&lt;br /&gt;
&lt;br /&gt;
  public ArrayOfPrimeNumber(int number) {&lt;br /&gt;
    this.number = number;&lt;br /&gt;
  }&lt;br /&gt;
  public int getNumber() {&lt;br /&gt;
    return number;&lt;br /&gt;
  }&lt;br /&gt;
  public void setNumber(int number) {&lt;br /&gt;
    this.number = number;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Класс, в зависимости от вызываемого метода, возвращает массив, состоящий из элементов int или Integer.&lt;br /&gt;
&lt;br /&gt;
=== Куча хлама ===&lt;br /&gt;
Вернемся к нашей Несмеяне. Так как королевство ей досталось, прямо скажем, маленькое, пришлось ей еще и за порядком следить, что значит знать, где и что. Здесь ей помог HashMap — такая интересная структура для хранения данных, класс который входит в '''java.util.''' Экземпляры класса HashMap позволяют хранить различные именованные объекты, которые хранятся в виде пар «ключ — значение». Снаружи объекта типа HashMap нельзя узнать (как в хорошем бардаке), что же там лежит, однако, зная ключ, можно получить то, что ищешь, ну а если ключ неизвестен, то необходимо начать разбирать бардак до тех пор, пока не будет найдено то, что требуется. HashMap часто используется для хранения параметров системы. Как царевна разбирала бардак&lt;br /&gt;
мужа с помощью HashMap, можно посмотреть ниже.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
HashMap sameHeap = new HashMap();&lt;br /&gt;
sameHeap.put(&amp;quot;Key1&amp;quot;, &amp;quot;Левый носок&amp;quot;);&lt;br /&gt;
sameHeap.put(&amp;quot;Key2&amp;quot;, &amp;quot;Грязная футболка&amp;quot;);&lt;br /&gt;
sameHeap.put(&amp;quot;Key3&amp;quot;, &amp;quot;Правый носок&amp;quot;);&lt;br /&gt;
String sameObj = (String) sameHeap.get(&amp;quot;Key1&amp;quot;);&lt;br /&gt;
System.out.println(&amp;quot;Key1 = &amp;quot; + sameObj);&lt;br /&gt;
Map.Entry entry = null;&lt;br /&gt;
Iterator it = sameHeap.entrySet().iterator();&lt;br /&gt;
while (it.hasNext()) {&lt;br /&gt;
  entry = (Map.Entry) it.next();&lt;br /&gt;
  System.out.println(&amp;quot;For key = &amp;quot; + entry.getKey() + &amp;quot; value = &amp;quot; + entry.getValue());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Для компиляции понадобится подключить java.util.HashMap, java.util.Iterator, java.util.Map — это можно сделать с помощью всего одной строкой вместо трех — import java.util.*;.&lt;br /&gt;
&lt;br /&gt;
Как вы можете убедиться, для помещения объекта в HashMap необходимо использовать метод put, где первым параметром будет ключ, а&lt;br /&gt;
вторым — ассоциируемый с ним объект. Извлечение объекта возможно с помощью метода get при передаче ключа или с помощью последовательного перебора записей в HashMap.&lt;br /&gt;
&lt;br /&gt;
После выполнения кода вы можете увидеть, что элементы в куче лежат не в том порядке, в котором вы их туда кинули (как в жизни, и не только короля). Порядок элементов в коллекции также может меняться во времени. HashMap обеспечивает постоянное время доступа для операций put и get. Как для ключей, так и для элементов допускаются значения типа null.&lt;br /&gt;
&lt;br /&gt;
=== Пятый угол ===&lt;br /&gt;
В хорошо написанной программе, как и в сказочном королевстве, все должно идти своим чередом, но непредвиденные ситуации все равно бывают, так как программа соприкасается с внешним миром (другими программами, файлами, пользователями). Для решения непредвиденных ситуаций в Java существуют исключения и специальные операторы позволяющие отловить и обработать их.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
try{&lt;br /&gt;
  // небезопасный код&lt;br /&gt;
} catch(Exception e) {&lt;br /&gt;
  // обработка исключительной ситуации&lt;br /&gt;
} finally {&lt;br /&gt;
  // гарантированно выполняющийся блок&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Выше представлена структура, с помощью которой производится обработка исключительных ситуаций: в блоке try производятся&lt;br /&gt;
потенциально опасные операции, а в блоке catch производится обработка возникшего исключения (блоков catch может быть несколько). Под блоком подразумевается последовательность операторов, объявлений локальных классов или локальных переменных, заключенных в фигурные скобки. Область видимости локальных переменных и классов ограничена блоком, в котором они определены.&lt;br /&gt;
&lt;br /&gt;
Иногда дополнительно, вне зависимости от того, как будет выполнен блок try, необходимо, чтобы выполнились какие-либо действия&lt;br /&gt;
(например, освобождение ресурсов), тогда используют оператор finally, который обеспечивает гарантированное выполнение указанного блока операторов.&lt;br /&gt;
&lt;br /&gt;
Исключительная ситуация может быть сгенерирована виртуальной машиной Java, а также программистом. Исключение «выбрасывается»&lt;br /&gt;
с помощью оператора throw.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public float calculate(int sameA, int sameB) throws Exception {&lt;br /&gt;
  float result;&lt;br /&gt;
  if (sameB != 0) {&lt;br /&gt;
    result = sameA / sameB;&lt;br /&gt;
  } else&lt;br /&gt;
    throw new Exception(&amp;quot;Параметр для вычисления не должен быть равным нулю&amp;quot;);&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Предложенный метод обеспечивает деление, а так как Царевна и король никогда не делят на ноль, они все делят поровну, то с помощью оператора throw порождается исключение в случае неправильно введенных данных. Это исключение можно «отловить» с помощью catch по месту использования метода.&lt;br /&gt;
&lt;br /&gt;
Жизнь царевны и короля изменилась: пришлось осваивать азы науки и знакомиться с простыми типами (чисел), разбираться в ветвлениях налогового кодекса, использовать все три типа циклов, а также усвоить исключения. Оставим их осмыслять все это до [[LXF86:Java|следующего номера…]]&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF84:Java</id>
		<title>LXF84:Java</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF84:Java"/>
				<updated>2008-03-19T06:53:06Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java}}&lt;br /&gt;
=== Сказка Java ===&lt;br /&gt;
''ЧАСТЬ 1: От кофеварок до промышленных серверов и биллинговых систем - Java можно встретить буквально везде. Начните изучение этой технологии вместе с '''Антоном Черноусовым'''.''&lt;br /&gt;
&lt;br /&gt;
Начиная ряд статей о программировании на объектно-ориентированном языке Java, хотел бы выразить свое мнение относительно корпоративного рынка разработки программного обеспечения, на котором в данный момент борются за лидерство два гиганта, две платформы: J2EE и .NET.&lt;br /&gt;
&lt;br /&gt;
В основе платформы J2EE лежит язык программирования Java – приложения, созданные с его помощью, являются кроссплатформенными, сам язык, средства разработки и технология активно поддерживаются многими корпорациями: Sun, Google, IBM, Oracle, BEA. Платформа пользуется большой популярностью и среди компаний, ориентированных на OpenSource, таких как Apache Foundation. В противовес J2EE, корпорация Microsoft предлагает свою технологию .NET, которая является колоссом, построенным на мощи программного обеспечения Microsoft.&lt;br /&gt;
&lt;br /&gt;
Сегодня еще нельзя сказать, какая технология станет доминирующей, и, возможно, от вас зависит скорость распространения современной кроссплатформенной технологии создания приложений J2EE и языка программирования Java.&lt;br /&gt;
&lt;br /&gt;
Предложенные вашему вниманию уроки позволят овладеть основными понятиями Java и создавать различные приложения с его помощью. Рассмотрев основы языка, мы сможем изучить типовые решения (паттерны) в программировании и приступить к изучению J2EE.&lt;br /&gt;
В первом уроке мы создадим свое первое приложение и разберемся с основными понятиями: инкапсуляция, наследование и полиморфизм. Для выполнения этого урока нам понадобится пакет Java SDK 1.5, текстовый редактор и немного терпения.&lt;br /&gt;
=== Героический объект ===&lt;br /&gt;
Приступая к этой серии материалов, я вспомнил, что, как правило, изучение языков программирования начинается с написания приложения &amp;quot;Hello World!&amp;quot;, но такой прием настолько изъезжен, что я намереваюсь предложить пример поинтереснее: мы напишем приложение, рассказывающее сказку. Основа приложения – два класса. Каждый класс содержит члены двух видов: атрибуты и методы. Атрибуты – это данные, принадлежащие самому классу. Совокупное значение атрибутов определяет состояние объекта или класса. Метод – это последовательность операторов, изменяющих значения атрибутов и, как следствие, состояние класса или объекта.&lt;br /&gt;
&lt;br /&gt;
В каждой интересной сказке должен быть свой герой. Предлагаю взглянуть на класс, который реализует нашего героя. Итак, по порядку. Следующий код необходимо сохранить в файл '''FirstHero.java.'''&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class FirstHero {&lt;br /&gt;
  private String quest;&lt;br /&gt;
  public FirstHero(String Quest) {&lt;br /&gt;
    this.quest = Quest;&lt;br /&gt;
  }&lt;br /&gt;
  public void setQuest(String Quest){&lt;br /&gt;
    this.quest = Quest;&lt;br /&gt;
  };&lt;br /&gt;
  public String getQuest(){&lt;br /&gt;
    return quest;&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Расположение одного класса в одном файле считается хорошим тоном среди программистов на Java – так что приучайтесь к нему сразу. Имя файла должно совпадать с названием класса, расширение у файла – '''.java.'''&lt;br /&gt;
&lt;br /&gt;
Первый созданный нами класс содержит один защищенный атрибут (private – модификатор, зарезервированное слово, которое обеспечивает возможность обращения к члену класса только внутри класса) и три открытых метода (public – модификатор, зарезервированное слово, которое обеспечивает возможность обращения к члену класса из любого другого класса.). Хорошо спроектированный класс не имеет открытых атрибутов, что позволяет быть уверенным в правильной работе с ними. Доступ к защищенным атрибутам осуществляется через открытые методы. Такая организация класса позволяет разработчику через методы реализовать различные проверки и исключить неправильное поведение объекта. Класс представляет собой объединение атрибутов и методов в единое целое – подобное объединение называется инкапсуляцией.&lt;br /&gt;
&lt;br /&gt;
Вы можете заметить, что первый метод (третья строка представленного ранее листинга) имеет то же название, что и класс – FirstHero. Такой метод называется конструктором. Конструктор – это метод, который используется при создании экземпляра класса для задания внутреннего состояния объекта, например:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
FirstHero ourNewHero = new FirstHero(&amp;quot;Спасти царевну&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Единственный атрибут нашего класса quest имеет тип строка (String). Для установки значения атрибута quest используется метод&lt;br /&gt;
setQuest. Метод setQuest является public и не возвращает никакого значения. Для обозначения методов, не возвращающих значение, используется зарезервированное слово void. Для вызова метода setQuest необходим обязательный параметр: Quest типа String. Для получения значения атрибута quest используется метод getQuest, который вызывается без параметров, является открытым и возвращает значение типа String.&lt;br /&gt;
&lt;br /&gt;
Вызов описанных выше методов для объекта ourNewHero осуществляется следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
ourNewHero.getQuest();&lt;br /&gt;
ourNewHero.setQuest(&amp;quot;какая-то строка&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Парные методы, различающиеся приставками set и get, принято создавать для работы с закрытыми атрибутами. Это обязательное&lt;br /&gt;
условие для реализации объекта в виде JavaBean. Что такое JavaBean, мы обсудим позже – сейчас запомните, что такое наименование методов позволяет избавиться от ряда проблем в больших системах.&lt;br /&gt;
&lt;br /&gt;
Приступим к написанию самой сказки. Возьмите следующий код и поместите его в файл '''Story.java'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class Story {&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    FirstHero ourNewHero = new FirstHero(&amp;quot;Спасти царевну &amp;quot;);&lt;br /&gt;
    System.out.println(“Наш герой хочет отправиться в путь и “ + ourNewHero.getQuest());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это класс Story, он имеет всего один метод main, который является статичным (static-методы и переменные принято называть переменными класса и методами класса, т.к. они общие для всех объектов) и используется для работы с классом в целом. Метод main – это стартовая точка для запуска программы, с которой начинается интерпретация кода.&lt;br /&gt;
&lt;br /&gt;
В ходе интерпретации метода main создается новый объект ourNewHero, а также вызывается метод println объекта out, который обеспечивает вывод в стандартный выходной поток строковойпеременной.&lt;br /&gt;
&lt;br /&gt;
Откомпилируем код и увидим, что у нас получилось. Для компиляции переместитесь в каталог, где вы разместили свои файлы и выполните следующую команду:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
# javac *.java&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
При желании вы можете откомпилировать классы по отдельности, следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
# javac Story.java&lt;br /&gt;
# javac FirstHero.java&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В итоге вы получите два файла '''Story.class''' и '''FirstHero.class'''. Теперь посмотрим на результат:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
# java Story&lt;br /&gt;
Наш герой хочет отправиться в квест и Спасти царевну&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Первая программа на Java готова и работает! Вы создали два класса и научились выводить информацию в консоль. Но мы забыли о&lt;br /&gt;
комментариях...&lt;br /&gt;
&lt;br /&gt;
Комментарии бывают нескольких типов:&lt;br /&gt;
*Строчные начинаются с символа // и длятся до окончания строки.&lt;br /&gt;
*Многострочные комментарии заключаются между /* и */.&lt;br /&gt;
*Комментарии JavaDoc – это многострочные комментарии, заключенные между /** и */, например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Класс является прототипом объекта &amp;quot;герой&amp;quot;&lt;br /&gt;
 * @author Chernousov Anton&lt;br /&gt;
 * @version 0.1&lt;br /&gt;
 */&lt;br /&gt;
public class FirstHero {&lt;br /&gt;
…&lt;br /&gt;
/**&lt;br /&gt;
   * Метод предназначен для установки внутренней переменной&lt;br /&gt;
quest&lt;br /&gt;
   * в значение Quest.&lt;br /&gt;
   * У этого метода один параметр&lt;br /&gt;
   * @param Quest это переменная означает задание для Героя&lt;br /&gt;
   */&lt;br /&gt;
  public void setQuest(String Quest)&lt;br /&gt;
…&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Комментарии JavaDoc предназначены для формирования документации к проекту из исходных кодов. Если добавить в файл '''FirstHero.java''' только что приведенные строки, то с помощью команды '''javadoc -author -version *.java''' можно сформировать документацию к нашему проекту.&lt;br /&gt;
&lt;br /&gt;
JavaDoc позволяет создавать подробную документацию, которая просто необходима для любого достаточно крупного проекта.&lt;br /&gt;
=== Наследование, интерфейсы и их реализация ===&lt;br /&gt;
Наша сказка написана, но что делать, если проект большой и над ним работает много людей? Как реализовать одновременное программирование разных классов так, чтобы результаты, полученные отдельными разработчиками, можно было без труда соединить в единое целое? Для решения этой задачи, а также задачи множественного наследования в Java существуют интерфейсы – interface. Но обо всем по порядку.&lt;br /&gt;
&lt;br /&gt;
Наследование – это одна из парадигм программирования, которая связана с инкапсуляцией. Суть наследования заключается в следующем: если есть класс, инкапсулирующий в себе некоторые атрибуты и методы, то класс, наследующий его, автоматически наследует все его атрибуты и методы.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class SecondHero extends FirstHero{&lt;br /&gt;
  public SecondHero(String Quest) {&lt;br /&gt;
    super(Quest + &amp;quot; Несмеяну&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Расположенный выше код объявляет класс SecondHero, который с помощью зарезервированного слова extends наследует (расширяет) класс FirstHero. В Java класс может наследовать (расширять)только один класс. При наследовании класса FirstHero, содержащего&lt;br /&gt;
конструктор, обязательно требуется переопределить его (например, как это делается в методе SecondHero). При выполнении оператора super(Quest) будет вызван аналогичный метод из суперкласса (класс-родителя). Строкой super(Quest + “Несмеяну”) мы переопределяем поведение конструктора. Естественно, класс SecondHero может содержать новые атрибуты и методы.&lt;br /&gt;
&lt;br /&gt;
Для проверки механизма наследования сохраните приведенный текст класса SecondHero в файл '''SecondHero.java''' и в файле '''Story.java''' измените имя класса FirstHero на SecondHero. Откомпилируйте и запустите программу, в результате вы должны увидеть следующее:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
# java Story&lt;br /&gt;
Наш герой хочет отправиться в путь и Спасти царевну Несмеяну&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
При разработке программы, перед тем, как приступить к программированию, сначала проводится процесс проектирования (например, через UML-нотации). В результате проектирования появляется документация к проекту, а также спецификации классов. Интерфейс – это явно указанная спецификация набора методов, которые должны быть представлены в классе, реализующий эту спецификацию. В серьезном проекте на момент начала программирования перед программистом оказываются интерфейсы, которые он должен реализовать в классах.&lt;br /&gt;
&lt;br /&gt;
Интерфейс в Java – это специальный класс, в котором отсутствует реализация! Давайте напишем интерфейс для нашего класса FirstHero. Следует скопировать следующий далее код и поместить его в файл '''Hero.java''' – именно этот интерфейс мы будет использован далее. Как вы видите, в отличие от других классов, интерфейс объявляется с помощью зарезервированного слова interface. В нашем случае интерфейс представляет собой следующий набор методов:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public interface Hero {&lt;br /&gt;
  public void setQuest(String Quest);&lt;br /&gt;
  public String getQuest();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Чтобы класс FirstHero реализовывал интерфейс Hero, необходимо изменить первую строчку в файле '''FirstHero.java''' на public class FirstHero implements Hero {. Интерфейс может наследовать (расширять) множество других интерфейсов. Наример:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public interface Lord {&lt;br /&gt;
  public String sendToQuest();&lt;br /&gt;
  public void setBodyguard(Hero hisHero);&lt;br /&gt;
  public Hero getBodyguard();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
public interface King extends Hero, Lord{&lt;br /&gt;
  public void setWife (String PrincesName);&lt;br /&gt;
  public String getWife();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Класс может одновременно наследовать класс и реализовывать один или несколько интерфейсов. Например, как в классе LandLord,&lt;br /&gt;
который наследует класс FirstHero и реализует интерфейс Lord:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LandLord extends FirstHero implements Lord{&lt;br /&gt;
  private Hero bodyguard;&lt;br /&gt;
  public LandLord(String Quest, Hero hisHero) {&lt;br /&gt;
    super(Quest);&lt;br /&gt;
    this.bodyguard = hisHero;&lt;br /&gt;
  }&lt;br /&gt;
  public String sendToQuest() {&lt;br /&gt;
    bodyguard.setQuest(this.getQuest());&lt;br /&gt;
    return null;&lt;br /&gt;
  }&lt;br /&gt;
  public void setBodyguard(Hero hisHero) {&lt;br /&gt;
    this.bodyguard = hisHero;&lt;br /&gt;
  }&lt;br /&gt;
  public Hero getBodyguard() {&lt;br /&gt;
    return bodyguard;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Чтобы окончательно закрыть тему наследования, необходимо поговорить про абстрактные классы – те, что занимают промежуточное&lt;br /&gt;
место между интерфейсами и реальными классами. Объявление абстрактного класса или метода выполняется с помощью специального&lt;br /&gt;
слова abstract:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
abstract public class Knight&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Абстрактный класс представляет собой неполную реализацию всех объявленных методов, и его можно наследовать, как и любой из классов. Обязательным условием при наследовании является полная реализация абстрактных методов.&lt;br /&gt;
&lt;br /&gt;
=== Полиморфизм ===&lt;br /&gt;
Полиморфизм – это концепция, реализованная в Java, которая позволяет одному и тому же объекту выступать в разных формах. Например, экземпляр класс LandLord можно использовать как объект класса FirstHero. Это стало возможным благодаря тому, что класс LandLord наследует класса FirstHero.&lt;br /&gt;
&lt;br /&gt;
=== Перегруженные методы ===&lt;br /&gt;
Иногда при создании сложных (и не очень) систем есть необходимость реализовать два различных метода, названых одинаково – это возможно с помощью перегруженных (overloading) методов. Выбор реализации зависит от типа объектов, переданных в качестве параметров.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class GreatKing extends LandLord implements King{&lt;br /&gt;
  private String wife;&lt;br /&gt;
  private boolean theftedWife;&lt;br /&gt;
&lt;br /&gt;
  public GreatKing(String Quest, Hero hisHero) {&lt;br /&gt;
    super(Quest, hisHero);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void setWife(String PrincesName) {&lt;br /&gt;
    this.wife = PrincesName;&lt;br /&gt;
    this.theftedWife = false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String getWife() {&lt;br /&gt;
    if (theftedWife){return null;}&lt;br /&gt;
    else{ return wife;}&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String getWife(boolean flag) {&lt;br /&gt;
    if (flag){ this.theftedWife = true;}&lt;br /&gt;
    return wife;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В представленном классе GreatKing существуют две реализации перезагруженного метода getWife, которые можно вызвать следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
GreatKing ourKing = new GreatKing(&amp;quot;Править мудро&amp;quot;, (Hero) new FirstHero(&amp;quot;Охранять господина&amp;quot;));&lt;br /&gt;
String hisWife = ourKing.getWife();&lt;br /&gt;
String theftedHisWife = ourKing.getWife(true);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вместо заключения ===&lt;br /&gt;
Ну вот, мы создали всех героев. Разместите интерфейсы Lord, King, а также классы LandLord и GreatKing в соответствующих файлах.&lt;br /&gt;
Немного измените класс Story, чтобы завершить сказку:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class Story {&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    // создадим наших героев&lt;br /&gt;
    Hero ourNewHero = (Hero) new FirstHero(&amp;quot;Спасити царевну&amp;quot;);&lt;br /&gt;
    GreatKing ourKing = new GreatKing(&amp;quot;Править мудро&amp;quot;, (Hero) new FirstHero(&amp;quot;Охранять господина&amp;quot;));&lt;br /&gt;
    LandLord ourNewLandLord = new LandLord(&amp;quot;Похитить царевну&amp;quot;, (Hero) new FirstHero(&amp;quot;Охранять господина&amp;quot;));&lt;br /&gt;
    // Женим нашего короля&lt;br /&gt;
    ourKing.setWife(&amp;quot;Несмеяна&amp;quot;);&lt;br /&gt;
    // И начнем повествование&lt;br /&gt;
    System.out.println(&amp;quot;Жил был мудрый король, и должен был он &amp;quot; + ourKing.getQuest());&lt;br /&gt;
    System.out.println(&amp;quot;Была у него жена, и звали ее &amp;quot; + ourKing.getWife());&lt;br /&gt;
    System.out.println(&amp;quot;Был в королевстве коварный Визирь и хотел он &amp;quot; + ourNewLandLord.getQuest());&lt;br /&gt;
    System.out.println(&amp;quot;И сделал это&amp;quot;);&lt;br /&gt;
    String wife = ourKing.getWife(true);&lt;br /&gt;
    //&lt;br /&gt;
    System.out.println(&amp;quot;А наш герой жаждал &amp;quot; + ourNewHero.getQuest() + &amp;quot; ..и добился этого&amp;quot;);&lt;br /&gt;
    ourKing.setWife(wife);&lt;br /&gt;
    System.out.println(&amp;quot;Король был счастлив.&amp;quot;);&lt;br /&gt;
    System.out.println(&amp;quot;Ну а что случилось дальше вы можете придумать сами...&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Откомпилируйте и насладитесь результатом выполнения урока.&lt;br /&gt;
&lt;br /&gt;
В [[LXF85:Java|следующей статье]] мы поговорим о простых числах и других типах, вычислениях, циклах, массивах и списках.&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	<entry>
		<id>http://wiki.linuxformat.ru/wiki/LXF84:Java</id>
		<title>LXF84:Java</title>
		<link rel="alternate" type="text/html" href="http://wiki.linuxformat.ru/wiki/LXF84:Java"/>
				<updated>2008-03-19T06:37:19Z</updated>
		
		<summary type="html">&lt;p&gt;Maximax: Что за &amp;quot;ООЯ &amp;quot; ? Я непонял. Поэтому я её убрал.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Цикл/Java}}&lt;br /&gt;
=== Сказка Java ===&lt;br /&gt;
''ЧАСТЬ 1: От кофеварок до промышленных серверов и биллинговых систем - Java можно встретить буквально везде. Начните изучение этой технологии вместе с '''Антоном Черноусовым'''.''&lt;br /&gt;
&lt;br /&gt;
Начиная ряд статей о программировании на объектно-ориентированном языке Java, хотел бы выразить свое мнение относительно корпоративного рынка разработки программного обеспечения, на котором в данный момент борются за лидерство два гиганта, две платформы: J2EE и .NET.&lt;br /&gt;
&lt;br /&gt;
В основе платформы J2EE лежит язык программирования Java – приложения, созданные с его помощью, являются кроссплатформенными, сам язык, средства разработки и технология активно поддерживаются многими корпорациями: Sun, Google, IBM, Oracle, BEA. Платформа пользуется большой популярностью и среди компаний, ориентированных на OpenSource, таких как Apache Foundation. В противовес J2EE, корпорация Microsoft предлагает свою технологию .NET, которая является колоссом, построенным на мощи программного обеспечения Microsoft.&lt;br /&gt;
&lt;br /&gt;
Сегодня еще нельзя сказать, какая технология станет доминирующей, и, возможно, от вас зависит скорость распространения современной кроссплатформенной технологии создания приложений J2EE и языка программирования Java.&lt;br /&gt;
&lt;br /&gt;
Предложенные вашему вниманию уроки позволят овладеть основными понятиями Java и создавать различные приложения с его помощью. Рассмотрев основы языка, мы сможем изучить типовые решения (паттерны) в программировании и приступить к изучению J2EE.&lt;br /&gt;
В первом уроке мы создадим свое первое приложение и разберемся с основными понятиями: инкапсуляция, наследование и полиморфизм. Для выполнения этого урока нам понадобится пакет Java SDK 1.5, текстовый редактор и немного терпения.&lt;br /&gt;
=== Героический объект ===&lt;br /&gt;
Приступая к этой серии материалов, я вспомнил, что, как правило, изучение языков программирования начинается с написания приложения &amp;quot;Hello World!&amp;quot;, но такой прием настолько изъезжен, что я намереваюсь предложить пример поинтереснее: мы напишем приложение, рассказывающее сказку. Основа приложения – два класса. Каждый класс содержит члены двух видов: атрибуты и методы. Атрибуты – это данные, принадлежащие самому классу. Совокупное значение атрибутов определяет состояние объекта или класса. Метод – это последовательность операторов, изменяющих значения атрибутов и, как следствие, состояние класса или объекта.&lt;br /&gt;
&lt;br /&gt;
В каждой интересной сказке должен быть свой герой. Предлагаю взглянуть на класс, который реализует нашего героя. Итак, по порядку. Следующий код необходимо сохранить в файл '''FirstHero.java.'''&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class FirstHero {&lt;br /&gt;
  private String quest;&lt;br /&gt;
  public FirstHero(String Quest) {&lt;br /&gt;
    this.quest = Quest;&lt;br /&gt;
  }&lt;br /&gt;
  public void setQuest(String Quest){&lt;br /&gt;
    this.quest = Quest;&lt;br /&gt;
  };&lt;br /&gt;
  public String getQuest(){&lt;br /&gt;
    return quest;&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Расположение одного класса в одном файле считается хорошим тоном среди программистов на Java – так что приучайтесь к нему сразу. Имя файла должно совпадать с названием класса, расширение у файла – '''.java.'''&lt;br /&gt;
&lt;br /&gt;
Первый созданный нами класс содержит один защищенный атрибут (private – модификатор, зарезервированное слово, которое обеспечивает возможность обращения к члену класса только внутри класса) и три открытых метода (public – модификатор, зарезервированное слово, которое обеспечивает возможность обращения к члену класса из любого другого класса.). Хорошо спроектированный класс не имеет открытых атрибутов, что позволяет быть уверенным в правильной работе с ними. Доступ к защищенным атрибутам осуществляется через открытые методы. Такая организация класса позволяет разработчику через методы реализовать различные проверки и исключить неправильное поведение объекта. Класс представляет собой объединение атрибутов и методов в единое целое – подобное объединение называется инкапсуляцией.&lt;br /&gt;
&lt;br /&gt;
Вы можете заметить, что первый метод (третья строка представленного ранее листинга) имеет то же название, что и класс – FirstHero. Такой метод называется конструктором. Конструктор – это метод, который используется при создании экземпляра класса для задания внутреннего состояния объекта, например:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
FirstHero ourNewHero = new FirstHero(&amp;quot;Спасти царевну&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Единственный атрибут нашего класса quest имеет тип строка (String). Для установки значения атрибута quest используется метод&lt;br /&gt;
setQuest. Метод setQuest является public и не возвращает никакого значения. Для обозначения методов, не возвращающих значение, используется зарезервированное слово void. Для вызова метода setQuest необходим обязательный параметр: Quest типа String. Для получения значения атрибута quest используется метод getQuest, который вызывается без параметров, является открытым и возвращает значение типа String.&lt;br /&gt;
&lt;br /&gt;
Вызов описанных выше методов для объекта ourNewHero осуществляется следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
ourNewHero.getQuest();&lt;br /&gt;
ourNewHero.setQuest(&amp;quot;какая-то строка&amp;quot;);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Парные методы, различающиеся приставками set и get, принято создавать для работы с закрытыми атрибутами. Это обязательное&lt;br /&gt;
условие для реализации объекта в виде JavaBean. Что такое JavaBean, мы обсудим позже – сейчас запомните, что такое наименование методов позволяет избавиться от ряда проблем в больших системах.&lt;br /&gt;
&lt;br /&gt;
Приступим к написанию самой сказки. Возьмите следующий код и поместите его в файл '''Story.java'''.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class Story {&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    FirstHero ourNewHero = new FirstHero(&amp;quot;Спасти царевну &amp;quot;);&lt;br /&gt;
    System.out.println(“Наш герой хочет отправиться в путь и “ + ourNewHero.getQuest());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это класс Story, он имеет всего один метод main, который является статичным (static-методы и переменные принято называть переменными класса и методами класса, т.к. они общие для всех объектов) и используется для работы с классом в целом. Метод main – это стартовая точка для запуска программы, с которой начинается интерпретация кода.&lt;br /&gt;
&lt;br /&gt;
В ходе интерпретации метода main создается новый объект ourNewHero, а также вызывается метод println объекта out, который обеспечивает вывод в стандартный выходной поток строковойпеременной.&lt;br /&gt;
&lt;br /&gt;
Откомпилируем код и увидим, что у нас получилось. Для компиляции переместитесь в каталог, где вы разместили свои файлы и выполните следующую команду:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
# javac *.java&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
При желании вы можете откомпилировать классы по отдельности, следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
# javac Story.java&lt;br /&gt;
# javac FirstHero.java&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В итоге вы получите два файла '''Story.class''' и '''FirstHero.class'''. Теперь посмотрим на результат:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
# java Story&lt;br /&gt;
Наш герой хочет отправиться в квест и Спасти царевну&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Первая программа на Java готова и работает! Вы создали два класса и научились выводить информацию в консоль. Но мы забыли о&lt;br /&gt;
комментариях...&lt;br /&gt;
&lt;br /&gt;
Комментарии бывают нескольких типов:&lt;br /&gt;
*Строчные начинаются с символа // и длятся до окончания строки.&lt;br /&gt;
*Многострочные комментарии заключаются между /* и */.&lt;br /&gt;
*Комментарии JavaDoc – это многострочные комментарии, заключенные между /** и */, например:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Класс является прототипом объекта &amp;quot;герой&amp;quot;&lt;br /&gt;
 * @author Chernousov Anton&lt;br /&gt;
 * @version 0.1&lt;br /&gt;
 */&lt;br /&gt;
public class FirstHero {&lt;br /&gt;
…&lt;br /&gt;
/**&lt;br /&gt;
   * Метод предназначен для установки внутренней переменной&lt;br /&gt;
quest&lt;br /&gt;
   * в значение Quest.&lt;br /&gt;
   * У этого метода один параметр&lt;br /&gt;
   * @param Quest это переменная означает задание для Героя&lt;br /&gt;
   */&lt;br /&gt;
  public void setQuest(String Quest)&lt;br /&gt;
…&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Комментарии JavaDoc предназначены для формирования документации к проекту из исходных кодов. Если добавить в файл '''FirstHero.java''' только что приведенные строки, то с помощью команды '''javadoc -author -version *.java''' можно сформировать документацию к нашему проекту.&lt;br /&gt;
&lt;br /&gt;
JavaDoc позволяет создавать подробную документацию, которая просто необходима для любого достаточно крупного проекта.&lt;br /&gt;
=== Наследование, интерфейсы и их реализация ===&lt;br /&gt;
Наша сказка написана, но что делать, если проект большой и над ним работает много людей? Как реализовать одновременное программирование разных классов так, чтобы результаты, полученные отдельными разработчиками, можно было без труда соединить в единое целое? Для решения этой задачи, а также задачи множественного наследования в Java существуют интерфейсы – interface. Но обо всем по порядку.&lt;br /&gt;
&lt;br /&gt;
Наследование – это одна из парадигм программирования, которая связана с инкапсуляцией. Суть наследования заключается в следующем: если есть класс, инкапсулирующий в себе некоторые атрибуты и методы, то класс, наследующий его, автоматически наследует все его атрибуты и методы.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class SecondHero extends FirstHero{&lt;br /&gt;
  public SecondHero(String Quest) {&lt;br /&gt;
    super(Quest + &amp;quot; Несмеяну&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Расположенный выше код объявляет класс SecondHero, который с помощью зарезервированного слова extends наследует (расширяет) класс FirstHero. В Java класс может наследовать (расширять)только один класс. При наследовании класса FirstHero, содержащего&lt;br /&gt;
конструктор, обязательно требуется переопределить его (например, как это делается в методе SecondHero). При выполнении оператора super(Quest) будет вызван аналогичный метод из суперкласса (класс-родителя). Строкой super(Quest + “Несмеяну”) мы переопределяем поведение конструктора. Естественно, класс SecondHero может содержать новые атрибуты и методы.&lt;br /&gt;
&lt;br /&gt;
Для проверки механизма наследования сохраните приведенный текст класса SecondHero в файл '''SecondHero.java''' и в файле '''Story.java''' измените имя класса FirstHero на SecondHero. Откомпилируйте и запустите программу, в результате вы должны увидеть следующее:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
# java Story&lt;br /&gt;
Наш герой хочет отправиться в путь и Спасти царевну Несмеяну&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
При разработке программы, перед тем, как приступить к программированию, сначала проводится процесс проектирования (например, через UML-нотации). В результате проектирования появляется документация к проекту, а также спецификации классов. Интерфейс – это явно указанная спецификация набора методов, которые должны быть представлены в классе, реализующий эту спецификацию. В серьезном проекте на момент начала программирования перед программистом оказываются интерфейсы, которые он должен реализовать в классах.&lt;br /&gt;
&lt;br /&gt;
Интерфейс в Java – это специальный класс, в котором отсутствует реализация! Давайте напишем интерфейс для нашего класса FirstHero. Следует скопировать следующий далее код и поместить его в файл '''Hero.java''' – именно этот интерфейс мы будет использован далее. Как вы видите, в отличие от других классов, интерфейс объявляется с помощью зарезервированного слова interface. В нашем случае интерфейс представляет собой следующий набор методов:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public interface Hero {&lt;br /&gt;
  public void setQuest(String Quest);&lt;br /&gt;
  public String getQuest();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Чтобы класс FirstHero реализовывал интерфейс Hero, необходимо изменить первую строчку в файле '''FirstHero.java''' на public class FirstHero implements Hero {. Интерфейс может наследовать (расширять) множество других интерфейсов. Наример:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public interface Lord {&lt;br /&gt;
  public String sendToQuest();&lt;br /&gt;
  public void setBodyguard(Hero hisHero);&lt;br /&gt;
  public Hero getBodyguard();&lt;br /&gt;
}&lt;br /&gt;
 &lt;br /&gt;
public interface King extends Hero, Lord{&lt;br /&gt;
  public void setWife (String PrincesName);&lt;br /&gt;
  public String getWife();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Класс может одновременно наследовать класс и реализовывать один или несколько интерфейсов. Например, как в классе LandLord,&lt;br /&gt;
который наследует класс FirstHero и реализует интерфейс Lord:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class LandLord extends FirstHero implements Lord{&lt;br /&gt;
  private Hero bodyguard;&lt;br /&gt;
  public LandLord(String Quest, Hero hisHero) {&lt;br /&gt;
    super(Quest);&lt;br /&gt;
    this.bodyguard = hisHero;&lt;br /&gt;
  }&lt;br /&gt;
  public String sendToQuest() {&lt;br /&gt;
    bodyguard.setQuest(this.getQuest());&lt;br /&gt;
    return null;&lt;br /&gt;
  }&lt;br /&gt;
  public void setBodyguard(Hero hisHero) {&lt;br /&gt;
    this.bodyguard = hisHero;&lt;br /&gt;
  }&lt;br /&gt;
  public Hero getBodyguard() {&lt;br /&gt;
    return bodyguard;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Чтобы окончательно закрыть тему наследования, необходимо поговорить про абстрактные классы – те, что занимают промежуточное&lt;br /&gt;
место между интерфейсами и реальными классами. Объявление абстрактного класса или метода выполняется с помощью специального&lt;br /&gt;
слова abstract:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
abstract public class Knight&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Абстрактный класс представляет собой неполную реализацию всех объявленных методов, и его можно наследовать, как и любой из классов. Обязательным условием при наследовании является полная реализация абстрактных методов.&lt;br /&gt;
&lt;br /&gt;
=== Полиморфизм ===&lt;br /&gt;
Полиморфизм – это концепция, реализованная в Java, которая позволяет одному и тому же объекту выступать в разных формах. Например, экземпляр класс LandLord можно использовать как объект класса FirstHero. Это стало возможным благодаря тому, что класс LandLord наследует класса FirstHero.&lt;br /&gt;
&lt;br /&gt;
=== Перегруженные методы ===&lt;br /&gt;
Иногда при создании сложных (и не очень) систем есть необходимость реализовать два различных метода, названых одинаково – это возможно с помощью перегруженных (overloading) методов. Выбор реализации зависит от типа объектов, переданных в качестве параметров.&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class GreatKing extends LandLord implements King{&lt;br /&gt;
  private String wife;&lt;br /&gt;
  private boolean theftedWife;&lt;br /&gt;
&lt;br /&gt;
  public GreatKing(String Quest, Hero hisHero) {&lt;br /&gt;
    super(Quest, hisHero);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public void setWife(String PrincesName) {&lt;br /&gt;
    this.wife = PrincesName;&lt;br /&gt;
    this.theftedWife = false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String getWife() {&lt;br /&gt;
    if (theftedWife){return null;}&lt;br /&gt;
    else{ return wife;}&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  public String getWife(boolean flag) {&lt;br /&gt;
    if (flag){ this.theftedWife = true;}&lt;br /&gt;
    return wife;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
В представленном классе GreatKing существуют две реализации перезагруженного метода getWife, которые можно вызвать следующим образом:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
GreatKing ourKing = new GreatKing(&amp;quot;Править мудро&amp;quot;, (Hero) new FirstHero(&amp;quot;Охранять господина&amp;quot;));&lt;br /&gt;
String hisWife = ourKing.getWife();&lt;br /&gt;
String theftedHisWife = ourKing.getWife(true);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Вместо заключения ===&lt;br /&gt;
Ну вот, мы создали всех героев. Разместите интерфейсы Lord, King, а также классы LandLord и GreatKing в соответствующих файлах.&lt;br /&gt;
Немного измените класс Story, чтобы завершить сказку:&lt;br /&gt;
&amp;lt;source lang = &amp;quot;java&amp;quot;&amp;gt;&lt;br /&gt;
public class Story {&lt;br /&gt;
  public static void main(String[] args) {&lt;br /&gt;
    // создадим наших героев&lt;br /&gt;
    Hero ourNewHero = (Hero) new FirstHero(&amp;quot;Спасити царевну&amp;quot;);&lt;br /&gt;
    GreatKing ourKing = new GreatKing(&amp;quot;Править мудро&amp;quot;, (Hero) new FirstHero(&amp;quot;Охранять господина&amp;quot;));&lt;br /&gt;
    LandLord ourNewLandLord = new LandLord(&amp;quot;Похитить царевну&amp;quot;, (Hero) new FirstHero(&amp;quot;Охранять господина&amp;quot;));&lt;br /&gt;
    // Женим нашего короля&lt;br /&gt;
    ourKing.setWife(&amp;quot;Несмеяна&amp;quot;);&lt;br /&gt;
    // И начнем повествование&lt;br /&gt;
    System.out.println(&amp;quot;Жил был мудрый король, и должен был он &amp;quot; + ourKing.getQuest());&lt;br /&gt;
    System.out.println(&amp;quot;Была у него жена, и звали ее &amp;quot; + ourKing.getWife());&lt;br /&gt;
    System.out.println(&amp;quot;Был в королевстве коварный Визирь и хотел он &amp;quot; + ourNewLandLord.getQuest());&lt;br /&gt;
    System.out.println(&amp;quot;И сделал это&amp;quot;);&lt;br /&gt;
    String wife = ourKing.getWife(true);&lt;br /&gt;
    //&lt;br /&gt;
    System.out.println(&amp;quot;А наш герой жаждал &amp;quot; + ourNewHero.getQuest() + &amp;quot; ..и добился этого&amp;quot;);&lt;br /&gt;
    ourKing.setWife(wife);&lt;br /&gt;
    System.out.println(&amp;quot;Король был счастлив.&amp;quot;);&lt;br /&gt;
    System.out.println(&amp;quot;Ну а что случилось дальше вы можете придумать сами...&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Откомпилируйте и насладитесь результатом выполнения урока.&lt;br /&gt;
&lt;br /&gt;
В следующей статье мы поговорим о простых числах и других типах, вычислениях, циклах, массивах и списках.&lt;/div&gt;</summary>
		<author><name>Maximax</name></author>	</entry>

	</feed>