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()
和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;
Run Code Online (Sandbox Code Playgroud)
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)
Hoo*_*pje 11
不,在我看来这是不合理的,因为每个对象都隐含地已经有了这样一个领域:this
.当然,对象有一个有时但不总是引用自身的字段(例如可能出现在循环链表中)是合理的,但问题是关于一个总是指对象的字段本身.
我已经看过代码,其中这样的字段用于能够从内部类(匿名)引用包含对象,但在这种情况下,这不是必需的.你可以用ContainingClass.this
.例如:
class A {
class B {
A getParent() {
return A.this;
}
}
}
Run Code Online (Sandbox Code Playgroud)
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=?
- 这是另一个有趣的话题.
我能想到的唯一一个案例是进行某种重构.要创建一个示例,对象可能已经开始作为一个非常面向对象的静态方法的集合:
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)
但如果有多个,使用实例变量将使代码更快地运行.
现在将是更好的去替换的所有实例it
与this
(和摆脱getType()
,并删除if
,等等),但作为一个中间步骤它仍然是一个改进,它可能会在此状态下,如果有(或被认为是)其他更重要的事情要做.
另一种可能性是从伪代码中this
具有名称的规范中复制伪代码,并且您故意尝试匹配伪代码结构以便于将实现与规范进行比较.(而且,如果你有多种方法,那么使用局部变量会导致重复.)
但一般来说,不,有一个总是指的实例变量this
是多余的,因此阻碍了清晰度.
如果引用的对象可以在之后更改,则可以证明是合理的,但初始值是this
(虽然这样的设计也应该重新访问,因为它可能表明它Thing
有更多的责任).
但是,如果引用的对象始终是this
,那么这是不必要的和令人困惑的.
以下声明不仅令人困惑,而且有趣:)
private final Thing thing = this;
归档时间: |
|
查看次数: |
2830 次 |
最近记录: |