Подтвердить что ты не робот

Всегда ли оправданно иметь объект, который сам по себе является полем?

Всегда ли оправданно иметь объект, который сам по себе является таким полем:

class Thing {

    Thing field;

    public Thing() {
        this.field = this;
    }
}

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

4b9b3361

Ответ 1

Да, хотя это редко. Это используется в JDK для ситуаций, в которых поле может быть this, но оно может и не быть.

Из класса, который реализует Collections.synchronizedCollection(c)

static class SynchronizedCollection<E> implements Collection<E>, Serializable {
    private static final long serialVersionUID = 3053995032091335093L;

    final Collection<E> c;  // Backing Collection
    final Object mutex;     // Object on which to synchronize

    SynchronizedCollection(Collection<E> c) {
        this.c = Objects.requireNonNull(c);
        mutex = this;
    }

    SynchronizedCollection(Collection<E> c, Object mutex) {
        this.c = Objects.requireNonNull(c);
        this.mutex = Objects.requireNonNull(mutex);
    }

В этом случае mutex может быть текущим классом, однако, если эта коллекция получена из существующей синхронизированной коллекции, мьютекс может быть другим. например если вы вызываете Map.values(), а Map - это synchronizedMap, то mutex будет отображать не коллекцию.


Другим примером является Throwable, который по умолчанию указывает на причину по умолчанию.

/**
 * The throwable that caused this throwable to get thrown, or null if this
 * throwable was not caused by another throwable, or if the causative
 * throwable is unknown.  If this field is equal to this throwable itself,
 * it indicates that the cause of this throwable has not yet been
 * initialized.
 *
 * @serial
 * @since 1.4
 */
private Throwable cause = this;

Ответ 2

Я могу представить хотя бы один пример, где это оправдано. например.

У меня есть цепочка сертификатов, где каждая ссылка в цепочке имеет ссылку на ее родителя. В верхней части цепочки последний сертификат подписан сам по себе, поэтому его родитель - это сам.

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

public class Cert {
    public Cert parent;
}

public class SelfSignedCert extends Cert {
    public SelfSignedCert() {
        this.parent = this;
    }
}

Ответ 3

Нет, по-моему, это никогда не оправдано, потому что у каждого объекта неявно уже есть такое поле: this. Разумеется, для объекта имеет смысл иметь поле, которое может иногда, но не всегда, ссылаться на себя (что может быть, например, встречается в циклическом связанном списке), но вопрос касается поля, которое всегда относится к объекту сам по себе.

Я видел код, в котором такое поле используется, чтобы иметь возможность ссылаться на содержащий объект (анонимный) из внутренних классов, но в этом случае это необязательно. Вы можете использовать ContainingClass.this. Например:

class A {
    class B {
        A getParent() {
            return A.this;
        }
    }
}

Ответ 4

Другой пример в JDK - java.lang.Throwable

private Throwable cause = this;

Поле cause может находиться в трех состояниях - не задано; set to null; установить на другое Throwable.

Реализатор использует this для представления состояния unset.

Более читаемая стратегия, вероятно, предназначена для определения сторожевого значения для unset

static Throwable UNSET = new Throwable();

private Throwable cause = UNSET;

конечно, существует рекурсивная зависимость - UNSET.cause=? - это еще одна забавная тема.

Ответ 5

Единственный случай, о котором я могу думать, - это некоторые виды рефакторинга. Чтобы создать пример, объект может быть запущен как набор статических методов, которые не очень объектно-ориентированы:

public static void doItToIt(Foo it) {
  if (it.getType().equals("bar")) {
    it.setSomeVariable(value);
    it.manipulate();
  } else {
    // do nothing
  }
}

... поэтому мы решили избавиться от getType() и сделать это подклассовым отношением, а при рефакторинге вещь была скопирована и вставлена, чтобы сделать код более понятным и объектно-ориентированным, что потребовало:

public class Bar extends Foo {
    private Bar it = this;

    private String getType() {
      return "bar";
    }

    public void doItToIt() {
      if (it.getType().equals("bar")) {
        it.setSomeVariable(value);
        it.manipulate();
      } else {
        // do nothing
      }
    }
 }

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

public void doItToIt() {
  final Bar it = this;
  ...
}

но если их несколько, использование переменной экземпляра заставит код работать быстрее.

Теперь было бы лучше пойти и заменить все экземпляры it на this (и избавиться от getType() и удалить if и т.д.), но в качестве промежуточного шага все еще улучшения, и в противном случае он может остаться в этом состоянии, если есть (или, как полагают, другие), более важные вещи.

Другой возможностью было бы копирование псевдокода из чего-то вроде спецификации, в которой this имеет имя в псевдокоде, и вы намеренно пытаетесь сопоставить структуру псевдокода, чтобы упростить сравнение реализации с спецификация. (И, опять же, если у вас было несколько методов, поэтому использование локальной переменной приведет к повторению.)

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

Ответ 6

Это может быть оправдано, если ссылочный объект может быть изменен впоследствии, но начальное значение this (хотя такой дизайн также следует пересмотреть, поскольку он может указывать, что Thing имеет больше обязанностей, чем он должен).

Однако, если ссылочный объект всегда this, тогда он не нужен и запутан.

Следующее объявление не только запутывает, но и смешно:)

private final Thing thing = this;

Ответ 7

Нет, потому что было бы лишним иметь себя как поле, когда у него есть ключевое слово this

Внутри метода экземпляра или конструктора this является ссылкой на текущий объект - объект, чей метод или конструктор вызывается. Вы можете обратиться к любому члену текущего объекта из метода экземпляра или конструктора с помощью this. "- Javadocs Keyword "this"

Ответ 8

В iOS объекты довольно часто имеют делегаты - обычно другой объект, который может предоставлять данные, или может делать другие вещи, необходимые для нормальной работы объекта, в качестве альтернативы подклассу. Если объект реализует все функции, которые должен реализовать делегат, объект может быть его собственным делегатом. Не совсем обычная, но не редкость.

Скажем, у вас есть "босс", у которого есть "секретарь", "кофеварка" и "водитель". Босс, очевидно, может писать свои собственные письма, делать свой собственный кофе и управлять собой, но не каждый босс. Поэтому иногда одно или несколько из этих полей будут установлены на "this".

Ответ 9

Случай отражения с элементами управления библиотечным интерфейсом.

Это полностью законно в определенных шаблонах использования. В нераскрытой структуре предприятия я видел XML как этот упрощенный пример:

<form>
    <comboBox listItems="order.LineItems" displayMember="description" valueMember="selfRef"/>
</form>

Привязки элемента управления к значениям выполняются, хотя Отражение. Если вы довольны только Integer ID как valueMember, вам не нужен член класса, ссылающийся на сам объект. Но если вы хотите ссылаться на сам объект. И по дизайну пустое значение ("") не реализовано как особый случайный смысл this, тогда вам нужно сохранить его в переменной-члене (selfRef в приведенном выше примере),