Материалы занятий

21бщую информацию о курсе см. на странице Общая информация.

Неделя 2016-02-08


1 Пишем "Hello World"

  1. На диске D: (или E:) создать папку со своей фамилией (желательно - латиницей и без пробелов).
  2. С помощью ярлыка на рабочем столе запустить DrJava.
  3. Найти в учебнике (или интернете), как пишется программа "hello world" на java.
  4. Внимательно проанализировать ее структуру и попытаться понять каждый элемент (наверняка там же есть описание + можно спросить у преподавателя).
  5. Запастись терпением и руками закодить ее в DrJava. Сохранить ее в своей папке, назвав файл так же, как класс (только с расширением .java).
  6. Скомпилировать и запустить, проверить, что все работает, как надо.

2 Регистрируемся в системе тестирования Ejudge

1 Заходим на ejudge.litvinov.in.ua, выбираем контест №9 (Лабы 2 семестр ООП (Java)).

2 Т.к. у нас нет аккаунта - нажимаем "Create account", вводим желаемый логин и свою настоящую почту. На почту придет письмо с паролем.

3 Перейдя по ссылке из письма и успешно залогинившись, нажимаем [Confirm registration].

4 Чтобы вас можно было идентифицирвать, как реального студента ХНУ, жмем на Edit ("General information [Edit]") - и вводим в поле "Team name" свою фамилию и имя (именно в таком порядке) на русском языке. Нажимаем сохранить.

 

5 (неудобный, но важный, шаг) Возвращаемся на страницу выбора контеста, выбираем контест №11 (Практика 2 семестр ООП (Java)).

6 Повторяем шаги 3-4 еще раз (логин и пароль вводить те же).

7 Нажимаем "Participate" и видим список "пре-лаб" - заданий на 1 балл, предназначенных для первичного ознакомления с темой соответствующей лабораторной работы.

8 При желании - меняем пароль на какой-нибудь более привычный.

3 Отправка программы на тестирование

1 Прочитайте условие задачи "1_pre". Обратите внимание на примеры входных и выходных данных, а также на поля "Time limit" и "Memory limit". В будущем они нам понадобятся.

2 Найдите в интернете, как считать с клавиатуры 2 числа, сложить их и вывести на экран. Запрос в гугле "java a+b" вполне подойдет.

3 В DrJava создайте новый файл и закодьте эту программу (тот из вариантов, где используется Scanner, а не InputStreamReader).

4 Если хотите чтобы после занятия в голове остались какие-то знания, не используйте Ctrl+c, Ctrl+v! Попытайтесь понять, зачем нужна каждая из строк этой программы!

5 Протестируйте свою программу (в DrJava) на данных из примера, который приведен в условии задачи.

6 Когда заработает, помогите соседу (устно!).

7 На странице задачи в ejudge выберите файл с исходным кодом программы (.java). Send!

8 Когда в таблице внизу экрана появится слово "Compiling", не ждите, что оно само исчезнет - жмите F5, чтобы обновить страницу.

9 Далее будет либо OK, либо "Compilation error".

10 В обоих случаях жмите на "view report":


11 Разберитесь, что означают ссылки "I", "O", "A", "E", "C".
12 Сделайте одну корректную отправку, одну с ошибкой компиляции и одну с неправильным результатом.
13 Покажите преподавателю результаты своей работы (программы и протоколы их тестирования), расскажите о смысле ссылок "I", "O", "A", "E", "C", покажите, как вы тестировали свою программу на примере входных/выходных данных из условия задачи и получите 1 балл за работу на занятии.

Д/з

  1. Настроить у себя дома среду разработки. Проверить, что работает "Hello, world". Скачать книги Хорстманна, Шилдта и Эккеля - выбрать из них более понятную (детали).
  2. Разобрать по учебнику ту часть Java, которая перескается с Паскалем. Попрактиковаться на примерах программ из учебника.
  3. Л.р.№1 еще не "задана" - но она может служить хорошим "указателем", какие темы из учебника вам пригодятся в первую очередь. Подробнее см. ВАЖНЫЕ пояснения к заданиям на лабы. Условие л.р.1 и отправка ее на проверку тут: http://ejudge.litvinov.in.ua/cgi-bin/new-register?contest_id=9.
  4. Если у вас не получается практиковаться в программировании по примерам из учебника - вот набор конкретных задач постепенно возрастающей сложности: http://ejudge.litvinov.in.ua/cgi-bin/new-register?contest_id=13

Неделя 2016-02-15


1 Выводы по предыдущему занятию

  • Ваша программа - это, собственно, файл с расширением .java - его и надо отправлять на проверку, приносить с собой на флешке из дому и т.п.
  • Программа, отправляемая на проверку на сервер (ejudge), не должна выводить на экран ничего лишнего: например, приглашений для ввода данных ("Введите a и b:"...).
  • В настройках ejudge обязательно надо указать свою настоящую фамилию и имя - чтобы потом от своего имени сдавать лабы.

2 Простые и ссылочные типы данных

В Java есть восемь простых ("primitive") типов данных: byte, short, int, long, float, double, boolean, char. Подробнее

Все остальные типы (т.е. массивы и классы) коструируются на их основе и являются ссылочными.

Ссылки в Java на 90% аналогичны указателям в Си или Паскале.

В случае простых типов:

  • переменная хранит непосредственно данные;
  • операция присваивания (=) изменяет сами данные в переменной;
  • операция сравнения (==) сравнивает непосредственно данные.

В случае ссылочных типов (сравните с указателями!):

  • переменная хранит ссылку на данные;
  • операция присваивания (=) заставляет переменную ссылаться на другие данные, старые данные при этом становятся недоступными ;
  • операция сравнения (==) сравнивает ссылки.

Также ссылочная переменная может хранить "пустое значение" - ссылку null:

Пример 1: простые типы

int a = 3;
int b = 5;
 
int c = a;

Вопрос: чему теперь равно a? b? c?

Ответ (выделить текст мышкой!): 3, 5, 3.

a = 0;

Вопрос: чему теперь равно a? b? c?

Ответ (выделить текст мышкой!): 0, 5, 3.

Пример 2: ссылочные типы

Проведем маленький эксперимент с классом java.util.Date (см. справку) (это ссылочный тип, и он инкапсулирует в себе некоторый момент во времени (день и время).

Проведите описанный ниже эксперимент в окне взаимодействий (Interactions) DrJava!


(это тоже вводить)
Date d2 = new Date();

Вопрос: чему равно d2? Объясните причину отличия от d1.

Date d3 = d1;

Вопрос: чему теперь равно d1? d2? d3? - проверьте.

Вопрос: проверьте истинность условий d1==d2, d1==d3 и d2==d3.

Теперь изменим d1 с помощью методов getTime()/setTime():

Вопрос: что означает полученное число 1455371904485?

Вопрос: проверьте, какое число теперь выдаст метод getTime() при вызове его на объекте d1; какая получится дата, если вызвать setTime(1000) (и почему)?


Теперь самый главный вопрос: чему равно d3? Проверьте!

(было)

(стало)

Почему?

Сделайте сами

  1. Создайте два объекта класса Date: d1 и d2. Сделайте обоим setTime(1000). Убедитесь, что они стали одинаковыми. Проверьте, что выдаст проверка d1==d2. Почему?
  2. Объявите, но не ицициализируйте ссылочную переменную типа Date: Date d; (без =new) - каково будет ее содержимое? Что если те же действия провести над обычным int'ом? Почему результат отличается?
  3. Создайте массив из нескольких элементов и "скормите" его функции System.out.println(). Что появилось на экране? Как вы думаете - почему?
  4. Подумайте (и попробуйте), как создать два объекта Date так, чтобы записанные в них времена отличались на 1 час.

Неделя 2016-02-22


1 Теория

Когда вы разрабатываете приложние на Java, вы создаете его в виде набора текстовых файлов с расширением .java. Каждый такой файл содержит определение ровно одного класса (если быть более точным - одного public-класса).

Далее, компилятор (javac.exe) превращает каждый ваш .java-файл в .class-файл с тем же именем. Этот файл содержит скомпилированный (в байт-код Java-машины) код вашего класса.

При запуске вы указатываете имя главного класса (т.к. классов, содержащих функцию main, может быть несколько). После этого Java-машина ищет в текущей директории указанный класс (а также все классы, от которых он зависит - например, класс Scanner), загружает его в память и запускает функцию main.

Помимо текущей папки, классы также ищутся по адресам, указанным в параметре CLASSPATH (задается либо переменной окружения CLASSPATH, либо через параметр "-cp" командной строки). Если класс принадлежит какому-либо пакету (например java.util), то он ищется в папках, структура вложенности которых повторяет структуру вложенности пакетов (в нашем примере это папка java/util).

2 Основы работы в командной строке

См. также тут.

  • Запуск интерпретатора команд осуществляется путем ввода команды "cmd" в окне "Выполнить..." (нажмите windows+R).
  • Путь к текущей директории ("папке") отображается в самой нижней строке.
  • Посмотреть ее содержимое - комана "dir" (от слова directory).
  • Зайти в дочернюю папку - команда "cd имя_папки" (от слов change directory).
  • Перейти в папку на уровень выше - "cd .." (две точки друг за другом).
  • Перейти на другой диск - "буква:".
  • Перейти в "корень" текущего диска - "cd \".
  • Запустить программу - "имя_программы параметр1 параметр2" (exe-шка программы ищется в текущей директории, а также по путям из переменной окружения PATH).
  • Очистить экран - "cls".
  • Создать директорию - "md имя", удалить файл - "del имя".

3 Ручная компиляция и запуск "Hello, world"

  1. javac имя_файла
  2. java имя_класса
  3. Подробнее см. http://docs.oracle.com/javase/tutorial/getStarted/cupojava/win32.html

Задание

Создайте в текстовом редакторе файл с программой "Hello, world", откомпилируйте и запустите его из командной строки.

Примечание: пожалуйста, сделайте это в своей папке на диске D.

Разберитесь с основными командами cmd, почитайте про переменные окружения PATH и CLASSPATH (и какое они имеют отношение к виртуальной машине Java!).

Неделя 2016-02-29


1 Три кита ООП

 Инкапсуляция     Наследование
 Полиморфизм
  • "студент тоже человек" (множество студентов - это подмножество людей);
  • наследник = предок + свои поля и методы => занимает больше памяти;
  • наследник может менять унаследованное поведение путем переопределения ("замещения" - overriding) методов.
  • наследник всегда может быть подставлен на место предка (т.к. "студент тоже человек").
  • "кнопки на видеомагнитофоне";
  • возможность взаимодействовать с объектом, не зная его точный тип.

  1. Инкапсуляция - "код и данные вместе".
  2. Наследование - "студент тоже человек".
  3. Полиморфизм - возможность взаимодействовать с объектом, не зная его точного типа ("кнопки на видеомагнитофоне").

2 Из чего состоит класс

public class Stakan{
    private float масса;                       // 1 поля
    private float объем;

    public Stakan(){                           // 2а конструктор по умолчанию
        инициализировать поля "дефолтными" значениями;
    }

    public Stakan(float m, float v){           //2b конструктор с параметрами
        явно инициализировать поля;
    }

    public float getMass(){...}                // 3 setter'ы и getter'ы
    public boolean setMass(float m){...}

    public void print(){                       // 4 операции с объектом. Самая популярная - print()
        распечатать информацию на экране в определенном формате
    }
}
...в main():
Stakan a = new Stakan();
Stakan b = new Stakan(20, 200);
Stakan[] m = new Stakan[n];
for(int i=0; i<m.length; i++){
    m[i] = new Stakan();
}
a.print();
b.setMass(b.getMass() - 10);
и т.п...

3 Как тестируются классы в Ejudge

  • От вас требуется не программа - а класс. Т.е. функцию main() можно не писать (когда она бывает нужна - это явно оговорено в задании).
  • Разные функции main() автоматически "пристыковываются" к вашему классу и тестируют его.
  • Строго соблюдайте формат вывода: один лишний пробел, одна маленькая буква вместо большой - и тест не пройден.
  • Всегда объявляйте главный класс как "public class". Если классов несколько - поместите их все в один файл, но только один класс объявите как public.
Задание
Класс Stakan (задание 2_pre).

Неделя 2016-03-07


1 "Резиновый массив"

"Резиновый массив", или - в простонаречии - вектор - структура данных, в которой n однотипных элементов хранятся непосредственно друг за другом (без пропусков) в памяти, и котоая автоматически расширяется при добавлении новых элементов.

Поддерживает 3 основные операции:

  • прочитать элемент в заданной позиции;
  • поменять (существующий!) элемент в заданной позиции;
  • добавить новый элемент в заданную позицию (со сдвигом остальных элементов вправо);
  • удалить элемент в заданной позиции (со сдвигом остальных элементов влево).

Типичная реализация (только операция добавления в конец):

static double[] arr = new double[10];

static int size = 0;            // изначально - пусто

static void add(double val){

    if(еще есть место){

        arr[size] = val;

        size++;

    }else{

        создать новый массив в 2 раза больше

        скопировать в него элементы

        присвоить ссылку на него "старому" массиву arr

        теперь место есть, и можно добавлять элемент так же, как показано выше в части if(){...}

    }

}

2 Assert

Правило хорошего тона - обнаруживать ошибку как можно раньше после ее возникновения. Поэтому, если ваш метод предъявляет определенные требования к своим входным данным и/или состоянию объекта - пропишите в первых его строках проверку диагностических утверждений.

См. также http://prog-school.ru/2010/03/zashhitnoe-programmirovanie-kak-pravilno и http://habrahabr.ru/post/191548/.

Важно! Чтобы assert'ы не игнорировались java-машиной, включите их с помощью опции "-ea": java -ea MyClass. В DrJava assert'ы включены по умолчанию. Eclipse - зайдите в меню Run->Run/Debug Config->Arguments->VM Arguments и добавьте опцию "-ea".

Замечание: тут может возникнуть одна проблема - с текущей версией языка. Ее решение см:
http://www.cis.upenn.edu/~matuszek/cit594-2004/Pages/eclipse-faq.html#assert

Задание

3_pre на ejudge. Чтобы упростить себе задачу - сделайте все поля и методы статическими (как main).

Неделя 2016-03-14


1 Наследование

public class Point{

    private double x=0, y=0;            // можно инициализировать поля в конструкторе, можно - здесь

    public Point(double x, double y){...}

    public void print(){}

}

public class Point3d extends Point{

    private double z=0;                // x и y у нас уже есть!

    public Point3d(double x, double y, double z){

        super(x, y);                    // вызов конструктора из суперкласса!

        инициализировать z

    }

    public void print(){...}            // переопределение!

}

..в main():

    Point p1 = new Point(11, 22);
        p1.print();                        // -> (11.0, 22.0)
    Point3d p2 = new Point3d(33, 44, 55);
        p2.print();                        // -> (33.0, 44.0, 55.0)

    // подстановка!
    Point p3 = new Point3d(66, 66, 66);
        p3.print();                        // что будет на экране?

Выводы

  1. Класс-наследник содержит все то же, что и суперкласс - плюс что-то свое.
  2. Следовательно, объект класса-наследника занимает больше места в памяти.
  3. Два способа "расширения" класса - добавление (полей и методов) и замещение (переопределение, overriding) методов.
  4. Конструкторы вызываются в порядке наследования (super).
  5. Студент является человеком, Point3d является точкой - значит ссылка на Point может ссылаться на объект Point3d! (восходящее преобразование)

2 Л.р.4


Задание: 4_pre

Неделя 2016-03-21


1 Забытая тема: операторы

В чем разница между операторами '&&' и '&'? Между операторами '||' и '|'?

Логические операторы
Побитовые операторы
  • оперируют с булевыми значениями;
  • пример: (x > 0) && (x < 5);
  • a || b // где a и b - boolean;
  • с целыми не работают!
 
  • оперируют с целыми числами;
  • пример: 6 | 5 // что получится?
  • a & b  // где a и b - целые;
  • с логическими не работают!

Также побитовые операторы совпадают по записи с "несокращенными" логическими операторами: такими, что в выражении 2==3 & 3/0==1 выдадут exception.

Задание:

  1. В окне "interactions" DrJava проверьте примеры выражений, приведенные в таблице выше.
  2. Попробуйте в этих примерах заменить логические операторы побитовыми и наоборот. В каком сдучае сработало, а в каком нет?
  3. Для объяснения результатов п.2 почитайте про сокращенное вычисление логических выражений: http://developer.alexanderklimov.ru/android/java/logic_operators.php и попробуйте вычислить 2==3 & 3/0==1, исползуя && и &. Объясните результат.
  4. Протестируйте программу из туториала от Sun: http://docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
  5. Найдите в туториале описание всех побитовых операций в Java. Объясните преподавателю, в чем их суть.
  6. Если есть время - поэкспериментируйте с операторами битовой инверсии и сдвига (с положительными и отрицательными числами, на разных типах данных).

2 Защищаем л.р.3,4.

Неделя 2016-03-28


1 Наследование реализации и композиция

Цели наследования:

  1. Наследование реализации (закрытое) - в Java не бывает! - чтобы 2-ой раз не писать тот же код.
  2. Наследование интерфейса (открытое) - чтобы работал принцип подстановки (наследник на место родителя).
Наследование Композиция + делегирование
public void push(double val){
    super.insert(val, super.getSize());
}
public void push(double val){
    v.insert(val, v.getSize());
}

2 Является ли квадрат прямоугольником

Допустим, квадрат поддерживает все операции из класса прямоугольник.

=> значит можно сделать setWidth(1) и setHeight(2)

=> значит это не квадрат

--

квадрат - это НЕ прямоугольник!

Задание (5_pre):


...
public void setSide(double s){
    r.width=s;
    r.height=s;
}
public double getArea(){
    return r.getArea();            // делегирование!
}
...

Неделя 2016-04-04


Полиморфизм

Полиморфизм - это возможность взаимодействия с объектом без знания его конкретного типа.

Но для этого нам нужна гарантия, что объект поддерживает все нужные нам операции:

public interface Container{

    void put(double val);

    double get();

}

class Stack implements Container{...}

class Queue implements Container{...}

После чего мы можем полиморфно вызывать методы этих классов:

1)

Container c = new Stack();

c.put(); c.put();        // 1,2

c.get(); c.get();        // 2,1

2)

void saveData(Container c){...c.put(...);...}        // 1 Тут мы НЕ ЗНАЕМ, вызываем ли мы метод из Stack или из Queue! (см. 2)

...в main():

Container c;

if(...)                                              // 2 Тут уже знаем. Но это становится известно на этапе ВЫПОЛНЕНИЯ, а НЕ компиляции.

    c = new Stack();

else

    c = new Queue();

saveData(c);

Полиморфный вызов - это вызов метода, при котором информация о том, какой именно метод (из нескольких) будет вызван, недоступна на этапе компиляции.

Позднее связывание - механизм, используемый компилятором для выбора одного из нескольких вызываемых методов по ходу выполнения программы, когда необходимая для этого информация недоступна на этапе компиляции.

Еще примеры:

http://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html

http://ermak.cs.nstu.ru/cprog/HTML/114.htm (примечание: в Java все функции - всегда виртуальные, но не все вызовы полиморфные)

Задание: 6_pre

Неделя 2016-05-02


Вложенные (nested) и внутренние (inner) классы


..main():
Vector.Iterator = new Vector.Iterator();
(или - обычно - new Vector.Iterator(v))
 ..main():
Vector v = new Vector();                    // нужен объект!
Vector.Iterator i = v.new Iterator();      // new "в контексте" объекта v

Локальный внутренний класс

Это класс внутри функции - он виден только внутри этой функции, а объекты его также содержат неявную ссылку на объект "внешнего" класса.

Безымянный:

ActionListener obj = new ActionListener(){

    public void actionPerformed(ActionEvent e) {
         System.out.println("Меня нажали");

    }

}

someButton.addActionListener(obj);

Методы локальныого внутреннего класса имеют доступ к локальным переменным вмещающей этот класс функции (но только final - см. в Хорстманне почему!).

Задание: 7_pre. Подробнее: см. Хорстманн и Java Tutorials.

Comments