- •Лабораторна робота № 1.
- •Короткі теоретичні відомості.
- •Практична частина. Створення найпростішого додатка Java.
- •Компіляція файлів проекту й запуск додатка.
- •Створення Java додатка із графічним інтерфейсом.
- •Контрольні питання.
- •Завдання.
- •Лабораторна робота № 2.
- •Короткі теоретичні відомості.
- •Контрольні питання.
- •Завдання.
- •Лабораторна робота № 3.
- •Короткі теоретичні відомості.
- •Контрольні питання.
- •Завдання.
- •Лабораторна робота № 4.
- •Короткі теоретичні відомості.
- •Контрольні питання.
- •Завдання.
- •Лабораторна робота № 5.
- •Короткі теоретичні відомості.
- •Контрольні питання.
- •Завдання.
- •Лабораторна робота № 6.
- •Короткі теоретичні відомості.
- •Контрольні питання.
- •Завдання.
Контрольні питання.
Назвіть основні керуючі конструкції.
У чому основне розходження операторів Break й Continue?
Чи можна використати числа, як значення типу Boolean?
Що таке інструкція перемикання?
Завдання.
Написати додаток із графічним користувальницьким інтерфейсом, у якому по натисканню на кнопку ілюструється дія операторів циклу for , while , do...while – залежно від того, яка із кнопок JRadioButton натиснута. За допомогою цих циклів повинна обчислюватися площа під кривою, що задає функцією f(x)=a∙ x2+b∙ x+c, при x мінливому від x1 до x2, де величини a,b,c, x1 й x2 повинні вводитися користувачем у відповідних пунктах уведення.
Додати в цей додаток обчислення з речовинним лічильником циклу для якого-небудь із операторів (for , while або do...while) у випадку, коли відзначена відповідна опція за допомогою кнопки JCheckBox. Показати наявність нестійкості при дуже малій зміні вхідних параметрів (який-небудь із величин a,b,c, x1,x2). Пояснити, чому зміна одних параметрів приводить до нестійкості, а інших - ні.
Написати додаток із графічним користувальницьким інтерфейсом, у якому по натисканню на кнопку JButton ілюструється дія операторів переривання continue, break, return, System.exit - залежно від того, яка із кнопок JToggleButton натиснута.
Лабораторна робота № 3.
Тема: Найважливіші об'єктні типи. Робота із графікою, рядками й масивами.
Ціль: Одержання практичних навичок у роботі з масивами й рядками
Мови Java, а також робота з графікой.
Короткі теоретичні відомості.
Робота з рядками:
Об'єкти String створені щоб бути незмінними. Якщо ви ознайомитеся з документацією по класі String, ви побачите що всі методи цього класу, які змінюють об'єкт String насправді лише створюють і повертають абсолютно новий об'єкт String утримуючої зміни. При цьому об'єкт-оригінал String залишається незмінним.
Оскільки об'єкт String незмінний, ви можете багаторазово дублювати посилання на нього. Оскільки він є об'єктом тільки для читання, немає ніякої небезпеки що дії з однієї з посилань приведуть до зміни об'єкта, що відіб'ється на роботі з іншими посиланнями. Так в об'єктах тільки для читання вирішується проблема дублюючих посилань.
Також представляється можливим обробка всіх случаяв, при яких вам необхідно вносити зміни в об'єкт. Із цією метою створюється зовсім новий варіант об'єкта із уже внесеними змінами, як це реалізовано в String. Однак, у деяких випадках це не ефективно. Прикладом є використання оператора '+', перевантаженого для об'єктів String. Термін "перевантажений" означає, що при використанні із класом певного типу оператор виконує специфічні функції. (Оператори '+' й '+=' для String - єдині перевантажені оператори в Java й в Java програміст не має можливості перевантажувати які-небудь інші оператори). Коли '+' використається з об'єктами String, він виконує операцію об'єднання двох і більше об'єктів String:
String s = "abc" + foo + "def" + Integer.toString(47);
Працює це так: в об'єкта String "abc" є метод append(), що створює об'єкт String, що містить "abc", об'єднаний із умістом foo. Новий об'єкт String у свою чергу створює новий об'єкт String, у який додається "def" і так далі.
Це вимагає створення безлічі об'єктів String лише для об'єднання цих нових об'єктів String, і в результаті у вас вийшла б величезна кількість проміжних об'єктів String, що вимагають збору сміття. Рішенням є використання класу-компаньйона, що модифікує, відповідно до розглянутого раніше принципу. Для об'єкта String класом-компаньйоном є StringBuffer, і компілятор автоматично створює StringBuffer для обробки деяких виражень, зокрема при використанні операторів '+' й '+=' стосовно до об'єктів String. От приклад того як це відбувається:
// Демонстрація StringBuffer.
public class ImmutableStrings {
public static void main(String[] args) {
String foo = "foo";
String s = "abc" + foo +
"def" + Integer.toString(47);
System.out.println(s);
// "Рівність" з використанням StringBuffer:
StringBuffer sb =
new StringBuffer("abc"); // Створює String!
sb.append(foo);
sb.append("def"); // Створює String!
sb.append(Integer.toString(47));
System.out.println(sb);
}
}
При створенні рядка String s компілятор створює грубу копію наступного коду, що використає sb: створюється StringBuffer і використається append() для додавання нових символів безпосередньо в об'єкт StringBuffer (це краще чим щораз створювати нові копії). При тім що це більш ефективно, слід зазначити, що щораз при створенні рядків ув'язнених у лапки, таких як "abc" або "def", компілятор перетворює їх в об'єкти String. Тому насправді створюється більше об'єктів чим вам могло здатися, незважаючи на ефективність StringBuffer.
У таблице 16 представлений огляд методів для класу String. Тут розглянуті не всі методи, а тільки найбільш важливі, що мають відношення до обговорюваної теми.
Таблиця 16.
Метод |
Параметри, Перевантаження |
Застосування |
Constructor |
Перевантажені: значення за замовчуванням, String, StringBuffer, масиви char, масиви byte. |
Створює об'єкти String. |
length( ) |
|
Кількість символів в String. |
charAt() |
int індекс |
Повертає символ із зазначеним індексом осередку String. |
getChars( ), getBytes( ) |
Початковий і кінцевий осередки, які будуть скопійований й осередок у зовнішнього масиву, у яку буде зроблене копіювання. |
Копіює char або byte у зовнішній масив. |
toCharArray( ) |
|
Створює масив char[], що зберігає символи з String. |
equals( ), equals-IgnoreCase( ) |
String з якої проводиться порівняння. |
Перевірка на рівність умісту двох Strings. |
compareTo( ) |
String з якої проводиться порівняння. |
Результат негативний, нуль або позитивний, на підставі лексиграфического впорядкування String і параметра. Заголовні й прописні символи не рівні! |
regionMatches( ) |
Зсув у поточної String, інший String і зсув і довжина фрагмента для порівняння. Перевантаження додає "ігнорувати регістр символів." |
Результат boolean, що свідчить про збіг фрагментів. |
startsWith( ) |
String, що може починати поточний String. Перевантаження додає параметр для вказівки зсуву. |
Результат boolean свідчить про те, чи починається String з переданої як параметр рядка. |
endsWith( ) |
String, що може завершувати поточний String. |
Результат boolean свідчить про те, чи завершується String переданої як параметр рядком. |
indexOf( ), lastIndexOf( ) |
Перевантажені: char, char й індекс початку, String, String й індекс початку. |
Повертає -1 якщо аргумент не знайдений у даному String, інакше повертається індекс початку знайденого фрагмента. lastIndexOf( ) здійснює пошук починаючи з кінця рядка. |
substring( ) |
Перевантажений: Індекс початку, індекс початку, і індекс кінця. |
Повертає новий об'єкт String, що містить зазначений набір символів. |
concat( ) |
String для об'єднання |
Повертає новий об'єкт String, содерщащий символи оригінального об'єкта String і розташовані слідом за ними символи передані як параметр. |
replace( ) |
Старий символ використовуваний для пошуку, новий символ використовуваний для заміни. |
Повертає новий об'єкт String з результатами проведеної заміни. Якщо шуканий символ не знайдений, використається старий String. |
toLowerCase( ) toUpperCase( ) |
|
Повертає новий об'єкт String зі зміненими на відповідний регістр символами. Якщо зміни не потрібно, використається старий String. |
trim( ) |
|
Повертає новий об'єкт String зі скороченням з обох кінців пробілів до одинарних. Якщо зміни не потрібні, використається старий String. |
valueOf( ) |
Перевантаження: Object, char[], char[] і зсув і покажчик, boolean, char, int, long, float, double. |
Повертає String, що містить символьне подання параметра. |
intern( ) |
|
Створює один і тільки один String з унікальною послідовністю символів. |
Тепер розглянемо клас StringBuffer, його методи представлені в таблиці 17:
Таблиця 17.
Метод |
Параметри, перевантаження |
Застосування |
Constructor |
Перевантажений: значення за замовчуванням, довжина створюваного буфера, String використовуваний як джерело. |
Створює новий об'єкт StringBuffer. |
toString( ) |
|
Створює String використовуючи поточний StringBuffer. |
length( ) |
|
Кількість символів в StringBuffer. |
capacity( ) |
|
Повертає поточний обсяг займаної пам'яті. |
ensure- Capacity( ) |
Integer визначальний бажаний обсяг пам'яті. |
StringBuffer резервує як мінімум зазначений обсяг пам'яті. |
setLength( ) |
Integer визначальну нову довжину рядка символів у буфері. |
Чи розширює укорочує рядок символів. Якщо рядок розширюється, нові осередки заповнюються нулями. |
charAt( ) |
Integer, що вказує на позицію елемента. |
Повертає char для заданої позиції буфера. |
setCharAt( ) |
Integer, що вказує на позицію елемента й нове значення char для цього елемента. |
Змінює значення в зазначеній позиції. |
getChars( ) |
Початок і кінець копируемого фрагмента, масив у який виробляється копіювання, індекс у цільовому масиві. |
Виконує копіювання символів char у зовнішній масив. На відміну від String тут немає методу getBytes( ). |
append( ) |
Перевантажений: Object, String, char[], char[] зі зсувом і довжиною, boolean, char, int, long, float, double. |
Параметр перетвориться в рядок і додається в кінець поточного буфера. При необхідності розмір буфера збільшується. |
insert( ) |
Перевантажений, для всіх першим параметром є зсув з яким виконується вставка: Object, String, char[], boolean, char, int, long, float, double. |
Другий параметр перетвориться в рядок й уставляється в поточний буфер починаючи із зазначеного зсуву. При необхідності розмір буфера збільшується. |
reverse( ) |
|
Порядок проходження символів у буфері міняється на протилежний. |
Робота з масивами:
Масив (array) - це впорядкований набір однаково влаштованих осередків, доступ до яких здійснюється по індексі. Наприклад, якщо в масиву ім'я a1, то a1[i] - ім'я осередку цього масиву, що має з індекс i.
В Java масиви є об'єктами, але особливого роду – їхнє оголошення відрізняється від оголошення інших видів об'єктів. Змінна типу масив є посилальної - у ній утримується адреса об'єкта, а не сам об'єкт, як і для всіх інших об'єктних змінних в Java. Як елементи (осередків) масиву можуть виступати значення як примітивних типів, так і посилальних типів, у тому числі - змінні типу масив.
Тип осередку масиву називається базовим типом для масиву.
Для завдання масиву, на відміну від об'єктів інших типів, не потрібно попередньо задавати клас, і мати спеціальне ім'я для даного об'єктного типу. Замість імені класу при оголошенні змінної використається ім'я базового типу, після якого йдуть порожні квадратні дужки.
Наприклад, оголошення
int[] a1;
задає змінну a1 типу масив. При цьому розмір масиву (число осередків у ньому) заздалегідь не задається й не є частиною типу.
Для того, щоб створити об'єкт типу масив, варто скористатися зарезервованим словом new, після чого вказати ім'я базового типу, а за ним у квадратних дужках число осередків у створюваному масиві:
a1=new int[10];
Можна сполучити оголошення типу змінної й створення масиву :
int[] a1=new int[10];
Після створення масиви Java завжди инициализированы - в осередках утримуються нулі. Тому якщо базовий тип масиву примітивний, елементи масиву будуть нулями відповідного типу. А якщо базовий тип посилальний - в осередках будуть значення null.
Довжина масиву зберігається в поле length, що доступно тільки по читанню - змінювати його шляхом присвоювання нового значення не можна.
Приклад роботи з масивом:
int[] a=new int[100];
for(int i=0;i<a.length;i++){
a[i]=i+1;
};
Якщо в нас є змінна типу масив, і їй зіставлений масив заданої довжини, у будь-який момент цієї змінної можна зіставити новий масив. Наприклад,
a1=new int[20];
При цьому колишній масив^-масив-об'єкт-масив, що перебуває в динамічній області пам'яті, буде загублений і перетвориться в сміття.
Змінні типу масив можна привласнювати один одному. Присвоювання змінних типу масив приводить до того, що імена змінних стають синонімами того самого масиву - копіюється адреса масиву. А зовсім не приводить до копіювання елементів з одного масиву в іншій, як це відбувається в деяких інших мовах програмування.
Двовимірний масив являє собою масив осередків, кожна з яких має тип “одномірний масив”. Відповідним чином він і задається. Наприклад, завдання двовимірного масиву цілих чисел буде виглядати так:
int[][] a=new int[10][20];
Буде заданий осередок типу “двовимірний масив”, а також створений і призначений цієї посилальної змінної масив, що має по першому індексі 10 елементів, а по другому 20. Тобто ми маємо 10 осередків типу “одномірний масив”, кожна з яких посилається на масив з 20 цілих чисел. При цьому базовим типом для осередків по першому індексі є int[], а для осередків по другому індексі int.
Розглянемо роботу із двовимірними масивами на прикладі заповнення двовимірного масиву випадковими числами:
int m=10;//10 рядків
int n=20;//20 стовпців
int[][] a=new int[m][n];
for(int i=0;i<m;i++){ //цикл по рядках
for(int j=0;j<n;j++){ //цикл по стовпцях
a[i][j]=(int)(100*Math.random());
System.out.print(a[i][j]+" ");
};
System.out.println();//переклад на новий рядок після виводу рядка матриці
};
Після створення масиву потрібно його инициализировать - записати потрібні значення в осередки. Дотепер ми робили це шляхом завдання значень у циклі по деякій формулі, однак часто потрібно задати конкретні значення. Дуже зручний наступний варіант синтаксису:
int[] a=new int[] {2,0,0,6};
При ініціалізації двовимірних і багатомірних масивів використають вкладені масиви, що задають за допомогою фігурних дужок. Наприклад, фрагмент коду
int[][] b= new int[][]
{
{2,0,0,0}, //це b[0]
{2,0,0,1}, //це b[1]
{2,0,0,2}, //це b[2]
{1,0,0,0}, //це b[3]
{2,0,0,0}, //це b[4]
{3,0,0,0}, //це b[5]
};
З об'єктів-масивів можна викликати метод clone(), що дозволяє створювати копію (клон) масиву:
a=new int[] {2,0,0,6};
int[] a1=a.clone();
Копіювання масивів можна здійснювати в циклі, але набагато швидше використати метод System.arraycopy.
int[] b=new int[a.length+10];
System.arraycopy(a,index1a,b, index1b,count);
Швидке заповнення масиву однаковими значеннями може здійснюватися методом Arrays.fill(масив, значення). Клас Arrays розташований у пакеті java.util. Заелементне порівняння масиву варто виконувати за допомогою методу Arrays.equals(a,a1). Сортування (упорядкування за значеннями) масиву a виробляються методами Arrays.sort(a) і Arrays.sort(a,index1,index2). Перший з них упорядковує в порядку зростання весь масив, другий – частина елементів (від індексу index1 до індексу index2).
Робота із графікою:
Вивід графіки здійснюється за допомогою об'єктів типу java.awt.Graphics. Для них визначений ряд методів, описаних у таблиці 18.
Мається на увазі, що w- ширина області або фігури, h- висота; x,y- координати лівого верхнього кута області. Для фігури x,y- координати лівого верхнього кута прямокутника, у який уписана фігура.
Таблиця 18.
Параметри виводу графіки |
|
Color getColor() |
Довідатися поточні кольори малювання. |
setColor(Color c) |
Задати поточні кольори малювання. |
Font getFont() |
Довідатися поточний фонт для виводу текстової інформації. |
setFont(Font f) |
Установити поточний фонт для виводу текстової інформації. Екземпляр фонта створюється за допомогою конструктора Font(“имяФонта”,стильФонта,размерФонта) |
FontMetrics getFontMetrics() |
Довідатися параметри поточного фонта |
FontMetrics getFontMetrics(Font f) |
Довідатися параметри для довільного фонта f |
setXORMode(Color c1)
|
Установка режиму малювання XOR (“ щовиключає або”) для кольорів c1. При цьому вивід крапки кольори color дає кольори, дорівнює побітовому значенню color ^ c1 (тобто color XOR c1) для числового RGB-кодування кольорів. Повторний вивід графічного зображення на те ж місце приводить до відновлення первісного зображення в області виводу. |
setPaintMode()
|
Повернення у звичайний режим з режиму малювання XOR. |
translate(x0,y0) |
Зрушення початку координат графічного контексту в крапку x0,y0. Всі координати, зазначені при виводі графічних примітивів, відраховують щодо цього початку координат. |
Малювання контурних фігур |
|
drawLine(x1,y1,x2,y2) |
Вивід лінії із крапки з координатами x1,y1 у крапку x2,y2 |
|
|
drawRect(x,y,w,h) |
Вивід прямокутника. |
drawRoundRect(x,y,w,h,arcWidth,arcHeight)
|
Вивід округленого прямокутника. |
draw3DRect(x,y,w,h,isRaised) |
Вивід “об'ємного” прямокутника. Якщо змінна isRaised ==true, він “опуклий” (raised), інакше - “втиснений”. |
drawPolygon(Polygon p); drawPolygon(int[] xPoints, int[] yPoints, int nPoints) |
Вивід багатокутника по масиві крапок, nPoints – число крапок. |
drawPolyline(int[] xPoints,int[] yPoints, int nPoints) |
Вивід незамкнутої ламаної лінії по масиві крапок, nPoints – число крапок. |
drawOval(x,y,w,h) |
Вивід еліпса. |
drawArc(x,y,w,h,startAngle,arcAngle) |
Вивід дуги еліпса. Початковий кут startAngle і кут, що задає кутовий розмір дуги arcAngle, задаються в градусах. |
drawImage(Image img,int x,int y, ImageObserver observer) і інші перевантажені варіанти методу |
Вивід зображення. |
Малювання заповнених фігур |
|
clearRect(x,y,w,h) |
Очищення прямокутника (заповнення поточними кольорами) |
fillRect(x,y,w,h) |
Вивід прямокутника, заповненого поточними кольорами. |
fillRoundRect(x,y,w,h,arcWidth,arcHeight) |
Вивід округленого прямокутника, заповненого поточними кольорами. |
fill3DRect(x,y,w,h, isRaised) |
Вивід “об'ємного” прямокутника, заповненого поточними кольорами. Якщо змінна isRaised ==true, він “опуклий” (raised), інакше - “втиснений”. |
fillPolygon(Polygon p) fillPolygon(int[] xPoints, int[] yPoints, int nPoints) |
Вивід багатокутника, заповненого поточними кольорами. |
fillOval(x,y,w,h) |
Вивід еліпса, заповненого поточними кольорами. |
fillArc(x,y,w,h,startAngle,arcAngle) |
Вивід сектора еліпса, заповненої поточними кольорами. Заповнюється сектор, обмежений відрізками із центра еліпса в кінці дуги, і самою дугою. |
copyArea(x,y,w,h,dx,dy) |
Копіювання області на нове місце, зрушене від старого на dx,dy |
Вивід текстової інформації |
|
drawString(s,x,y) |
Вивід рядка s |
drawChars(char[] data,int offset,int length,int x,int y) |
Вивід масиву символів |
drawBytes(byte[] data,int offset,int length,int x,int y) |
Вивід символів, представлених як послідовність байт |
Керування областю виводу |
|
setClip(x,y,w,h) setClip(Shape clip) |
Установка нових границь області виводу. Поза цією областю при виводі графічних примітивів вони усікаються (не виводяться). |
clipRect(x,y,w,h) |
Звуження області виводу. |
Rectangle getClipBounds() Rectangle getClipBounds(Rectangle r) |
Повертає параметри прямокутника, у який уписана область виводу. |
Graphics create() |
g1=g.create()- створення копії графічного об'єкта g |
dispose() |
Деструктор - знищення графічного об'єкта з одночасним вивільненням ресурсів (без очікування, коли це зробить збирач сміття). |
Приклад методу, що працює із графікою.
java.awt.Graphics g,g1;
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {
java.awt.Graphics g,g1;
g=jPanel1.getGraphics();
int x1=20,x2=120,y1=20,y2=120;
int x3=20,y3=20,w3=60,h3=80;
int x4=30,y4=60,w4=30,h4=40;
int x0=10,y0=10,w0=10,h0=10;
int w1=80,h1=120;
g.setClip(0,0,60,80);//границі області виводу
g.drawLine(x1,y1,x2,y2);//лінія
g.drawOval(x3,y3,w3,h3);//еліпс
g.clipRect(x4,y4,20,20);//звуження області виводу
g.clearRect(x4,y4,w4,h4);//очищення прямокутника
g.setClip(0,0,200,280); //нові границі області виводу
g.copyArea(x1,y1,w1,h1,60,0);
g.draw3DRect(10,20,w1,h1,false);
g.drawPolygon(new java.awt.Polygon(new int[]{10,10,20,40},
new int[]{10,20,30,60},4) );
}
У випадку спроби такого використання виникає проблема: при перемальовуванні графічного контексту все виведене зображення зникає. А перемальовування викликається автоматично при зміні розміру вікна додатка, а також його відновленні після мінімізації або перекриття іншим вікном.
Для того щоб результати виводу не пропадали, у класі додатка потрібно перевизначити метод paint, викликуваний при отрисовке. Код цього методу може виглядати так:
public void paint(java.awt.Graphics g){
super.paint(g);
g=jPanel1.getGraphics();
... - команди графічного виводу
}
Правда, при зміні розміру вікна додатка цей код не спрацює, і для панелі треба буде призначити оброблювач
private void jPanel1ComponentResized (java.awt.event.ComponentEvent evt) {
... - команди графічного виводу
}
У випадку отрисовки з оброблювача якої-небудь події зміни графічного контексту не відбувається до закінчення оброблювача. Це принципова особливість роботи з ідеології оброблювачів подій - поки не скінчиться один оброблювач, що випливає не починається. Для дострокової отрисовки безпосередньо під час виконання оброблювача події служить виклик методу update(Graphics g). Приклад:
for(int i=0;i<=100;i++){
FiguresUtil.moveFigureBy(figure,dx,dy);
update(g);
};
При роботі зі статичними зображеннями викладених алгоритмів цілком достатньо. Однак при використанні елементів, що рухаються, у багатьох графічних системах виникає мельтешение, пов'язане з постійними перемальовуваннями. У цих випадках звичайно застосовують ідеологію подвійний буферизации: отрисовку елементів по невидимому буферному зображенню, а потім показ цього зображення в якості видимого. А те зображення, що було видиме, при цьому стає невидимим буфером.