№1. Особенности реализации основных фундаментальных свойств ООП в Java.
Особенности языка Java
-
Основан на синтаксисе С
-
Развитая система типов («абстракция», «инкапсуляция», «типизация»)
-
Одиночное наследование классов и множественное наследование интерфейсов («иерархия»)
-
Развитая система пакетов («модульность»)
-
Обработка исключений
-
Автоматическая сборка мусора
-
Обеспечение конкурентного доступа к данным при многопоточности («параллелизм»)
-
Отсутствие низкоуровневого управления памятью
-
Развитая библиотека (с поддержкой «сохраняемости»)
Принципы Java
-
Простота; Безопасность; Переносимость, независимость от архитектуры; ООП; Многопоточность; Высокая производительность; Распределенность; Динамичность (reflection)
№2.Классы и объекты.
Класс – это шаблон для объекта. Объект – это экземпляр класса. Данные класса называются переменными экземпляра. Каждый объект содержит собственную копию этих переменных. Метод предназначен для обработки данных.
Понятие и определение класса
-
class classname {
-
type instance-variable1;
-
type instance-variable2;
-
// …
-
type instance-variableN;
-
type methodname1 (parameter-list) {
-
// тело метода
-
}
-
type methodname2 (parameter-list) {
-
// тело метода
-
}
-
//…
-
type methodnameN(parameter-list) {
-
// тело метода
-
}
}
Членами класса могут быть: поля; методы; внутренние типы (классов и интерфейсов; конструкторы; инициализаторы; статические инициализаторы.
Классы о объекты
Получение объектов класса − это двухшаговый процесс.
Во-первых, нужно объявить переменную типа «класс». Она не определяет объект. Это просто переменная, которая может ссылаться на объект. Во-вторых, нужно получить актуальную, физическую копию объекта и назначать ее этой переменной. Это можно сделать с помощью операции new. Операция new распределяет динамически (т.е. во время выполнения) память для объекта и возвращает ссылку на нее. Данная ссылка является адресом ячейки памяти, выделенной объекту вышеуказанной операцией. Затем эта ссылка сохраняется в переменной. Таким образом, в Java все объекты класса должны быть распределены динамически.
№3.Динамическая инициализация объектов.
Операция new распределяет динамически (т.е. во время выполнения) память для объекта и возвращает ссылку на нее. Данная ссылка является адресом ячейки памяти, выделенной объекту вышеуказанной операцией. Затем эта ссылка сохраняется в переменной. Таким образом, в Java все объекты класса должны быть распределены динамически.
№4. Модификаторы класса.
-
public – класс доступен для использования, наследования вне зависимости от пакета или от каталога; public-классы должны храниться в файлах с именем имя_класса.java.
-
friendly – модификатор класса по умолчанию, если модификатор не определен явно для класса. Такой класс доступен только для объектов, находящихся в том же пакете. Вне пакета он выступает как private.
-
final – класс не может быть наследован, т.е. иметь подклассов.
-
abstract – класс, в котором объявлен хотя бы один абстрактный метод. Для таких классов нельзя создавать объекты. Такие классы используются для производных классов, а также для организации стандартизированных интерфейсов.
№5. Ограничения доступа к элементам класса
Атрибут |
Разрешенный доступ |
Отсутствие атрибута доступа |
Из любого класса в том же пакете |
public |
Из любого класса откуда угодно |
private |
Никакого доступа вне класса |
protected |
Из любого класса в том же пакете и из любого подкласса где угодно |
№6. Методы класса, конструкторы.
Создание класса: свойства и методы
Рассмотрим пример создания простейшего класса. Давайте с его помощью смоделируем окружности на координатной плоскости. Каждая такая окружность, как известно, будет определяться своим центром (т.е. точкой с двумя числовыми координатами) и радиусом (т.е. его длиной, представляемой в виде числа). Таким образом, окружность на координатной плоскости характеризуют 3 вещественных числа. Значит в нашем классе должно быть три соответствующих свойства. Пока не будем пытаться решать серьёзных задач с помощью класса, а наделим его следующими возможностями: созданную на основе класса окружность должно быть возможно выводить на экран (в виде описания её характеристик), перемещать (т.е. совершать преобразование движения, меняя координаты её центра) и масштабировать (т.е. совершать преобразование подобия, меняя радиус окружности).
// описываем отдельный новый класс
class Circle {
// свойства класса
public double x; // абсцисса центра
public double y; // ордината центра
public double r; // радиус
// методы класса
// выводит на экран параметры окружности
public void printCircle() {
System.out.println("Окружность с центром ("+x+";"+y+") и радиусом "+r);
}
// перемещает центр, движение окружности
public void moveCircle(double a, double b) {
x = x + a;
y = y + b;
}
// масштабируем, выполняем преобразование подобия с коэффициентом k
public void zoomCircle(double k) {
r = r * k;
}
}
// описываем основной класс, содержащий метод main
public class Main {
public static void main(String[] args) {
// Создаём объект (окружность класса Circle), у неё будет нулевой
// радиус и центр в (0.0;0.0), поскольку все свойства получат
// значения по умолчанию
Circle o1 = new Circle();
// выводим на экран параметры окружности
o1.printCircle();
// Меняем абсциссу центра, обращааясь к свойству x
o1.x = 3;
// Меняем радиус, обращааясь к свойству r
o1.r = 12.3;
// выводим на экран обновлённые параметры окружности
o1.printCircle();
// Создаём другой объект того же класса
Circle o2 = new Circle();
o2.r = 3.14;
o2.zoomCircle(1.66);
o2.printCircle(); // Окружность с центром (0.0;0.0) и радиусом 5.2124
}
}
Конструкторы
Когда мы создаём объект командой Circle o1 = new Circle(); используется так называемый конструктор по умолчанию (или конструктор без параметров) — это специальный метод класса, мы его не определяли явно, но даже если его не определить он создаётся автоматически, выполняется при создании каждого нового объекта и присваивает первоначальные значения его свойствам (инициализирует их). Значения по умолчанию для свойств зависят от их типа (0 или 0.0 для чиловых типов, false для логического типа и т.д.). Конструктор по умолчанию можно описать явно и при этом задать начальные значения для свойств нового объекта, отличные от значений по умолчанию. От остальных методов конструктор отличается тем, что имеет то же самое имя, что и весь класс, а также не имеет типа возвращаемого значения (по сути, в результате своей работы конструктор возвращает новый объект нужного класса).
class Circle {
public double x; // абсцисса центра
public double y; // ордината центра
public double r; // радиус
public void printCircle() {
System.out.println("Окружность с центром ("+x+";"+y+") и радиусом "+r);
}
public void moveCircle(double a, double b) {
x = x + a;
y = y + b;
}
public void zoomCircle(double k) {
r = r * k;
}
// конструктор по умолчанию, теперь сразу после создания объекта будем
// получать окружность единичного радиуса с центром в начале координат
public Circle() {
x = 0.0;
y = 0.0;
r = 1.0;
}
}
public class Main {
public static void main(String[] args) {
Circle o1 = new Circle();
o1.printCircle(); // Окружность с центром (0.0;0.0) и радиусом 1.0
}
}
Поскольку методы можно перегружать, а конструктор является методом, то с помощью перегрузки можно создать дополнительные варианты конструкторов. Например, удобно иметь конструктор, который позволит при создании объекта явно указывать координаты его центра и длину радиуса.
Описать подобный конструктор можно в дополнение к основному следующим образом:
public Circle(double a, double b, double s) {
x = a;
y = b;
r = s;
}
Теперь при создании объектов можно пользоваться любым конструктором на выбор:
Circle o1 = new Circle();
o1.printCircle(); // Окружность с центром (0.0;0.0) и радиусом 1.0
Circle o2 = new Circle(1,-1,14);
o2.printCircle(); // Окружность с центром (1.0;-1.0) и радиусом 14.0
Нужно учитывать следующий факт: если в классе описан явно хотя бы один конструктор с параметрами, то конструктор по умолчанию (без параметров) создаваться автоматические уже не будет (его в такой ситуации надо описывать явно). Хотя, если вам требуется только конструктор с параметрами (как второй из нашего примера), то можно обойтись и совсем без конструктора по умолчанию (описать в классе только один конструктор с параметрами).
Доступ к членам класса из тела методов
Добавим в наш класс метод, вычисляющий площадь той окружности, к которой метод применён. Метод будет описывать так:
public double squareCircle() {
double s = Math.PI * r * r;
return s;
}
Результат работы метода можно увидеть следующим образом:
System.out.println("Площадь круга o2: "+o2.squareCircle()); //615.75...
№7. Основы наследования: понятие суперкласса и подкласса, организация связей при наследовании.
-
Чтобы наследовать класс, нужно просто включить определение одного класса в другое, используя ключевое слово extends. Например
class SubClass extends SuperClass
{//тело класса SubClass
}
Членами класса могут быть: поля (данные); методы; внутренние типы (классов и интерфейсов); конструкторы; инициализаторы; статические инициализаторы.
Основы наследования: Наследование позволяет создавать иерархические классификации; Используя наследование, можно создать главный класс, который определяет свойства, общие для набора связанных элементов; Класс, который унаследован, называется суперклассом (superclass); Класс, который выполняет наследование, называется подклассом (subclass) — это специализированная версия суперкласса; Подкласс наследует все переменные экземпляра и методы, определенные суперклассом, и прибавляет свои собственные уникальные элементы.
№8. Модификаторы ограничения доступа к элементам при наследовании.
Атрибут |
Разрешенный доступ |
Отсутствие атрибута доступа |
Из любого класса в том же пакете |
public |
Из любого класса откуда угодно |
private |
Никакого доступа вне класса |
protected |
Из любого класса в том же пакете и из любого подкласса где угодно |
№9. Перегрузка, переопределение методов и их применение.
Переопределение и перегрузка (override и overload)
Ранее мы посмотрели пример того, как можно добавлять функциональность к классу путем его расширения (наследования). Но в класс можно не только добавлять новые возможности путем создания новых методов. Методы класса можно также переопределять - сделать override. Или перегрузить - сделать overload. Давайте попробуем разобраться что означает каждый термин.
Переопределение (override)
Переопределение использутеся тогда, когда вы переписываете (переделываете, переопределяете) УЖЕ сещуствующий метод. Например в классе Object есть очень популярный метод toString(), который возвращает строковое представление объекта. В реализации Object результат достаточно страшненький - имя класса с какими-то цифрами (это так называемы хэш-код).
ublic class Robot
{
}
public class RobotManager
{
public static void main(String[] args) {
Robot robot = new Robot();
System.out.println(robot.toString());
}
}
Перегрузка (overload)
Перегрузка метода заключается в следующем - вы создаете метод с таким же именем, но с другим набором параметров. Например, в классе может быть несколько методов с названием summa, но с разным набором парметров.
public double summa(double x1, double x2) {
return x1 + x2;
}
public double summa(double x1, double x2, double x3) {
return x1 + x2 + x3;
}
public double summa(double x1, double x2, double x3, double x4) {
return x1 + x2 + x3 + x4;
}
№10. Использование ключевого слова final при наследовании.
Запрет наследования или переопределения с помощью ключевого слова final
Если нужно запретить переопределение (overriding) метода во всех порожденных классах, то этот метод можно описать как final. Кроме того, ключевое слово final может применяться к классам. Это означает, что данный класс не может быть унаследован другим классом.
Множественное наследование интерфейсов
Интерфейсы допускают множественное наследование. Один класс при этом может удовлетворять нескольким интерфейсам сразу. В этом состоит серьезное отличие интерфейсов от обычных классов и от абстрактных классов. Интерфейсы не порождают проблем с множественным наследованием, поскольку они не содержат полей.
После этого может следовать ключевое слово extends и список интерфейсов, от которых будет наследоваться объявляемый интерфейс. Родительских типов может быть много, главное, чтобы не было повторений, и чтобы отношение наследования не образовывало циклической зависимости.Наследование интерфейсов действительно очень гибкое. Так, если есть два интерфейса A и B, причем B наследуется от A, то новый интерфейс C может наследоваться от них обоих. Указание наследования от A является избыточным, все элементы этого интерфейса и так будут получены по наследству через интерфейс B.
№11. Понятие и использование абстрактных классов.
-
Помимо обычных классов, в Java бывают абстрактные классы (abstract class) и интерфейсы (interface).
Абстрактный класс – класс с модификатором abstract.
Абстрактный класс - класс, в котором объявлен хотя бы один абстрактный метод.
Абстрактный класс, как правило, используется в случаях, когда необходимо, чтобы базовый класс представлял только интерфейс для наследуемых классов. В таких случаях нет смысла создавать физические экземпляры некоторой обобщенной (или виртуальной) сущности, обычно размещаемой в верхних уровнях иерархии классов.
Абстрактный
базовый класс Сотрудник (String fio;
int age;
int kvalif;
------------------------------------
abstract int calcSallary(int age,
int kvalif);
Сотрудник: бухгалтер, финансист, Директор – производные классы
№12. Интерфейсы. Определение интерфейсов
-
Интерфейс – ссылочный тип, членами которого являются константы и абстрактные методы.
-
Интерфейс не может быть реализован в виде экземпляра объекта, но его могут реализовывать классы, обеспечивая реализацию его абстрактных методов.
-
Класс может реализовывать один или более интерфейсов, в том смысле, что любой экземпляр класса реализует все абстракные методы, заданные интерфейсом или интерфейсами.
Формальное определение инфтерфейсов
-
модификатор_доступа interface имя_интерфейса{
-
final тип имя_final_переменной 1=значение;
-
…
-
final тип имя_final_переменной N=значение;
-
тип_возвращаемого_значения имя_метода1(список_параметров);
-
…
-
тип_возвращаемого_значения имя_метода1(список_параметров);
-
}
№13. Интерфейсы. Реализация интерфейсов.
Интерфейсы имеют следующие ограничения
-
Модификатор доступа – могут быть только public или не используется (тогда по умолчанию доступен только членам пакета).
-
Методы – все только абстрактные.
-
Поля – final, static.
-
Методы не имеют реализации (тел).
Реализующие данный интерфейс классы отвечают за содержательную реализацию этих методов, т.е. в реализующих классах необходимо реализовать каждый метод интерфейса.
№14. Интерфейсы. Пример применения интерфейсов.
-
interface Figure{
-
final int x=5,y=4;
-
final float P=0, S=0;
-
public float calcPerimeter();
-
public float calcArea();
-
public String printInfo();
}
-
class Circle implements Figure{
-
int r;
-
float f;
-
public float calcPerimeter(){/*тело*/;};
-
public float calcArea(){/*тело*/;}
-
public String printInfo(){/*тело*/;};
-
}
-
class Triangle implements Figure{
-
int a, h;
-
float f;
-
public float calcPerimeter(){/*тело*/;};
-
public float calcArea(){/*тело*/;};
-
public String printInfo(){/*тело*/;};
-
String defineType(){
-
return "TriangleType";};
-
}
-
public class DemoInterface{
-
Figure figure;
-
Circle circle=new Circle();
-
Triangle triangle=new Triangle();
-
float circleperimeter=circle.calcPerimeter();
-
float triangleperimeter=triangle.calcPerimeter();
-
float circlearea=circle.calcArea();
-
float trianglearea=triangle.calcArea();
}
№15. Байтовые и символьные потоки ввода/вывода в Java.
Java-программы выполняют ввод-вывод через потоки. Поток является абстракцией, которая или производит или потребляет информацию. Поток связывается с физическим устройством с помощью системы ввода-вывода. Все потоки ведут себя одинаковым образом, хотя фактически физические устройства, с которыми они связаны, могут сильно различаться. Используя потоки одни и те же классы и методы ввода-вывода можно применять к устройствам любого типа, то есть поток ввода может извлекать много различных видов входных данных: из клавиатуры, из файла, из сетевого разъёма. Поток вывода также может обратиться к консоли, к файлу, к сетевому соединению (сокету). Благодаря потокам программа может выполнить ввод-вывод, не понимая различий между клавиатурой и сетью. Java реализует потоки с помощью иерархии классов, определённых в пакете java.io.
В Java2 определены 2 типа потоков: байтовые и символьные.
-
Байтовые потоки представляют удобные средства для обработки ввода и вывода байтов. Используются при чтении и записи данных в двоичном коде.
-
Символьные потоки представляют удобные средства для обработки ввода и вывода символов. Они используют Unicode и могут быть интернационализированы.
-
Версия Java1.0 не включала символьные потоки и весь ввод-вывод был байтовым. На самом низком уровне весь ввод-вывод всё ёщё байтовый.
№16. Чтение консольного ввода.
Методы классов InputStream/Reader
int read () — возвращает один символ или байт, взятый из входного потока, в виде целого значения типа int; если поток уже закончился, возвращает -1;
int read (byte/char [] buf) — заполняет заранее определенный массив buf символами из входного потока; в классе InputStream массив типа byte[] и заполняется он байтами; метод возвращает фактическое число взятых из потока элементов или -1, если поток уже закончился;
int read (byte/char [] buf, int offset, int len) — заполняет часть символьного или байтового массива buf, начиная с индекса offset, число взятых из потока элементов равно len; метод возвращает фактическое число взятых из потока элементов или -1.
-
import java.io.*;
-
class MethodReadExample{
-
public static void main (String args[]) throws IOEXception {
-
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
-
int i=br.read();
-
System.out.println(“i= ”+(char)i);
-
}
-
}
№17. Запись консольного вывода.