Java programming выпуск 18-й
Здравствуйте дорогие читатели!
Начинающим
Условные операторы
if-else
В обобщенной форме этот оператор записывается следующим образом:
if (логическое выражение) оператор1; [ else оператор2;]
Раздел else необязателен. На месте любого из операторов может стоять составной оператор, заключенный в фигурные скобки. Логическое выражение — это любое выражение, возвращающее значение типа boolean.
Вот посмотрите небольшую программку определения возрастной категории, используются операторы if-else:
class IfElseClass { public static void main(String args[]) { int age=6; if(age>=0&&age;<7) System.out.println("You very young"); else if(age>=7&&age;<18) System.out.println("You young"); else if(age>=18&&age;<50) System.out.println("You adult"); else if(age>=50&&age;<80) System.out.println("You old"); else if(age>=80&&age;<=180) System.out.println("You very old"); else if(age>180) System.out.println("You deadmen"); else System.out.println("Wrong age"); } }
После выполнения программы вы должны получить следующий результат:
You very young
break
В языке Java отсутствует оператор goto. Для того, чтобы в некоторых случаях заменять goto, в Java предусмотрен оператор break. Этот оператор сообщает исполняющей среде, что следует прекратить выполнение именованного блока и передать управление оператору, следующему за данным блоком. Для именования блоков в языке Java используются метки. Оператор break при работе с циклами и в операторах switch может использоваться без метки. В таком случае подразумевается выход из текущего блока.
Например, в следующей программе имеется три вложенных блока, и у каждого своя уникальная метка. Оператор break, стоящий во внутреннем блоке, вызывает переход на оператор, следующий за блоком b. При этом пропускаются два оператора println.
class Break { public static void main(String args[]) { boolean t = true; a: { b: { c: { System.out.println("Before the break"); // Перед break if (t) break b; System.out.println("This won't execute"); // Не будет выполнено } System.out.println("This won't execute"); // Не будет выполнено } System.out.println("This is after b"); //После b } } }В результате исполнения программы вы получите следующий результат:
Before the break
This is after b
switch
Оператор switch обеспечивает ясный способ переключения между различными частями программного кода в зависимости от значения одной переменной или выражения. Общая форма этого оператора такова:
switch ( выражение )
{
case значение1:
break;
case значение2:
break;
case значением:
break;
default:
}
Результатом вычисления выражения может быть значение любого простого типа, при этом каждое из значений, указанных в операторах case, должно быть совместимо по типу с выражением в операторе switch. Все эти значения должны быть уникальными литералами. Если же вы укажете в двух операторах case одинаковые значения, транслятор выдаст сообщение об ошибке.
Если же значению выражения не соответствует ни один из операторов case, управление передается коду, расположенному после ключевого слова default. Отметим, что оператор default необязателен. В случае, когда ни один из операторов case не соответствует значению выражения и в switch отсутствует оператор default выполнение программы продолжается с оператора, следующего за оператором switch.
Внутри оператора switch break без метки приводит к передаче управления на код, стоящий после оператора switch. Если break отсутствует, после текущего раздела case будет выполняться следующий. Иногда бывает удобно иметь в операторе switch несколько смежных разделов case, не разделенных оператором break.
В следующей программе определим к какому сезону относится месяц:
class SwitchClass { public static void main(String args[]) { int month = 4; String season; switch (month) { case 12: case 1: case 2: season = "Winter"; break; case 3: case 4: case 5: season = "Spring"; break; case 6: case 7: case 8: season = "Summer"; break; case 9: case 10: case 11: season = "Autumn"; break; default: season = "Bogus Month"; } System.out.println("April is in the " + season + "."); } }
return
Оператор return приводит к немедленному завершению работы и передаче управления коду, вызвавшему метод.
Рассмотрим пример, иллюстрирующий использование оператора return для немедленного возврата управления, в данном случае — исполняющей среде Java.
class ReturnDemo { public static void main(String args[]) { boolean t = true; System.out.println("Before the return"); //Перед оператором return if (t) return; System.out.println("This won't execute"); //Это не будет выполнено } }
Замечание: Зачем в этом примере использован оператор if (t)? Дело в том, не будь этого оператора, транслятор Java догадался бы, что последний оператор println никогда не будет выполнен. Такие случаи в Java считаются ошибками, поэтому без оператора if оттранслировать этот пример нам бы не удалось.
В следующем номере мы рассмотрим циклы.
Тема "на заказ"
Многопоточность (продолжение)
Синхронизация потоков
Многопоточный режим работы открывает новые возможности для программистов, однако за эти возможности приходится расплачиваться усложнением процесса проектирования приложения и отладки. Основная трудность, с которой сталкиваются программисты, никогда не создававшие ранее многопоточные приложения, это синхронизация одновременно работающих потоков.
Однопоточная программа, такая, например, как программа MS-DOS, при запуске получает в монопольное распоряжение все ресурсы компьютера. Так как в однопоточной системе существует только один процесс, он использует эти ресурсы в той последовательности, которая соответствует логике работы программы. Процессы и потоки, работающие одновременно в многопоточной системе, могут пытаться обращаться одновременно к одним и тем же ресурсам, что может привести к неправильной работе приложений.
Поясним это на наглядном примере.
Реализуем модель в которой имеются некий счет и клиенты которые могут либо добавлять на него деньги, либо снимать.
Клиент реализуется классом наследуемым от класса Thread:
package samplethread; public class ClientAccount extends Thread { StartFrame moneyFrame; int money=0; public ClientAccount(int money, StartFrame moneyFrame) { this.moneyFrame=moneyFrame; this.money=money; } public void run() { while(true) { moneyFrame.cMoney(money); } } }
В конструкторе мы получаем сумму которую мы хотим снять или положить на счёт (если сумм положительна то положить, если отрицательно - снять), и форму в которой нам доступен метод cMoney(money)
реализующий доступ к счету.
Форма содержащая счёт и метод cMoney(money)
будет представляться следующим классом:
package samplethread; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class StartFrame extends JFrame { XYLayout layout = new XYLayout(); JTextField mainAccount = new JTextField("100000"); JTextField comeMoney = new JTextField("0"); JLabel jLabel1 = new JLabel("Сумма на счету:"); JLabel jLabel2 = new JLabel("Приход:"); JButton jb = new JButton("Exit"); JButton jb2 = new JButton("Start"); ClientAccount ca1; ClientAccount ca2; ClientAccount ca3; JTextArea errorTextArea1 = new JTextArea(); public StartFrame() { enableEvents(AWTEvent.WINDOW_EVENT_MASK); try { jbInit(); } catch(Exception e) { e.printStackTrace(); } } private void jbInit() throws Exception { this.setSize(new Dimension(320, 180)); this.setTitle("Sample no synchronized thread"); this.getContentPane().setLayout(layout); mainAccount.setEditable(false); comeMoney.setEditable(false); jb.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(MouseEvent e) { jbCM(); } }); jb2.addMouseListener(new java.awt.event.MouseAdapter() { public void mouseClicked(MouseEvent e) { jb2CM(e); } }); this.setResizable(false); this.getContentPane().add(jLabel1, new XYConstraints(5, 5,100, 20)); this.getContentPane().add(mainAccount, new XYConstraints(120, 5, 100, 20)); this.getContentPane().add(jLabel2, new XYConstraints(5, 50, 100, 20)); this.getContentPane().add(comeMoney, new XYConstraints(120, 50, 100, 20)); this.getContentPane().add(jb, new XYConstraints(240, 40, 60, 20)); this.getContentPane().add(jb2, new XYConstraints(240, 10, 60, 20)); this.getContentPane().add(errorTextArea1, new XYConstraints(5, 80, 300, 60)); } protected void processWindowEvent(WindowEvent e) { super.processWindowEvent(e); if (e.getID() == WindowEvent.WINDOW_CLOSING) { jbCM(); } } public void jb2CM(MouseEvent e) { ca1=new ClientAccount(1000,this); ca1.start(); ca2=new ClientAccount(-2000,this); ca2.start(); ca3=new ClientAccount(3000,this); ca3.start(); } public void jbCM() { ca1=null; ca2=null; ca3=null; System.exit(0); } public void cMoney(int money) { comeMoney.setText(""+money); try { Integer mm= new Integer(mainAccount.getText()); int m=mm.intValue()+money; mainAccount.setText(""+m); } catch(Exception e) { errorTextArea1.setText(errorTextArea1.getLineCount()+" Error: Одновременный доступ к счету: " + e + "\n"); //System.out.println("Error: Одновременный доступ к счету: "+ e); } } }
По нажатии кнопочки jb создаём три новых потока (в методе jb2CM(MouseEvent e)).
По нажатии кнопочки jb2 завершаем работу потоков (в методе jbCM()).
В методе cMoney(int money), который вызывается потоками-клиентами, мы получаем сумму, выводим её в текстовое поле "приход", и прибавляем её к основному счету.
Как вы могли заметить в методе cMoney(int money) все основные операции находятся в блоке try, т.е. обрабатываются на возможность появления исключительной ситуации. Это связано с тем что при попытке одновременного доступа потоков к методу будет появляться ошибка преобразования форматов, так как в текстовое поле mainAccount будут записываться одновременно разные данные.
Можете посмотреть это запустив приложение из данного jar-архива.
Для того чтобы избежать этого необходимо объявить наш метод как synchronized, сделав его синхронизированным:
public synchronized void cMoney(int money)
При вызове синхронизированного метода соответствующий ему объект блокируется для использования другими синхронизированными методами. В результате предотвращается одновременная запись двумя методами значений в область памяти, принадлежащую данному объекту.
Использование синхронизированных методов - достаточно простой способ синхронизации потоков, обращающихся к общим критическим ресурсам.
Не обязательно синхронизовать весь метод - можно выполнить синхронизацию только критичного фрагмента кода:
synchronized(mainAccount) { Integer mm= new Integer(mainAccount.getText()); int m=mm.intValue()+money; mainAccount.setText(""+m); }
Вот теперь посмотрите как работает приложение запустив его из данного jar-архива.
В следующем номере ещё поговорим о потоках и попробуем написать более функциональную программу.
Вопрос - ответ
Вопрос: Требуется загрузить в BufferedImage изображение из указаного файла после
обработки сохранить на диск в указаный файл.
|
Ответ: Вот метод позволяющий сохранять BufferedImage в jpg файл: import java.io.*; import java.awt.image.*; import com.sun.image.codec.jpeg.*; /* .................... */ public void saveImageAsJPEG(Image img, String fileName, ImageObserver imgObs) { int w=img.getWidth(this); int h=img.getHeight(this); BufferedImage bimg = new BufferedImage(w,h,BufferedImage.TYPE_3BYTE_BGR); bimg.getGraphics().drawImage(img,0,0,imgObs); /* .......... Здесь вставляете код обработки изображения. .......... */ try { FileOutputStream fos = new FileOutputStream(fileName); JPEGImageEncoder jc= JPEGCodec.createJPEGEncoder(fos); jc.encode(bimg); fos.close(); } catch(IOException ioe) { } } |
Вопрос: Есть апплет, состоящий из трех панелей. Одна из панелей имеет компоновку CardLayout(), и к ней прицеплено еще три панели, на одной из которых есть элемент TextArea() со скроллингом у которого setBounds() такой-же как и у панели. Вопрос в следующем, почему когда я медленно меняю размер окна скроллинг всегда проявляется, как только я бысторо изменил размер или перешел в полноэкранный и обратно скроллинг пропадает и появляется только после парезагрузки апплета. Я решил данный эелемент сделать на Swing, используя ScrollPane(,,,,) и
JTextArea() у меня это работает. Но когда я хочу этот элемент вставить
в CardLayout() как панель или на какую-нибудь другую панель то эффекта никакого!!!!
|
Ответ: Если я вас правильно понял то работающий пример помещаю в раздел "Программный код…" |
Вопрос: Как можно использовать RadioButton в меню (JMenu) и каким образом я могу задать горячею клавишу.
|
Ответ: Посмотрите пример создания меню |
Вопрос: Где можно скачать JAVA и сколько занимает оригинал JAVA.
|
Ответ:
Прошу перед тем как задать вопрос прочитать FAQ по разделу: |
Программный код…
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Frame1 extends JFrame { JPanel contentPane; JPanel panel1 = new JPanel(); JPanel panel2 = new JPanel(); JPanel panel3 = new JPanel(); JPanel panel2_1 = new JPanel(); JPanel panel2_2 = new JPanel(); JPanel panel2_3 = new JPanel(); JPanel panel4 = new JPanel(); JScrollPane jScrollPane1 = new JScrollPane(); JTextArea jTextArea1 = new JTextArea(); BorderLayout borderLayout1 = new BorderLayout(); BorderLayout borderLayout2 = new BorderLayout(); BorderLayout borderLayout3 = new BorderLayout(); CardLayout cardLayout1 = new CardLayout(); public Frame1() { enableEvents(AWTEvent.WINDOW_EVENT_MASK); try { jbInit(); } catch(Exception e) { e.printStackTrace(); } } private void jbInit() throws Exception { contentPane = (JPanel) this.getContentPane(); this.setSize(new Dimension(400, 300)); this.setTitle("Frame Title"); contentPane.setLayout(borderLayout1); contentPane.add(panel1, BorderLayout.NORTH); contentPane.add(panel2, BorderLayout.CENTER); contentPane.add(panel3, BorderLayout.SOUTH); panel1.setBackground(Color.red); panel2.setBackground(Color.green); panel3.setBackground(Color.blue); panel2.setLayout(borderLayout2); panel2.add(panel2_1, BorderLayout.NORTH); panel2.add(panel2_2, BorderLayout.CENTER); panel2.add(panel2_3, BorderLayout.SOUTH); panel2_2.setLayout(cardLayout1); panel2_1.setBackground(new Color(0,200,0)); panel2_2.setBackground(new Color(0,150,0)); panel2_3.setBackground(new Color(0,100,0)); panel2_2.add(panel4,"panel4"); panel4.setLayout(borderLayout3); panel4.add(jScrollPane1); jScrollPane1.getViewport().add(jTextArea1); jScrollPane1.setAutoscrolls(true); jTextArea1.setText("jTextArea1"); } protected void processWindowEvent(WindowEvent e) { super.processWindowEvent(e); if (e.getID() == WindowEvent.WINDOW_CLOSING) { System.exit(0); } } }Jar-архив
JavaScript
Вопрос: Подскажите пожалуйста, как сделать, чтобы ежемесячно в один и
тот же день, например первого числа, происходила бы смена рисунка, причём не
выборочно, а по порядку. Т.е. каждому месяцу соответствовал бы свой рисунок.
|
Ответ: <html;> <body;> <img; src="1.gif" name="monthImg"> <script; language="JavaScript"> <!-- d=new Date(); document.monthImg.src=d.getMonth()+".gif"; //--> </script> </body> </html> |
Вопрос: Как установить проверку на наличие Java Virtual Machine на клиентском компьютере?
|
Ответ: navigator.javaEnabled() |
Вопрос: Как сделать, что бы все изображениясразу загружались?
|
Ответ:
О предворительной загрузки изображений ужеговорилось в
в выпуске 7. |
Вопрос: Можно ли при помощи JavaScript сделать какие-нибудь фокусы с указателем (мышью)???
|
Ответ: Какие фокусы? Ну смену курсора можно сделать. <script;> <!-- function changeCursor(obj,i) { t=i; if(i==0)t="DEFAULT" else if(i==1)t="CROSSHAIR" else if(i==2)t="HEND" else if(i==3)t="MOVE" else if(i==4)t="TEXT" else if(i==5)t="WAIT" obj.style.cursor=t; } //--> </script> Допустим хотим сменить курсор над ссылкой: <a; OnMouseOver="changeCursor(this,1)" href="my_file.htm">Ссылка</a>Пример: Ссылка |
Вопросы присылайте на E-mail
[email protected] с пометкой "Вопрос по Java".
Жду вопросов и предложений.
Подписаться на эту рассылку и посмотреть архив можно тут /subs/subs.html