Ключевое слово this
Ключевое слово this является стандартной ссылкой на объект, из которого вызывается метод. При этом следует учесть, что в Java ссылка на объект фактически является именем этого объекта. Хотя наличие такой ссылки может на первый взгляд показаться излишним, она достаточно часто используется на практике. Условно можно выделить два типа ситуаций, когда может потребоваться ссылка this: если она реально необходима и если благодаря ей улучшается читабельность программного кода. Примеры первого типа приводятся в последующих главах книги — для их понимания необходимо сначала познакомиться с особенностями выполнения ссылок на объекты, способами передачи аргументов методам и механизмом возвращения методом объекта в качестве результата. Здесь же мы приведем примеры использования ключевого слова this в «косметических» целях.
В рассматривавшихся ранее примерах ссылки на члены класса в теле методов этого же класса выполнялись простым указанием имени соответствующего члена. Если для класса создается объект и из этого объекта вызывается метод, то обращение к члену класса в программном коде метода означает обращение к соответствующему члену объекта. В то же время обращение к полям и методам объекта выполняется в «точечном» синтаксисе, то есть указывается имя объекта, точка и затем имя поля или метода. Для упомянутой ситуации это означает, что в методе объекта выполняется обращение к члену того же объекта. Этот замечательный факт можно отразить в программном коде метода в явном виде с помощью ссылки this. Пример приведен в листинге 4.5.
Листинг 4.5. Использование ссылки this
class MyClass{
// Поля класса:
double Re,Im;
void set(double Re,double Im){
// Использование ссылки this:
this.Re=Re;
this.Im=Im;}
void get(){
// Инструкция перехода на новую строку \n:
System.out.println("Значения полей:\nRe="+this.Re+" и Im="+this.Im);}
}
class ThisDemo{
public static void main(String[] args){
MyClass obj=new MyClass();
obj.set(1,5);
obj.get();}
}
В данном случае класс MyClass содержит всего два поля Re и Im типа double. Кстати, обращаем внимание, что оба поля объявлены одной инструкцией, в которой указан тип полей, а сами поля перечислены через запятую. Данный класс является очень слабой аналогией реализации комплексных чисел, у которых есть действительная (поле Re) и мнимая (поле Im) части.
Кроме двух полей, у класса имеется два метода: метод set() для присваивания значений полям и метод get() для отображения значений полей. У метода set() два аргумента типа double, причем их названия совпадают с названиями полей класса. Разумеется, в таком экстремизме необходимости нет, вполне можно было предложить иные названия для аргументов, но мы не ищем простых путей, поэтому сложившаяся ситуация далеко не однозначна. Если в теле метода set() использовать обращение Re или Im, то это будет ссылка на аргумент метода, а не на поле класса, поскольку в случае совпадения имен переменных приоритет имеет локальная переменная (то есть объявленная в блоке, в котором находится инструкция вызова переменных с совпадающими именами). Из ситуации выходим, воспользовавшись ссылкой this. Так, инструкции this.Re и this.Im означают поле Re и поле Im соответственно объекта this, то есть того объекта, из которого вызывается метод set() . При этом инструкции Re и Im являются обращениями к аргументам метода. Поэтому, например, команду this. Re=Re следует понимать так: полю Re объекта this (объекта, из которого вызывается метод set() ) присвоить значение аргумента Re, то есть первого аргумента, переданного методу set() при вызове. Хотя описанная ситуация вполне оправдывает использование ссылки this, все же такой прием считается несколько искусственным, поскольку в запасе всегда остается возможность просто поменять названия аргументов.
Совсем неоправданным представляется использование ссылки this в программном коде метода get() , который выводит сообщение со значениями полей объекта. В данном случае инструкции вида this.Re и this.Im можно заменить простыми обращениями Re и Im соответственно — функциональность кода не изменится. У метода аргументов нет вообще, поэтому никаких неоднозначностей не возникает. По большому счету, обращение к полю класса (или методу) по имени является упрощенной формой ссылки this (без применения самого ключевого слова this). Этой особенностью синтаксиса языка Java мы пользовались ранее и будем пользоваться в дальнейшем. Тем не менее в некоторых случаях указание ссылки this даже в «косметических» целях представляется оправданным.
Обращаем внимание на инструкцию перехода на новую строку \n в текстовом аргументе метода println() в теле метода get() . Эта инструкция включена непосредственно в текст и ее наличие приводит к тому, что в месте размещения инструкции при выводе текста выполняется переход на новую строку. Поэтому в результате выполнения программы получим сообщение из двух строк:
Значения полей:
Re=1.0 и Im=5.0
Как уже отмечалось, это далеко не единственный способ использования инструкции this. Далее в книге есть и другие примеры.
Внутренние классы
Внутренний класс — это класс, объявленный внутри другого класса. Эту ситуацию не следует путать с использованием в качестве поля класса объекта другого класса. Здесь речь идет о том, что в рамках кода тела класса содержится описание другого класса, который и называется внутренним. Класс, в котором объявлен внутренний класс, называется внешним. В принципе, внутренний класс может быть статическим, но такие классы используются на практике крайне редко, поэтому рассматривать мы их не будем, а ограничимся только нестатическими внутренними классами.
Внутренний класс имеет несколько особенностей. Во-первых, члены внутреннего класса доступны только в пределах внутреннего класса и недоступны во внешнем классе (даже если они открытые). Во-вторых, во внутреннем классе можно обращаться к членам внешнего класса напрямую. Наконец, объявлять внутренние классы можно в любом блоке внешнего класса. Пример использования внутреннего класса приведен в листинге 4.6.
Листинг 4.6. Использование внутреннего класса
class MyOuter{
// Поле внешнего класса:
int number=123;
// Метод внешнего класса:
void show(){
// Создание объекта внутреннего класса:
MyInner InnerObj=new MyInner();
// Вызов метода объекта внутреннего класса:
InnerObj.display();}
// Внутренний класс:
class MyInner{
// Метод внутреннего класса: void display(){
System.out.println("Поле number="+number);}
}
}
class InnerDemo{
public static void main(String args[]){
// Создание объекта внешнего класса:
MyOuter OuterObj=new MyOuter();
// Вызов метода объекта внешнего класса:
OuterObj.show();}
}
В программе описаны три класса: внешний класс MyOuter, описанный в нем внутренний класс MyInner, а также класс InnerDemo. В классе InnerDemo описан метод main() , в котором создается объект внешнего класса MyOuter и вызывается метод этого класса show() .
Структура программы следующая: во внешнем классе MyOuter объявляется поле number, метод show() и описывается внутренний класс MyInner. У внутреннего класса есть метод display() , который вызывается из метода внешнего класса show() . Для вызова метода display() в методе show() создается объект внутреннего класса InnerObj. Причина в том, что вызывать метод display() напрямую нельзя — члены внутреннего класса во внешнем классе недоступны.
В методе display() выводится сообщение со значением поля внешнего класса number. Поскольку во внутреннем классе допускается непосредственное обращение к членам внешнего класса, обращение к полю number выполняется простым указанием его имени.
В результате выполнения программы получаем сообщение: Поле number=123
Отметим, что в главном методе программы можно создать объект внешнего класса, но нельзя создать объект внутреннего класса — за пределами внешнего класса внутренний класс недоступен.
Анонимные объекты
Как уже отмечалось, при создании объектов с помощью оператора new возвращается ссылка на вновь созданный объект. Прелесть ситуации состоит в том, что эту ссылку не обязательно присваивать в качестве значения переменной. В таких случаях создается анонимный объект. Другими словами, объект есть, а переменной, которая бы содержала ссылку на этот объект, нет. С практической точки зрения такая возможность представляется сомнительной, но это только на первый взгляд. На самом деле анонимные объекты требуются довольно часто — обычно в тех ситуациях, когда единожды используется единственный объект класса. Достаточно простой пример применения анонимного объекта приведен в листинге 4.7.
Листинг 4.7. Анонимный объект
class MyClass{
void show(String msg){
System.out.println(msg);}
}
class NamelessDemo{
public static void main(String args[]){
// Использование анонимного объекта:
new MyClass().show("Этот объект не имеет имени");}
}
В классе MyClass описан всего один метод show() с текстовым аргументом. Текстовый аргумент — это объект встроенного Java-класса String. Действие метода состоит в том, что на экран выводится текст, переданный аргументом метода.
В методе main() класса NamelessDemo всего одна команда, которая и демонстрирует применение анонимного объекта:
new MyClass().show("Этот объект не имеет имени")
Эту команду можно условно разбить на две части. Инструкцией new MyClass() создается новый объект класса MyClass, а сама инструкция в качестве значения возвращает ссылку на созданный объект. Поскольку ссылка никакой переменной в качестве значения не присваивается, созданный объект является анонимным. Однако это все равно объект класса MyClass, поэтому у него есть метод show() . Именно этот метод вызывается с аргументом "Этот объект не имеет имени". Для этого после инструкции new MyClass() ставится точка и имя метода с нужным аргументом.
Это далеко не единственный способ применения анонимных объектов. В следующей главе приводятся примеры использования анонимных объектов при работе с конструкторами.
Дата добавления: 2016-06-13; просмотров: 1575;