采用这两个Java类:
class User {
final Inventory inventory;
User (Inventory inv) {
inventory = inv;
}
}
class Inventory {
final User owner;
Inventory (User own) {
owner = own;
}
}
有没有办法without using reflection*解决这个问题?我实际上并不指望它是这样,但是问它也不会有害。
更新:由于在字节码构造中有两个步骤(1.分配对象,2。调用构造函数**)这可能是(ab)用于执行此操作,使用手写字节码或自定义编译器?我说的是首先对两个对象执行步骤1,然后使用步骤1中的参考执行步骤2.当然这样的事情会相当麻烦,而这部分问题是学术性的。
(*因为反思可能会给安全管理员带来麻烦)
(**说我的知识有限)
答案 0 :(得分:13)
如果其中一个对象是由另一个创建的,那么它只能干净地工作。例如,您可以将User
类更改为此类(同时保持Inventory
类不变):
class User {
private final Inventory inventory;
User () {
inventory = new Inventory(this);
}
}
您需要注意访问User
构造函数中的Inventory
对象,但是:它还没有完全初始化。例如,其inventory
字段仍为null
!
广告更新:我现在已经确认字节码操作方法无法正常工作。我使用Jasmin尝试了它,但始终无法加载VerifyError
。
深入研究这个问题,我找到了§ 4.10.2.4 Instance Initialization Methods and Newly Created Objects。本节介绍JVM如何确保只传递初始化的对象实例。
答案 1 :(得分:7)
如果您不需要注入其中一个对象,则可以执行此操作。
class User {
private final Inventory inventory;
User () {
inventory = new Inventory(this);
}
}
答案 2 :(得分:3)
class User {
private final Inventory inventory;
User (/*whatever additional args are needed to construct the inventory*/) {
//populate user fields
inventory = new Inventory(this);
}
}
class Inventory {
private final User owner;
Inventory (User own) {
owner = own;
}
}
这是我能想到的最好的。也许有更好的模式。
答案 3 :(得分:1)
略显迂腐,但如果你不介意一点间接,那么在另一个内部创建一个并不是严格必要的。他们都可以成为内部阶级。
public class BadlyNamedClass {
private final User owner;
private final Inventory inventory;
public BadlyNamedClass() {
this.owner = new User() {
... has access to BadlyNamedClass.this.inventory;
};
this.inventory = new Inventory() {
... has access to BadlyNamedClass.this.owner;
};
}
...
}
甚至:
public class BadlyNamedClass {
private final User owner;
private final Inventory inventory;
public BadlyNamedClass() {
this.owner = new User(this);
this.inventory = new Inventory(this);
}
public User getOwner() { return owner; }
public Inventory getInventory() { return inventory; }
...
}
答案 4 :(得分:0)
这是一个“解决方案”,但丢失一个final
是不方便的。
class User {
Inventory inventory;
User () { }
// make sure this setter is only callable from where it should be,
// and is called only once at construction time
setInventory(inv) {
if (inventory != null) throw new IllegalStateException();
inventory = inv;
}
}
class Inventory {
final User owner;
Inventory (User own) {
owner = own;
}
}
答案 5 :(得分:0)
如果您只对JVM字节码感兴趣并且不关心Java中的编码,那么使用 Scala 或 Clojure 可能会有所帮助。你需要某种letrec
机器。
答案 6 :(得分:0)
B:“用户创建的库存是我们最后的希望” Y:“不,还有另一个。”
如果您将引用抽象为第三方,则可以控制其中的关系。
例如。
public class User
{
private final String identifier; // uniquely identifies this User instance.
public User(final String myIdentifier)
{
identifier = myIdentifier;
InventoryReferencer.registerBlammoUser(identifier); // Register the user with the Inventory referencer.
}
public Inventory getInventory()
{
return InventoryReferencer.getInventoryForUser(identifier);
}
}
public interface Inventory // Bam!
{
... nothing special.
}
// Assuming that the Inventory only makes sence in the context of a User (i.e. User must own Inventory).
public class InventoryReferencer
{
private static final Map<String, Inventory> referenceMap = new HashMap<String, Inventory>();
private InventoryReferencer()
{
throw ... some exception - helps limit instantiation.
}
public static void registerBlammoUser(final String identifier)
{
InventoryBlammo blammo = new InventoryBlammo();
referenceMap.add(indentifier, blammo);
}
public static void registerKapowUser(final String identifier)
{
InventoryBlammo kapow = new InventoryKapow();
referenceMap.add(indentifier, kapow);
}
public static Inentory getInfentoryForUser(final String identifier)
{
return referenceMap.get(identifier);
}
}
// Maybe package access constructors.
public class InventoryBlammo implements Inventory
{
// a Blammo style inventory.
}
public class InventoryKapow implements Inventory
{
// a Kapow style inventory.
}