Клонирование объектов. “Сборка мусора” и освобождение ресурсов.




Объекты в методы передаются по ссылке, в результате чего в метод передается ссылка на объект, находящийся вне метода. Поэтому если в методе изменить значение поля объекта, то это изменение коснется исходного объекта. Во избежание такой ситуации для защиты внешнего объекта следует создать клон (копию) объекта в методе. Класс Object содержит protected-метод clone(), осуществляющий побитовое копирование объекта производного класса. Однако сначала необходимо переопределить метод clone() как public для обеспечения возможности вызова из другого пакета. В переопределенном методе следует вызвать базовую версию метода super.clone(), которая и выполняет собственно клонирование. Чтобы окончательно сделать объект клонируемым, класс должен реализовать интерфейс Cloneable. его реализация гарантирует, что метод clone() класса Object возвратит точную копию вызвавшего его объекта с воспроизведением значений всех его полей. В противном случае метод генерирует исключение CloneNotSupportedException.

* пример # 13: класс, поддерживающий клонирование: Student.java */

package chapt04;

public class Student implements Cloneable {/*включение

интерфейса */

private int id = 71;

public int getId() {

return id;

}

public void setId(int value) {

id = value;

}

public Object clone() {//переопределение метода

try {

return super.clone();//вызов базового метода

} catch (CloneNotSupportedException e) {

throw new AssertionError("невозможно!");

} } }

“Сборка мусора” и освобождение ресурсов

Автоматическое освобождение памяти, занимаемой объектом, выполняется с помощью механизма “сборки мусора”. Когда никаких ссылок на объект не существует, то есть все ссылки на него вышли из области видимости программы, предполагается, что объект больше не нужен, и память, занятая объектом, может быть освобождена. “Сборка мусора” происходит нерегулярно во время выполнения программы. Форсировать “сборку мусора” невозможно, можно лишь “рекомендовать” ее выполнить вызовом метода System.gc() или Runtime.getRuntime().gc(), но виртуальная машина выполнит очистку памяти тогда, когда сама посчитает это удобным. Вызов метода System.runFinalization() приведет к запуску метода finalize() для объектов утративших все ссылки.

Иногда объекту нужно выполнять некоторые действия перед освобождением памяти. Например, освободить внешние ресурсы. Для обработки таких ситуаций могут применяться два способа: конструкция try-finally и механизм finalization.

Конструкция try-finally является предпочтительной, абсолютно надежной.Запуск механизма finalization определяется алгоритмом сборки мусора и до его непосредственного исполнения может пройти сколь угодно много времени. Внутри метода finalize(), вызываемого непосредственно перед освобождением памяти, следует определить действия, которые должны быть выполнены до уничтожения объекта.

Метод finalize() имеет следующую сигнатуру:

protected void finalize(){ // код завершения }

Метод finalize() вызывается только перед самой “сборкой мусора”, а не тогда, когда объект выходит из области видимости, то есть заранее невозможно определить, когда finalize() будет выполнен, и недоступный объект может занимать память довольно долго.

 

Интерфейсы

Интерфейсы подобны полностью абстрактным классам, но не являются классами. Ни один из объявленных методов не может быть реализован внутри интерфейса. В языке Java существуют два вида интерфейсов:

· интерфейсы, определяющие контракт для классов посредством методов,

· интерфейсы, реализация которых автоматически (без реализации методов) придает классу определенные свойства.(Cloneable и Serializable, отвечающие за клонирование и сохранение объекта в информационном потоке соответственно)

Все объявленные в интерфейсе методы автоматически трактуются как public и abstract, а все поля – как public, static и final, даже если они так не объявлены. Класс может реализовывать любое число интерфейсов, указываемых через запятую после ключевого слова implements, дополняющего определение класса.

Определение интерфейса имеет вид:

[public] interface Имя [extends Имя1, Имя2,…, ИмяN] { /*реализация интерфейса*/}

/* пример # 1: объявление интерфейсов: LineGroup.java, Shape.java */

package chapt06;

public interface LineGroup {

// по умолчанию public abstract

double getPerimeter();// объявление метода }

 

package chapt06;

public interface Shape extends LineGroup {

//int id; // ошибка, если нет инициализации

//void method(){} /* ошибка, так как абстрактный метод не может иметь тела! */

double getSquare(); // объявление метода }

Интерфейсы обычно объявляются как public, потому что описание функциональности, предоставляемое ими, может быть использовано в нескольких пакетах проекта. Интерфейсы с областью видимости в рамках пакета могут использоваться только в этом пакете и нигде более.

Реализация интерфейсов классом может иметь вид:

[доступ] class ИмяКласса implements Имя1, Имя2,…, ИмяN { /*код класса*/}

Класс, который реализует интерфейс, должен предоставить полную реализацию всех методов, объявленных в интерфейсе. Кроме этого, данный класс может объявлять свои собственные методы. Если класс расширяет интерфейс, но полностью не реализует его методы, то этот класс должен быть объявлен как abstract.

/* пример # 2: реализация интерфейса: Rectangle.java */

package chapt06;

public class Rectangle implements Shape {

private double a, b;

public Rectangle(double a, double b) {

this.a = a;

this.b = b;

} //реализация метода из интерфейса

public double getSquare() {//площадь прямоугольника

return a * b;

} //реализация метода из интерфейса

public double getPerimeter() {

return 2 * (a + b); } }

Статический импорт.

Константы и статические методы класса можно использовать без указания принадлежности к классу, если применить статический импорт, как это показано в следующем примере.

// пример # 10: статический импорт: ImportDemo.java

package chapt06;

import static java.lang.Math.*;

public class ImportDemo {

public static void main(String[] args) {

double radius = 3;

System.out.println(2 * PI * radius);

System.out.println(floor(cos(PI/3))); } }

Если необходимо получить доступ только к одной константе класса или интерфейса, например Math.E, то статический импорт производится в следующем виде:

import static java.lang.Math.E;

import static java.lang.Math.cos;//для одного метода

 



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-02-16 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: