Как изменить несколько ссылок одновременно в Java? - PullRequest
2 голосов
/ 28 августа 2011

У меня есть массив, содержащий ссылки для объектов. Я хочу изменить некоторые из этих ссылок в массиве на другой объект. На данный момент я использую цикл for, как показано ниже:

for (int i = region2.getStartPos(); i <= curPos; i++) {        
    if (regions[i] == region2) {
        regions[i] = region1;
    }
}

Я хочу избежать цикла for, потому что это увеличивает вычислительную сложность.

Есть ли способ сделать объект, на который ссылается region2, равным объекту region1 напрямую? Например, я попытался написать метод в классе Region, подобный приведенному ниже, но он дает мне сообщение «невозможно присвоить значение конечной переменной this».

public void mergeRegions(Region region){
    this = region;
}

Возможно ли что-то подобное?

Ответы [ 3 ]

1 голос
/ 28 августа 2011

Каждая ссылка в Java - это просто адрес какого-то объекта в памяти, поэтому требуемые «автоматические обновления» невозможны без дополнительного кода.

Представьте, что region1 ссылается на адрес 0x1001 в памяти, а region2 ссылается на 0x2001. Эти две области памяти содержат фактические данные региона:

  • 0x1001: x = 0, y = 5, width = 20, height = 30
  • 0x2001: x = 100, y = 200, width = 50, height = 20

Если бы вы могли как-то сказать, что объект в 0x2001 равен 0x1001, используя ваш mergeRegions метод, попытается ли Java сделать что-то подобное?

  • 0x1001: x = 0, y = 5, width = 20, height = 30
  • 0x2001: 0x1001

Это не сработает, потому что оба объекта Java должны быть Region объектами, каждый с одинаковыми полями и методами. Если мы уничтожим объект Java на 0x2001 и просто введем простой адрес, ни одна из существующих ссылок на 0x2001 не будет работать, потому что все они ожидают объект Region по этому адресу. Вот почему вы не можете "напрямую назначить" одну ссылку Java другой.

Вот три подсказки, которые помогут вам изменить ваш алгоритм:

  1. Вместо копирования адреса 0x1001 в 0x2001, вы можете скопировать все данные из 0x1001 в объект в 0x2001. Это сделает оба объекта эквивалентными, но разделенными.
  2. Вы можете ввести один уровень косвенности. Если вы знаете C, подумайте «указатели на указатели». Ваш массив regions будет содержать ссылки на IndirectRegion объекты, которые, в свою очередь, будут содержать ссылки на реальные Region объекты. Если вы хотите обновить region2 до region1, вам нужно только попросить один из IndirectRegion объектов обновить его внутреннюю ссылку.
  3. Дождитесь окончания вашего алгоритма, прежде чем объединять регионы. Если вам удастся собрать все операции слияния, вы сможете выполнить их все в одном цикле O (n).
0 голосов
/ 28 августа 2011

Для чего вы используете массив? Предложения Амира и Дана об обмене содержимым или использовании косвенного обращения также пришли мне на ум. Но у меня есть ощущение, что, возможно, вам следует изменить структуру данных. Не могли бы вы рассказать подробнее об использовании вашего массива?

Например, если у вас есть только несколько областей, n, то, возможно, вместо использования массива объектов регионов, вы можете использовать n наборов целых чисел и использовать операции над множествами, такие как объединение, пересечение и дополнение или замена множеств. Или вам больше не нужны целые числа, но вы можете использовать EnumSets или EnumMaps.

Если у вас есть книга Джоша Блоха "Эффективная Java", взгляните на пункт 25 о массивах и пункт 32/33 о EnumSets / EnumMaps.

0 голосов
/ 28 августа 2011

Вы не можете сделать это, потому что это нарушит контракт того, как этот объект может вести себя с другими вызывающими. Ваш первый цикл - лучшее, что вы можете сделать. Лучшее решение может состоять в том, чтобы не использовать массив и вместо этого использовать то, что имеет доступ O (1). Например, Set<T>. Вы могли бы что-то вроде

set.remove(region2);
set.add(region1);

Что будет очень быстро, если вы написали, .equals() и .hashcode()

Другое решение - скопировать все из одного класса в другой. Я не уверен, что я чувствую по этому поводу и если это даже безопасно. Но вы можете сделать что-то вроде.

public void mergeRegions(Region region){
    this.a=region.a;
    this.b=region.b;
    this.c=region.c;
    this.d=region.d;
}
...