抽象静态成员初始化

sds*_*sds 1 java abstract-class

我希望派生类有自己的记录器,但看起来我不能:

abstract class C {
  final protected static Logger l;
  C (...) {
    l.emit("C");
  }
}
class C1 extends C {
  final protected static Logger l = new Logger("C1");
  C1 (...) {
    super(...);
    l.emit("C1");
  }
}
Run Code Online (Sandbox Code Playgroud)

我想要一个Loggerin C1但不是in C,所以new C1()产生这个输出:

C1: C
C1: C1
Run Code Online (Sandbox Code Playgroud)

(第一行来自C构造函数,第二行来自C1构造函数).相反,我得到一个nullPointerException,C因为lnull.

我不能让labstractC,我不希望有初始化,要么因为那么输出将是

C: C
C1: C1
Run Code Online (Sandbox Code Playgroud)

我有什么选择?

谢谢!

hay*_*lem 6

解决方案1(经典)

一种可能的方法是getLogger()在抽象类中使用抽象方法,以便派生类被强制提供自己的记录器.

public class AbstractClass {
  abstract Logger getLogger();

  public void someMethodInAbstractClass() {
    getLogger().debug("something"); // will output using provided child logger
  }
}

public class ConcreteClass extends AbstractClass {
  private static final Logger LOGGER = Logger.getLogger(ConcreteClass.class);

  @Override
  Logger getLogger() {
    return (LOGGER);
  }

  public void someMethod() {
    getLogger().debug("something"); // will output using local logger
  }
}
Run Code Online (Sandbox Code Playgroud)

您还可以在抽象类中提供默认实现,以强制子实现覆盖.您可以使抽象类的使用者(开发具体类)更容易,但是您不会强制执行方法的细粒度.

解决方案2(啰嗦...)

另一个更暴力的解决方案是getMagicLogger()在抽象类中有一个方法,它将在运行时确定当前实例的具体类型,以返回新的记录器实例,每次或延迟加载并将其存储在字段中.

通过这种方式,抽象类可以处理所有这些,对消费者来说非常容易,但这是一件很疯狂的事情.AND,这意味着Logger显然不是静态字段.