class Base{ int a,b; void show(){
System.out.println(a+":"+b);} }
class Test{
void f(int x,int y){
x*=2;
y/=2;
System.out.println(x+":"+y);}
void f(Base obj){
obj.a*=2;
obj.b/=2;
System.out.println(obj.a+":"+obj.b);}
}
class TestDemo{
public static void main(String args[]){
Base obj=new Base();
Test tstFunc=new Test();
obj.a=10;
obj.b=200;
tstFunc.f(obj.a,obj.b);
obj.show();
tstFunc.f(obj);
obj.show();}
}
В классе Baseимеются два целочисленных поля a и b, а также метод show(), предназначенный для отображения значений этих полей.
В классе Test описан перегруженный метод f(). У метода два варианта: с двумя аргументами типа int и с одним аргументом-объектом класса Base. В первом случае при выполнении метода f() его первый аргумент умножается на два, а второй делится на два. Затем выводится сообщение с парой значений первого и второго аргументов (после внесения в них изменений). Во втором варианте метода та же процедура проделывается с полями объекта, указанного аргументом метода: первое поле объекта умножается на два, а второе делится на два, и новые значения полей выводятся в сообщении.
В главном методе программы в классе TestDemo создаются два объекта: объект obj класса Base и объект tstFunc класса Test. Командами obj.a=10 и obj.b=200 полям объекта obj присваиваются значения, после чего командой tstFunc.f(obj.a,obj.b) вызывается вариант метода f(), аргументами которого указаны поля объекта obj. В результате, как и следовало ожидать, появляется сообщение 20:100. Однако если проверить значения полей объекта obj с помощью команды obj.show(), то мы получим сообщение 10:200, означающее, что значения полей не изменились. Причина в том, что хотя объект передается аргументом по ссылке, целочисленные поля объекта — это переменные базового типа, поэтому передаются по значению. По этой причине при вызове метода f() изменялись копии этих полей, а сами поля не изменились.
После выполнения команды tstFunc.f(obj) мы снова получаем сообщение 20:100. Такое же сообщение мы получаем при выполнении команды obj.show(). Следовательно, поля объекта изменились. В данном случае это вполне ожидаемо: аргументом методу передавался объект, а объекты передаются по ссылке, поэтому все вносимые изменения сказываются на самом объекте.
Примеры программ
Бинарное дерево
Рассмотрим программу, в которой на основе конструкторов класса создается бинарное дерево объектов — каждый объект имеет по две ссылки на объекты того же класса. Пример учебный, поэтому ситуация упрощена до предела. Каждый объект, кроме прочего, имеет три поля. Символьное (типа char) поле Level определяет уровень объекта: например, в вершине иерархии находится объект уровня A, который ссылается на два объекта уровня B, которые, в свою очередь, ссылаются в общей сложности на четыре объекта уровня C и т. д. Объекты нумеруются, для чего используется целочисленное поле Number. Нумерация выполняется в пределах одного уровня. Например, на верхнем уровне A всего один объект с номером 1. На втором уровне B два объекта с номерами 1 и 2. На третьем уровне C четыре объекта с номерами от 1 до 4 включительно и т. д. Описанная структура объектов представлена на рис. 5.2.
Рис. 5.2. Структура бинарного дерева объектов
Кроме метки уровня и номера объекта на уровне, каждый объект имеет еще и свой «идентификационный код». Этот код генерируется случайным образом при создании объекта и состоит по умолчанию из восьми цифр (количество цифр в коде определяется закрытым статическим целочисленным полем IDnum). Что касается самого кода, то он записывается в целочисленный массив, на который ссылается переменная массива ID — закрытое поле класса ObjectTree (листинг 5.13). Каждая цифра кода записывается отдельным элементом соответствующего массива. Для генерирования (создания) кода объекта используется метод getID(). Для этого в теле метода командой ID[i]=(int)(Math.random()*10) в рамках цикла генерируются случайные целые числа (инструкцией (int)(Math. random()*10)) и записываются в качестве значений элементов массива ID.
Для вывода кода объекта используется закрытый метод showID(). Методом последовательно выводятся на экран элементы массива ID, при этом в качестве разделителя используется вертикальная черта. Сам метод вызывается в методе show(), который, в свою очередь, предназначен для отображения параметров объекта: уровня объекта в структуре, порядкового номера объекта на уровне и идентификационного кода объекта.
Открытые поля FirstRef и SecondRef являются объектными переменными класса ObjectTree и предназначены для записи ссылок на объекты следующего уровня. Присваивание значений этим переменным выполняется при вызове конструктора класса. Обратимся к листингу 5.13.