拥有一个自己作为场地的物体是否合理?

Aut*_*tar 27 java field object this

是否有理由拥有一个像这样的字段的对象:

class Thing {

    Thing field;

    public Thing() {
        this.field = this;
    }
}
Run Code Online (Sandbox Code Playgroud)

我不是在谈论一个具有相同类型字段的类,而是一个类,使得类的每个实例都将其自身作为字段.我刚刚在一些遗留代码中看到了这个(这个领域从未使用过),所以我很好奇.任何合法使用这个?

Pet*_*rey 38

是的,虽然这很少见.这在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);
    }
Run Code Online (Sandbox Code Playgroud)

在这种情况下,mutex可能是当前类,但是如果此集合是从现有的同步集合中获取的,则互斥锁可能不同.例如,如果你调用Map.values()MapsynchronizedMapmutex必应地图不是集合.


另一个例子是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;
Run Code Online (Sandbox Code Playgroud)

  • @DavidGrinberg添加了Throwable作为一个例子,其中字段的类型与它所在的类相同. (3认同)

bhs*_*cer 19

我至少可以想到一个合理的例子.例如

我有一个证书链,链中的每个链接都有一个对其父级的引用.在链的顶部,最后一个证书是自签名的,因此其父级是自己的.

简而言之,它实际上取决于您正在建模的问题空间.任何绝对主张声称不应该这样做是因为缺乏想象力.

public class Cert {
    public Cert parent;
}

public class SelfSignedCert extends Cert {
    public SelfSignedCert() {
        this.parent = this;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 另一个例子,我是我自己的理发师:) (4认同)

Hoo*_*pje 11

不,在我看来这是不合理的,因为每个对象都隐含地已经有了这样一个领域:this.当然,对象有一个有时但不总是引用自身的字段(例如可能出现在循环链表中)是合理的,但问题是关于一个总是指对象的字段本身.

我已经看过代码,其中这样的字段用于能够从内部类(匿名)引用包含对象,但在这种情况下,这不是必需的.你可以用ContainingClass.this.例如:

class A {
    class B {
        A getParent() {
            return A.this;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @ user11177答案非常明确地指出**总是*等于`this`的字段有**理由,但是**有些*理由是*有时*(但不总是!)等于"这个".对我来说似乎没什么混乱...... (3认同)
  • "this"在匿名内部类中不起作用."this"将引用anon cobject而不是hold父对象. (2认同)
  • 这个答案令人困惑,因为它首先声明它永远不合理,然后在下面的句子中提出了一个合理的例子.是否合理?如果是,那么就不要说它永远不合理. (2认同)

Zho*_*gYu 6

JDK中的另一个例子 - java.lang.Throwable

private Throwable cause = this;
Run Code Online (Sandbox Code Playgroud)

cause领域可以处于3个状态 - 未设置; 设为null; 设置为另一个Throwable.

实现者用于this表示未设置状态.

更可读的策略可能是为unset定义一个sentinel值

static Throwable UNSET = new Throwable();

private Throwable cause = UNSET;
Run Code Online (Sandbox Code Playgroud)

当然,还有一个递归依赖UNSET.cause=?- 这是另一个有趣的话题.


Dav*_*ell 5

我能想到的唯一一个案例是进行某种重构.要创建一个示例,对象可能已经开始作为一个非常面向对象的静态方法的集合:

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

...所以我们决定摆脱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
      }
    }
 }
Run Code Online (Sandbox Code Playgroud)

如果只有这样的方法,最好使用局部变量:

public void doItToIt() {
  final Bar it = this;
  ...
}
Run Code Online (Sandbox Code Playgroud)

但如果有多个,使用实例变量将使代码更快地运行.

现在将是更好的去替换的所有实例itthis(和摆脱getType(),并删除if,等等),但作为一个中间步骤它仍然是一个改进,它可能会在此状态下,如果有(或被认为是)其他更重要的事情要做.

另一种可能性是从伪代码中this具有名称的规范中复制伪代码,并且您故意尝试匹配伪代码结构以便于将实现与规范进行比较.(而且,如果你有多种方法,那么使用局部变量会导致重复.)

但一般来说,不,有一个总是指的实例变量this是多余的,因此阻碍了清晰度.


Dra*_*vic 5

如果引用的对象可以在之后更改,则可以证明是合理的,但初始值是this(虽然这样的设计也应该重新访问,因为它可能表明它Thing有更多的责任).

但是,如果引用的对象始终是this,那么这是不必要的和令人困惑的.

以下声明不仅令人困惑,而且有趣:)

private final Thing thing = this;