java 解决父构造器中拿到对象

2023-10-20 12:35:07 浏览数 (1)

这两天被问到一个有意思的问题,就是如果在构造器中拿到匿名对象。 这个问题有意思在,直觉上是可以通过外部放一个成员变量去接,然后后续就可以使用了,但实际不行。

问题复现

下面这个是构造器,当通过 supper 去调用父类构造器。由于问题出现在Spring项目当中,所以我复现的例子也基于Spring重新搭了一个项目来复现这个过程,代码放github上。

复现demo:

代码语言:javascript复制
package com.test;

import org.springframework.beans.factory.annotation.Autowired;

public class TransactionCache extends RevokingDB {

  @Autowired
  public TransactionCache(String dbName) {
    // 其他代码不能在 supper 之前,但是又要拿到 TxCacheDB,不能再new一次,否则会初始化两次TxCacheDB。
    super(new TxCacheDB(dbName));
    // 需要是在这里调一下 txCacheDB.init();
  }
}
代码语言:javascript复制
public class TxCacheDB {

  public TxCacheDB(String dbName) {
    System.out.println("TxCacheDB: "   dbName);
  }

  public void init() {
    System.out.println("TxCacheDB: init");
  }
}

这里可以偿试几种解决方案:

  1. 方案一 直接成员变量中 new TxCacheDB(dbName); 构造器中再使用
  2. 方案二 super调用一个方法,而不直接new TxCacheDB();
  3. 方案三 将对象保在ThreadLocal中,再拿出来

验证方案

方案一

这种在直觉上没有问题,但是实际有问题:

  1. 成员变量不知道 dbName,传入的具体值是什么,如果写死就失去灵活性。
  2. 写死。如果写死,你不能确定会传入dbName将会是什么,实际中这个dbName有很多个,没有办法写死

方案二

这个方法看着就可行,来验证一下。

代码语言:javascript复制
import org.springframework.beans.factory.annotation.Autowired;

@Slf4j
public class TransactionCache2 extends RevokingDB {

  private static TxCacheDB txCacheDB = null;

  @Autowired
  public TransactionCache2(String dbName) {
    // 其他代码不能在 supper 之前
    super(getTxCache(dbName));
    txCacheDB.init();
  }

  private static TxCacheDB getTxCache(String dbName) {
    txCacheDB = new TxCacheDB(dbName);
    return txCacheDB;
  }
}

输出结果:

TxCacheDB: trans-cache TxCacheDB: init

结查证明可行。 但是有个问题,我就用一次,还有开辟一段元数据区态内存来放 这个 static TxCacheDB,不划算。 我就想用一次,不想还占用内存。

方案三

将对象放入本地线程中,使用后就移除。 这样即可以使用对象,也不需要一直占用部分内存。

代码语言:javascript复制
public class TransactionCache3 extends RevokingDB {

  @Autowired
  public TransactionCache3(String dbName) {
    // 其他代码不能在 supper 之前
    super(new TxCacheDB(dbName));
    try {
      TxCacheDB txCacheDB = ThreadLocalUtil.get();
      txCacheDB.init();
    } finally {
      ThreadLocalUtil.remove();
    }
  }
}

TxCacheDB: trans-cache3 TxCacheDB: init

总结

java 对象在初始化的时候构造器中 supper 是永远放在第一行不能变。这一特性决定了这个问题的解决只能曲线救国。

0 人点赞