public class Foo {
private static final Logger LOG = LoggerFactory.getLogger(Foo.class);
}
在大多数成熟的Kotlin代码中,您会发现下面的模式之一。使用属性委托的方法利用了Kotlin生成最小代码的能力。
注意:这里的代码用于java.util.logging
,但同样的理论适用于任何日志库
类静态(常见,相当于问题中的Java代码)
class MyClass {
companion object {
val LOG = Logger.getLogger(MyClass::class.java.name)
}
fun foo() {
LOG.warning("Hello from MyClass")
}
}
关于同伴对象的更多信息:同伴对象...还请注意,在上面的示例中,MyClass::Class.java
为记录器获取类
类型的实例,而this.javaclass
将获取类
类型的实例。
类的每个实例(公共)
但是,确实没有理由避免在实例级别调用和获取记录器。您提到的惯用Java方式已经过时,并且基于对性能的恐惧,而每个类的记录器已经被地球上几乎任何合理的日志html" target="_blank">系统缓存。只需创建一个成员来保存记录器对象。
class MyClass {
val LOG = Logger.getLogger(this.javaClass.name)
fun foo() {
LOG.warning("Hello from MyClass")
}
}
2015年12月26日上午11:28:44 org.stackoverflow.kotlin.test.MyClass foo信息:来自MyClass的你好
您可以测试每个实例和每个类的性能变化,看看大多数应用程序是否存在实际差异。
属性委托(常见的,最优雅的)
fun <R : Any> R.logger(): Lazy<Logger> {
return lazy { Logger.getLogger(unwrapCompanionClass(this.javaClass).name) }
}
// see code for unwrapCompanionClass() below in "Putting it all Together section"
class Something {
val LOG by logger()
fun foo() {
LOG.info("Hello from Something")
}
}
对于每个类实例,或者如果您希望它更加静态,每个类只有一个实例:
class SomethingElse {
companion object {
val LOG by logger()
}
fun foo() {
LOG.info("Hello from SomethingElse")
}
}
对这两个类调用foo()
的输出是:
2015年12月26日上午11:30:55 org.stackoverflow.kotlin.test.Something foo信息:Hellow from Something
// extend any class with the ability to get a logger
fun <T: Any> T.logger(): Logger {
return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
}
现在,在一个类(或伴生对象)中,我可以简单地在我自己的类上调用这个扩展:
class SomethingDifferent {
val LOG = logger()
fun foo() {
LOG.info("Hello from SomethingDifferent")
}
}
产生产出的:
2015年12月26日上午11:29:12 org.stackoverflow.kotlin.test.SomethingDifferent foo info:来自SomethingDifferent的你好
val LOG1 = "".logger()
val LOG2 = Date().logger()
val LOG3 = 123.logger()
标记界面上的扩展函数(不确定有多常见,但“特征”的常见模型)
为了使扩展的使用更干净并减少“污染”,您可以使用标记接口来扩展:
interface Loggable {}
fun Loggable.logger(): Logger {
return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
}
甚至使用默认实现使方法成为接口的一部分:
interface Loggable {
public fun logger(): Logger {
return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
}
}
class MarkedClass: Loggable {
val LOG = logger()
}
interface Loggable {
val LOG: Logger // abstract required field
public fun logger(): Logger {
return Logger.getLogger(unwrapCompanionClass(this.javaClass).name)
}
}
现在接口的实现者必须如下所示:
class MarkedClass: Loggable {
override val LOG: Logger = logger()
}
当然,抽象基类也可以这样做,既可以选择接口,也可以选择实现该接口的抽象类,从而允许灵活性和统一性:
abstract class WithLogging: Loggable {
override val LOG: Logger = logger()
}
// using the logging from the base class
class MyClass1: WithLogging() {
// ... already has logging!
}
// providing own logging compatible with marker interface
class MyClass2: ImportantBaseClass(), Loggable {
// ... has logging that we can understand, but doesn't change my hierarchy
override val LOG: Logger = logger()
}
// providing logging from the base class via a companion object so our class hierarchy is not affected
class MyClass3: ImportantBaseClass() {
companion object : WithLogging() {
// we have the LOG property now!
}
}
把它放在一起(一个小助手库)
// Return logger for Java class, if companion object fix the name
fun <T: Any> logger(forClass: Class<T>): Logger {
return Logger.getLogger(unwrapCompanionClass(forClass).name)
}
// unwrap companion class to enclosing class given a Java Class
fun <T : Any> unwrapCompanionClass(ofClass: Class<T>): Class<*> {
return ofClass.enclosingClass?.takeIf {
ofClass.enclosingClass.kotlin.companionObject?.java == ofClass
} ?: ofClass
}
// unwrap companion class to enclosing class given a Kotlin Class
fun <T: Any> unwrapCompanionClass(ofClass: KClass<T>): KClass<*> {
return unwrapCompanionClass(ofClass.java).kotlin
}
// Return logger for Kotlin class
fun <T: Any> logger(forClass: KClass<T>): Logger {
return logger(forClass.java)
}
// return logger from extended class (or the enclosing class)
fun <T: Any> T.logger(): Logger {
return logger(this.javaClass)
}
// return a lazy logger property delegate for enclosing class
fun <R : Any> R.lazyLogger(): Lazy<Logger> {
return lazy { logger(this.javaClass) }
}
// return a logger property delegate for enclosing class
fun <R : Any> R.injectLogger(): Lazy<Logger> {
return lazyOf(logger(this.javaClass))
}
// marker interface and related extension (remove extension for Any.logger() in favour of this)
interface Loggable {}
fun Loggable.logger(): Logger = logger(this.javaClass)
// abstract base class to provide logging, intended for companion objects more than classes but works for either
abstract class WithLogging: Loggable {
val LOG = logger()
}
选择你想保留的任何一个,下面是所有正在使用的选项:
class MixedBagOfTricks {
companion object {
val LOG1 by lazyLogger() // lazy delegate, 1 instance per class
val LOG2 by injectLogger() // immediate, 1 instance per class
val LOG3 = logger() // immediate, 1 instance per class
val LOG4 = logger(this.javaClass) // immediate, 1 instance per class
}
val LOG5 by lazyLogger() // lazy delegate, 1 per instance of class
val LOG6 by injectLogger() // immediate, 1 per instance of class
val LOG7 = logger() // immediate, 1 per instance of class
val LOG8 = logger(this.javaClass) // immediate, 1 instance per class
}
val LOG9 = logger(MixedBagOfTricks::class) // top level variable in package
// or alternative for marker interface in class
class MixedBagOfTricks : Loggable {
val LOG10 = logger()
}
// or alternative for marker interface in companion object of class
class MixedBagOfTricks {
companion object : Loggable {
val LOG11 = logger()
}
}
// or alternative for abstract base class for companion object of class
class MixedBagOfTricks {
companion object: WithLogging() {} // instance 12
fun foo() {
LOG.info("Hello from MixedBagOfTricks")
}
}
// or alternative for abstract base class for our actual class
class MixedBagOfTricks : WithLogging() { // instance 13
fun foo() {
LOG.info("Hello from MixedBagOfTricks")
}
}
本示例中创建的所有13个记录器实例都将生成相同的记录器名称,并输出:
2015年12月26日上午11:39:00 org.stackoverflow.kotlin.test.mixedbagofticles foo信息:来自mixedbagofticles的你好
如何在使用Kotlin的Spring Boot中正确初始化ConfigurationProperties? 目前我喜欢下面的例子: 但是它看起来很丑陋,实际上不是一个iable,foo是常量ue,应该在启动期间初始化,将来不会改变。
问题内容: 我正在学习具有C ++和Java背景的Kotlin。我期待下面的打印,不。我知道这对应到。默认实现不比较每个成员,即和吗?如果是这样,它会不会看到字符串值相等(因为再次映射到字符串值)?显然,我在Kotlin中还没有涉及平等与身份相关的问题。 问题答案: 您描述的默认实现仅适用于数据类。不适用于从中继承实现的常规类,只需使对象与自身相等即可。
这是正确的吗? 我可以找到一个相关的问题,但它是有参数的,我不能在没有params的情况下转换它。
我正在尝试IntDef typedef将特定类型的参数限制为函数。但是当我使用Java使用IntDef时,它工作正常,但同时,它不适用于kotlin。以下是我的代码片段 - 在JAVA中- 在静态编程语言中- 在课堂上使用- 调用演示函数给我一个错误消息,说它必须是:< code>TransTypeJava之一。CASH,< code>TransTypeJava。通过传递< code>TransT