Kotlin单例Logger在Java中调用报非静态方法引用错误的解决
Kotlin单例Logger在Java类中调用报错的原因与解决方法
问题场景
我在Android中实现了一个仅在Debug构建时输出日志的Kotlin单例Logger类:
object Logger2 { private const val TAG = Constants.LOGGING_TAG fun d(message : Any?){ if (BuildConfig.DEBUG) Log.d(TAG , message.toString()) } fun d(message: Any? , e : Exception?){ if (BuildConfig.DEBUG) Log.d(TAG , message.toString(), e) } fun e(message : Any?){ if (BuildConfig.DEBUG) Log.e(TAG , message.toString()) } fun e(message: Any? , e : Exception?){ if (BuildConfig.DEBUG) Log.e(TAG , message.toString(), e) } fun w(message : Any?){ if (BuildConfig.DEBUG) Log.w(TAG , message.toString()) } fun w(message: Any? , e : Exception?){ if (BuildConfig.DEBUG) Log.w(TAG , message.toString(), e) } fun v(message : Any?){ if (BuildConfig.DEBUG) Log.v(TAG , message.toString()) } fun v(message: Any? , e : Exception?){ if (BuildConfig.DEBUG) Log.v(TAG , message.toString(), e) } }
在Kotlin类中调用Logger2.e("message")完全正常,但在Java类中调用时,即便调用方法不是静态的,依然会报错:Non-static method cannot be referenced from a static context。
错误含义
Kotlin的object单例在编译为Java字节码时,会生成一个包含静态INSTANCE字段的类,但object中定义的普通fun会被编译成该类的非静态成员方法。
在Java中直接写Logger2.e("message"),本质是试图通过类名直接访问非静态方法——这违反了Java的语法规则:非静态方法必须通过类的实例来调用,不能直接用类名调用,因此触发该错误。
解决方法
方法1:在Java中通过INSTANCE调用实例方法
Kotlinobject编译后会自动生成一个名为INSTANCE的静态实例,Java代码中可以通过这个实例来调用Logger的方法:
// 普通日志调用 Logger2.INSTANCE.e("message"); // 带异常的日志调用 Logger2.INSTANCE.e("error message", new Exception("test exception"));
方法2:给Kotlin方法添加@JvmStatic注解
如果希望Java代码和Kotlin一样直接用类名调用,可以给Logger的每个方法添加@JvmStatic注解。这个注解会让Kotlin编译器在生成Java字节码时,额外生成对应的静态方法,这样Java就能直接通过类名调用:
object Logger2 { private const val TAG = Constants.LOGGING_TAG @JvmStatic fun d(message : Any?){ if (BuildConfig.DEBUG) Log.d(TAG , message.toString()) } @JvmStatic fun d(message: Any? , e : Exception?){ if (BuildConfig.DEBUG) Log.d(TAG , message.toString(), e) } @JvmStatic fun e(message : Any?){ if (BuildConfig.DEBUG) Log.e(TAG , message.toString()) } @JvmStatic fun e(message: Any? , e : Exception?){ if (BuildConfig.DEBUG) Log.e(TAG , message.toString(), e) } @JvmStatic fun w(message : Any?){ if (BuildConfig.DEBUG) Log.w(TAG , message.toString()) } @JvmStatic fun w(message: Any? , e : Exception?){ if (BuildConfig.DEBUG) Log.w(TAG , message.toString(), e) } @JvmStatic fun v(message : Any?){ if (BuildConfig.DEBUG) Log.v(TAG , message.toString()) } @JvmStatic fun v(message: Any? , e : Exception?){ if (BuildConfig.DEBUG) Log.v(TAG , message.toString(), e) } }
修改后,Java代码就可以和Kotlin一样直接调用:
Logger2.e("message");
内容的提问来源于stack exchange,提问作者Saneen K P
相关产品推荐
相关产品推荐

