有什么好方法可以让两个不可变对象互相引用吗?
以这两个Java类为例:
class User {
final Inventory inventory;
User (Inventory inv) {
inventory = inv;
}
}
class Inventory {
final User owner;
Inventory (User own) {
owner = own;
}
}
有没有办法不使用反射* 来完成这个任务吗?我实际上并不希望如此,但问一下也没什么坏处。
更新:由于字节码构造有两个步骤(1.分配对象,2.调用构造函数**),这可以(ab)用于通过手写字节码或自定义编译器来执行此操作吗?我说的是首先对两个对象执行步骤 1,然后使用步骤 1 中的引用对两个对象执行步骤 2。当然,类似的事情会相当麻烦,而且问题的这一部分是学术性的。
(* 因为反射可能会给安全经理带来麻烦)
(** 说我的知识有限)
Take these two Java classes:
class User {
final Inventory inventory;
User (Inventory inv) {
inventory = inv;
}
}
class Inventory {
final User owner;
Inventory (User own) {
owner = own;
}
}
Is there any way without using reflection* to pull this off? I don't actually expect it is, but it can't hurt to ask.
Update: Since in bytecode construction has two steps (1. allocate object, 2. call constructor**) could this be (ab)used to do this, with handwritten bytecode or a custom compiler? I'm talking about performing step 1 for both objects first, then step 2 for both, using references from step 1. Of course something like that would be rather cumbersome, and this part of the question is academic.
(* Because reflection may give trouble with a security manager)
(** Says my limited knowledge)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
只有当其中一个对象由另一个对象创建时,这才能干净地工作。例如,您可以将
User
类更改为类似以下内容(同时保持Inventory
类不变):您需要小心访问
User
但是,Inventory
构造函数中的 > 对象尚未完全初始化。例如,其inventory
字段仍将为null
!广告更新:我现在已经验证字节码操作方法不起作用。我已经使用 Jasmin 尝试过,但它总是无法加载
VerifyError
。深入研究这个问题,我发现§ 4.10.2.4 实例初始化方法和新创建的对象。本节说明 JVM 如何确保仅传递已初始化的对象实例。
This can only work cleanly if one of the objects is created by the other. For example you can change your
User
class to something like this (while keeping theInventory
class unchanged):You need to be careful about accessing the
User
object in theInventory
constructor, however: it's not fully initialized yet. For example, itsinventory
field will still benull
!Ad Update: I've now verified that the bytecode-manipulation approach does not work. I've tried it using Jasmin and it always failed to load with a
VerifyError
.Delving deeper into the issue, I found§ 4.10.2.4 Instance Initialization Methods and Newly Created Objects. This section explains how the JVM ensures that only initialized object instances get passed around.
如果您不需要注入其中一个对象,则可以这样做。
You can do it if you don't need to inject one of the objects.
这是我能想到的最好的。也许有更好的模式。
That's the best I can think of. Maybe there's a better pattern.
有点迂腐,但严格来说,如果您不介意一点间接的话,则没有必要在另一个内部创建一个。它们都可能是内部类。
或者甚至:
Slightly pedantic, but it's not strictly speaking necessary to create one inside the other, if you don't mind a little indirection. They could both be inner classes.
Or even:
这是一种“解决方案”,尽管失去一个
final
会带来不便。This is one "solution", though the loss of one
final
is inconvenient.如果您只对 JVM 字节码感兴趣而不关心 Java 编码,那么使用 Scala 或 Clojure 可能会有所帮助。您需要某种
letrec
机制。If you are only interested in JVM bytecode and don't care about coding in Java specifically, perhaps using Scala or Clojure could help. You'll need some kind of
letrec
machinery.B:“用户创建的库存是我们最后的希望”。
Y:“不,还有另一个。”
如果你将引用抽象为第三方,你就可以控制其中的关系。
例如。
B: "Inventory created by the User is our last hope".
Y: "No, there is another."
If you abstract the references to a third party, you can control the relationship therein.
For example.