拥有一个像这样的字段的对象是否合理:
class Thing {
Thing field;
public Thing() {
this.field = this;
}
}
我不是在谈论一个具有相同类型字段的类,而是一个类,以便该类的每个实例都将其自身作为字段。 我刚刚在一些遗留代码中看到了这个(这个领域从未使用过),所以我很好奇。任何合法使用这个吗?
答案 0 :(得分:38)
是的,虽然这种情况很少见。这在JDK中用于字段可能为this
的情况,但可能不是。{/ p>
来自实现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;
答案 1 :(得分:19)
我至少可以想到一个合理的例子。 e.g。
我有一个证书链,其中链中的每个链接都有对其父级的引用。在链的顶部,最后一个证书是自签名的,因此其父级是自己的。
简而言之,它实际上取决于您正在建模的问题空间。任何绝对主张声称不应该这样做是因为缺乏想象力。
public class Cert {
public Cert parent;
}
public class SelfSignedCert extends Cert {
public SelfSignedCert() {
this.parent = this;
}
}
答案 2 :(得分:11)
不,在我看来这是不合理的,因为每个对象都隐含地已经有这样一个字段:this
。当然,对象有一个有时但不总是引用自身的字段(例如可能出现在循环链表中)是合理的,但问题是关于一个总是指对象的字段本身。
我见过代码,其中这样的字段用于从内部类引用(匿名)包含对象,但在这种情况下,这不是必需的。您可以使用ContainingClass.this
。例如:
class A {
class B {
A getParent() {
return A.this;
}
}
}
答案 3 :(得分:7)
JDK中的另一个例子 - java.lang.Throwable
private Throwable cause = this;
cause
字段可以处于3个状态 - 未设置;设为null;设置为另一个Throwable。
实施者使用this
来表示未设置状态。
更易读的策略可能是为取消设置
定义一个标记值static Throwable UNSET = new Throwable();
private Throwable cause = UNSET;
当然,还有一个递归依赖 - UNSET.cause=?
- 这是另一个有趣的话题。
答案 4 :(得分: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
的实例变量是多余的,因而无法明确。
答案 5 :(得分:5)
如果之后可以更改引用的对象,但是初始值为this
(尽管这样的设计也应该重新访问,因为它可能表明Thing
有更多的责任,这可能是合理的。比它应该)。
但是,如果引用的对象始终是this
,那么这是不必要的并且令人困惑。
以下声明不仅令人困惑,而且有趣:)
private final Thing thing = this;
答案 6 :(得分:2)
不,因为当它具有关键字SELECT * FROM Data
WHERE Data.Kvartal IN (SELECT Kvartal.Kvartal_text
FROM Kvartal
WHERE Kvartal.Kvartal_nummer = Data.Kvartal);
在实例方法或构造函数中,
this
是对当前对象的引用 - 正在调用其方法或构造函数的对象。您可以使用this
从实例方法或构造函数中引用当前对象的任何成员。“ - Javadocs Keyword "this"
答案 7 :(得分:2)
在iOS中,对象通常具有委托 - 通常是可以提供数据的另一个对象,或者可以执行使对象正常工作所需的其他事物,作为子类化的替代方法。如果一个对象实现了委托应该实现的所有功能,那么该对象可以是它自己的委托。不完全常见,但也不常见。
让我们说你有一个&#34;老板&#34;谁有一个&#34;秘书&#34;,一个&#34;咖啡机&#34;和#34;司机&#34;。老板显然可以写自己的信件,自己做咖啡并开车自己,但不是每个老板都这样做。因此,有时这些字段中的一个或多个将被设置为&#34;这个&#34;。
答案 8 :(得分:0)
在某些使用模式中完全合法。在未公开的企业框架中,我已经看到了像这个简化示例的XML:
<form>
<comboBox listItems="order.LineItems" displayMember="description" valueMember="selfRef"/>
</form>
通过反射进行控件与值的绑定。如果您只对Integer ID
valueMember
感到满意,则不需要类成员引用对象本身。但是如果你想通过设计引用对象本身,那么空值(""
)不会被实现为特殊情况this
,那么你需要将它保存在一个成员变量中{{{ 1}}在上面的例子中)。