инкапсуляции, следствием чего может быть нарушение корректности информации, как это показано ниже:
//Пример №7. Использование класса public class Runner {
public static void main(String[] args) { Coin ob = new Coin();
ob.diameter = -0.12; // некорректно: прямой доступ ob.setWeight(100);
// ob.weight = -150; // поле недоступно: compile error
}
}
Чтобы компиляция оператора:
ob.diameter = -0.12; // некорректно: прямой доступ
стала невозможной, следует поле diameter класса Coin объявить с атрибутом доступа private:
private double diameter;
Тогда строка с попыткой прямого присваивания значения поля с помощью ссылки на объект приведет к ошибке компиляции, что не позволит сохранять в поле класса некорректные данные.
//Пример №8. Использование класса package by.bsuir.java.first; class Coin {
private double diameter; // правильная инкапсуляция private double weight; // правильная инкапсуляция public double getDiameter() {
return diameter;
}
public void setDiameter(double value) { if (value > 0) diameter = value;
else System.out.println("Oтрицательный диаметр!");
}
// правильное имя метода getWeight вместо имени takeWeight public double getWeight() {
return weight;
}
public void setWeight(double weight) { this.weight = weight;
}
}
16
Проверка корректности входящей извне информации осуществляется в методе setDiameter() и позволяет уведомить о нарушении инициализации объекта.
//Пример №9. Использование объектов класса Coin package by.bsuir.java.first;
class Coin {
private double diameter; // правильная инкапсуляция private double weight; // правильная инкапсуляция public double getDiameter() {
return diameter;
}
public void setDiameter(double value) { if (value > 0) diameter = value;
else System.out.println("Oтрицательный диаметр!");
}
// правильное имя метода getWeight вместо имени takeWeight public double getWeight() {
return weight;
}
public void setWeight(double weight) { this.weight = weight;
}
}
class CompareCoin {
public void compareDiameter(Coin first, Coin second) { double delta = first.getDiameter() -
second.getDiameter(); if (delta > 0) {
System.out.println("Первая монета больше второй на "
+delta);
}else if (delta == 0) {
System.out.println("Монеты имеют одинаковый
диаметр");
} else {
System.out.println("Вторая монета больше первой на "
+ -delta);
}
}
}
public class Runner {
public static void main(String[] args) { Coin coin1 = new Coin();
coin1.setDiameter(-0.11);//сообщение о неверных данных coin1.setDiameter(0.12); // корректная установка поля coin1.setWeight(150);
Coin coin2 = new Coin(); coin2.setDiameter(0.21); coin2.setWeight(170);
CompareCoin compareCoin = new CompareCoin();
17
compareCoin.compareDiameter(coin1, coin2);
}
}
Компиляция и выполнение данного кода приведут к выводу на консоль следующей информации:
Объект класса создается за два шага. Сначала объявляется ссылка на объект класса. Затем с помощью оператора new создается экземпляр объекта, например:
Coin coin1;// объявление ссылки
coin1 = new Coin();// создание объекта
Однако эти два действия обычно объединяют в одно:
Coin coin1 = new Coin();/*объявление ссылки и создание объекта*/
Оператор new вызывает конструктор, в данном примере конструктор по умолчанию без параметров, но в круглых скобках могут размещаться аргументы, передаваемые конструктору, если у класса объявлен конструктор с параметрами. Операция присваивания для объектов означает, что две ссылки будут указывать на один и тот же участок памяти.
Метод compareDiameter() выполняет два действия, которые следует разделять: выполняет сравнение и выводит ответ. Действия слишком различны по природе, чтобы быть совмещенными. Естественным решением будет изменить возвращаемое значение метода на int и оставить в нем только вычисления.
public int compareDiameter(Coin first, Coin second) { int result = 0;
double delta = first.getDiameter() - second.getDiameter(); if (delta > 0) result = 1;
else if (delta < 0) result = -1; return result;
}
Формирование отчета следует поместить в другой метод другого класса.
ОБЪЕКТНЫЕ ССЫЛКИ
Java работает не с объектами, а со ссылками на объекты. Это объясняет то, что операции сравнения ссылок на объекты не имеют смысла, так как при этом сравниваются адреса. Для сравнения объектов на эквивалентность по
18
значению необходимо использовать специальные методы, например, boolean equals(Object obj). Этот метод наследует каждый класс от суперкласса Object, который находится в корне дерева иерархии всех классов. Метод equals() должен переопределяться в каждом классе для определения эквивалентности содержимого двух объектов этого класса.
//Пример №10. Использование переменных типа String package by.bsuir.java.first;
class ComparisonStrings {
public static void main(String[] args) { String s1, s2;
s1 = "Java";
s2 = s1; //две переменные ссылаются на строку "Java"
System.out.println("сравнение ссылок " + (s1 == s2));
// создание нового объекта
s2 = new String("Java");//эквивалентно s2=new String(s1);
System.out.println("сравнение ссылок " + (s1 == s2)); System.out.println("сравнение значений " +
s1.equals(s2));
}
}
В результате выполнения действия s2 = s1 получается, что обе ссылки ссылаются на один и тот же объект. Оператор «==» возвращает true при сравнении ссылок только в том случае, если они ссылаются на один и тот же объект.
Результаты работы программы:
Если же ссылку инициализировать при помощи конструктора s2 = new String(s1), то создается новый объект в другом участке памяти, который инициализируется значением, взятым у объекта s1. В итоге существуют две ссылки, каждая из которых независимо ссылается на свой объект, который никак физически не связан другим объектом. Поэтому оператор сравнения ссылок возвращает результат false, так как ссылки ссылаются на различные участки памяти. Объекты обладают одинаковыми значениями, что легко определяется вызовом метода equals().
Если в процессе разработки возникает необходимость в сравнении по значению объектов классов, созданных программистом, то для этого следует переопределить в классе метод boolean equals(Object obj) в соответствии с теми критериями сравнения, которые существуют для объектов данного типа или по стандартным правилам, заданным в документации.
19
ВЗАИМОДЕЙСТВИЕ С КОНСОЛЬЮ
Консоль определяется программой, предоставляющей интерфейс командной строки для интерактивного обмена текстовыми командами и сообщениями с операционной системой или программным обеспечением.
Взаимодействие с консолью с помощью потока System.in представляет собой один из простейших способов передачи информации в приложение. Рассмотрим ввод информации в виде символа из потока ввода, связанного с консолью, и последующего вывода на консоль символа и его числового кода.
//Пример №11. Взаимодействие с консолью package by.bsuir.java.first;
class ReadCharRunner {
public static void main(String[] args) { int x;
try {
System.out.println("Введите символ: "); x = System.in.read();
char c = (char) x;
System.out.println("Код символа: " + c + " = " + x); } catch (java.io.IOException e) {
System.err.println("ошибка ввода " + e);
}
}
}
Результат работы программы:
Обработка исключительной ситуации IOException, которая может возникнуть в операциях ввода/вывода и в любых других взаимодействиях с внешними устройствами, осуществляется в методе main() с помощью реализации блока try-catch. Если ошибок при выполнении не возникает, то выполняется полностью блок try{}, в противном случае генерируется исключительная ситуация, и выполнение программы перехватывает блок catch{}.
Ввод блока информации осуществляется посредством чтения строки с консоли с помощью возможностей объекта класса Scanner, имеющего возможность соединяться практически с любым источником информации: строкой, файлом, сокетом, адресом в Интернете, с любым объектом, из которого можно получить ссылку на поток ввода.
//Пример №12. Использование класса Scanner package by.bsuir.java.first;
import java.util.Scanner; class RunScanner {
20