Операции над объектами. Операция присваивания объектов. Операции сравнения объектов

Операции над объектами. Операция присваивания объектов. Операции сравнения объектов


Содержание



1. Какие операции можно применять над объектами в языке программирования Java?

Язык программирования Java предоставляет широкий спектр операций, которые можно применять для примитивных типов данных и для объектов.

Для объектов можно применять следующие операции:

  • присваивание =;
  • сравнение на равенство ==;
  • сравнение на неравенство !=.

2. Каким образом работает операция присваивания объектов =? Общая форма

Операция присваивания объектов имеет следующую общую форму

obj1 = obj2;

где

  • obj1, obj2 – ссылка на объекты, которые имеют одинаковый тип (класс). При присваивании объектов значение ссылки на объект obj2 присваивается ссылке obj1. Фактически, присваиваются только ссылки, то есть копируется ссылка из одного места в другое. После выполнения присваивания, обе ссылки ссылаются на один и тот же участок памяти (объект).

3. Какое отличие между присваиванием (=) переменных примитивных типов и присваиванием объектов?

Отличие между присваиванием переменных примитивных типов и объектов состоит в следующем:

  • при присваивании переменных примитивных типов копируется значение одной переменной в другую. При этом переменные размещаются в разных участках памяти. Изменение значения одной переменной не приведет к изменению значения другой переменной;
  • при присваивании объектов, копируется только ссылка на объект а не значение этого объекта. То есть, после выполнения присваивания объектов, ссылки на эти объекты указывают на один и тот же участок памяти. После присваивания, изменение данных объекта по одной ссылке приведет к изменению данных объекта по другой ссылке, поскольку ссылки на объекты ссылаются на один и тот же участок памяти.

4. Какие ошибки могут возникнуть при присваивании ссылок на объекты?

Если при выполнении присваивания ссылка на объект в левой части указывала на некоторый ранее выделенный участок памяти (оператором new), то этот участок может быть потерян если нету копии этой ссылки. После присваивания получить информацию о данных из этого участка будет невозможно. Позже этот участок будет автоматически очищен «сборщиком мусора».

5. Примеры использования оператора присваивания = для присваивания объектов классов

Пример 1. Пусть задан класс с именем SomeClass

// некоторый класс
class SomeClass {
    // внутренние данные класса
    int d;
    float f;
    char c;

    // конструктор класса
    SomeClass(int d, float f, char c) {
        this.d = d;
        this.f = f;
        this.c = c;
    }
}

Ниже демонстрируется присваивание объектов этого класса и демонстрация доступа к одному и тому же участку памяти:

// создание объекта obj1
SomeClass obj1 = new SomeClass(5, 3.8f, 'z');

// объявление объекта obj2 класса SomeClass, для которого не выделена память
SomeClass obj2 = null;

// присваивание ссылок на объекты
obj2 = obj1; // ссылки на объекты ссылаются на один и тот же участок памяти

int d = obj2.d; // d = 5
d = obj1.d; // d = 5

float f = obj2.f; // f = 3.8
f = obj1.f; // f = 3.8

char c = obj2.c; // c = 'z'
c = obj1.c; // c = 'z'

obj1.d = 280;
d = obj2.d; // d = 280

obj2.f = 7.777f;
f = obj1.f; // f = 7.777

Пример 2. Сортировка массива объектов методом вставки. В примере демонстрируется обмен между ссылками на объект типа Data.

Задан класс Data, содержащий одну внутреннюю переменную value и объяснение message к ней типа String. Реализовать сортировку данных по убыванию значения value методом вставки.

Реализация класса Data следующая:

// объявление класса Data
class Data {
    // данные класса
    int value;
    String message;

    // метод, устанавливающий новые значения во внутренних переменных класса
    void Set(int val, String msg) {
        value = val;
        message = msg;
    }
}

Использование массива объектов типа Data может быть, например, следующим

// объявление массива объектов
Data[] D = new Data[10]; // выделение памяти для массива типа Data целиком
Data tmp; // дополнительная ссылка типа Data

// выделение памяти для каждого объекта массива Data
for (int i=0; i<D.length; i++)
    D[i] = new Data();

// заполнение массива произвольными значениями
D[0].value = 5;
D[0].message = "value = 5";
D[1].value = 3;
D[1].message = "value = 3";
D[2].value = 7;
D[2].message = "value = 7";
D[3].value = 8;
D[3].message = "value=8";
D[4].value = 9;
D[4].message = "value => 9";
D[5].value = 10;
D[5].message = "value = 10";
D[6].value = 4;
D[6].message = "value = 4";
D[7].value = 6;
D[7].message = "value => 6 ";
D[8].value = 7;
D[8].message = "value = 7";
D[9].value = 2;
D[9].message = "value = two";

// сортировка массива в порядке убывания
for (int i=0; i<D.length-1; i++)
    for (int j=i; j>=0; j--)
        if (D[j].value<D[j+1].value) {
            // обмен местами - обмениваются только ссылки на объект
            tmp = D[j]; // используется дополнительная ссылка tmp
            D[j] = D[j+1];
            D[j+1] = tmp;
        }

// Вывод массива
for (int i=0; i<D.length; i++)
    System.out.println("D["+i+"]: value = " + D[i].value + "; message " + D[i].message);

Как видно из вышеприведенного примера, между объектами D[j] и D[j+1] осуществляется обмен ссылками на объект класса, а не значениями данных этих объектов. Использование ссылок при таком обмене есть эффективным в случае когда экземпляр класса (объект) содержит большое количество данных. Ведь обмен двух ссылок выполняется намного быстрее чем обмен всех данных класса.

На экран будет выведен следующий результат:

D[0]: value = 10; message value = 10
D[1]: value = 9; message value => 9
D[2]: value = 8; message value=8
D[3]: value = 7; message value = 7
D[4]: value = 7; message value = 7
D[5]: value = 6; message value => 6
D[6]: value = 5; message value = 5
D[7]: value = 4; message value = 4
D[8]: value = 3; message value = 3
D[9]: value = 2; message value = two

Если реализовать обмен данными в классе, то следующий код цикла сортировки будет выполняться дольше чем предыдущий:

// этот код выполняется медленнее
String msg;
int val;

for (int i=0; i<D.length-1; i++)
    for (int j=i; j>=0; j--)
        if (D[j].value<D[j+1].value) {
            // обмен местами данных объектов - выполняется медленнее
            val = D[j].value;
            D[j].value = D[j+1].value;
            D[j+1].value = val;
            msg = D[j].message;
            D[j].message = D[j+1].message;
            D[j+1].message = msg;
        }

6. Можно ли присваивать объекты разных классов?

Нет, нельзя. При присваивании объектов разных классов компилятор Java выдает ошибку с сообщением:

Type mismatch: cannot convert from SomeClass to SomeClass2

7. Каким образом работает операция присваивания объектов, содержащих вложенные объекты?

При присваивании одного объекта другому присваивается значение ссылки. На объект, объявленный в классе, операция присваивания никак не влияет.

8. Операция сравнения объектов ==. Пример

При сравнении объектов сравниваются значения ссылок. Результат сравнения true, если ссылки имеют одинаковые значения, то есть они ссылаются на один и один и тот же объект.

Пусть задан класс DayWeek, реализующий день недели

// класс день недели
class DayWeek {
    int day;

    DayWeek(int day) {
        if ((day>=1)&&(day<=7))
        this.day = day;
    }
}

В нижеследующем примере происходит сравнение объектов класса типа DayWeek. Результат true устанавливается только тогда, когда значения ссылок на объекты класса равны между собой.

DayWeek dw = new DayWeek(5);
DayWeek dw2= null;
boolean b;

b = dw==dw2; // b = false
dw2 = dw;    // dw2 и dw равны между собой
b = dw==dw2; // b = true

// объявление ссылок на разные участки памяти
DayWeek dw3 = new DayWeek(3);
DayWeek dw4 = new DayWeek(3);

if (dw3==dw4)
    b = true;
else
    b = false; // b = false

9. Операция сравнения объектов !=. Пример

Операция != (не равно) возвращает false в случае, когда значение ссылок на объекты класса различны между собой. Операция работает точно также как и операция сравнения на равенство == объектов класса.

Пусть дан класс Circle, реализующий окружность на координатной плоскости

// класс, реализующий окружность
class Circle {
    double x, y;
    double radius;

    // конструктор
    Circle() {
        radius = 1;
        x = y = 0;
    }
}

Ниже демонстрируется использование операции != для сравнения объектов

// объявление объектов класса Circle
Circle c1 = new Circle(); // c1 - ссылка на объект класса Circle
Circle c2 = new Circle(); // c2 - ссылка на объект класса Circle
c2.radius = 2.5;

boolean b;
b = c1!=c2; // b = true: ссылки c1 и c2 имеют разные значения
c2 = c1;
b = c1!=c2; // b = false: ссылки c1, c2 имеют одинаковые значения


Связанные темы