我正在Android应用程序中创建我的第一个Kotlin类。通常为了记录目的,我有一个名为$hash_map{key} = \@arr
的常量。我在Java中会做的是:
TAG
我知道在Kotlin课程中我可以用这种方式创建private static final String TAG = MyClass.class.getSimpleName();
:
TAG
对于使用Java和Kotlin的项目来说这是可以的,但是如果我开始一个仅在Kotlin中的新项目呢?如何定义private val TAG = MyClass::class.java.simpleName
常数?有没有更多的Kotlin方式,我没有这种奇怪的结构TAG
?
答案 0 :(得分:29)
一般来说常量都是大写字母(例如FOO)并且位于companion object:
class MyClass {
companion object {
public const val FOO = 1
}
}
并定义您可以使用的TAG字段:
private val TAG = MyClass::class.qualifiedName
答案 1 :(得分:18)
此扩展程序使我们可以在任何类中使用TAG
val Any.TAG: String
get() {
val tag = javaClass.simpleName
return if (tag.length <= 23) tag else tag.substring(0, 23)
}
//usage
Log.e(TAG,"some value")
它还经过验证可以用作Android有效的Log标签。
答案 2 :(得分:11)
通常建议使用companion object
的方法生成伴侣类的额外static final
实例,因此性能和内存都很差。
将日志标记定义为顶级常量,因此只生成额外的类(MyClassKt
),但与companion object
进行比较时,它不会有static final
个实例(和没有任何实例):
private const val TAG = "MyLogTag"
class MyClass {
fun logMe() {
Log.w(TAG, "Message")
}
}
使用普通val
。虽然看到日志标记不是全大写常量看起来很不寻常,但这不会生成任何类并且开销最小。
class MyClass {
private val tag = "myLogTag"
fun logMe() {
Log.w(tag, "Message")
}
}
答案 3 :(得分:8)
在Kotlin中,您可以创建扩展,然后将tag调用为方法调用。这意味着您不必在每个类中都定义它,我们每次调用该方法时都可以动态构造它:
inline fun <reified T> T.TAG(): String = T::class.java.simpleName
答案 4 :(得分:6)
只需执行以下操作即可。
private val TAG = this::class.java.simpleName
答案 5 :(得分:5)
您可以按TAG
定义@JvmField
,如下所示:
companion object {
@JvmField val TAG: String = MyClass::class.java.simpleName
}
有关详细信息,请阅读以下文章:Kotlin's hidden costs
答案 6 :(得分:3)
我创建了一些Log扩展函数,以避免像我们在Java中那样声明log标记(可能性能较低,但是鉴于我们正在谈论日志记录,这应该是IMO)。该方法使用经过修饰的类型参数和其他Kotlin好吃的东西来检索类的简单名称。这是一个基本示例:
inline fun <reified T> T.logi(message: String) =
Log.i(T::class.java.simpleName, message)
您可以找到更详细的要旨here
答案 7 :(得分:2)
使用Kotlin 1.2.20
class MyClass {
companion object {
@JvmField
public val FOO = 1
}
}
用途
MyClass.FOO
答案 8 :(得分:1)
我找到了一种更多&#34;复制粘贴&#34; -able的方式,因为它不要求您输入班级名称:
package com.stackoverflow.mypackage
class MyClass
{
companion object {
val TAG = this::class.toString().split(".").last().dropLast(10)
}
}
它不是最优雅的解决方案,但它有效。
this::class.toString().split(".").last()
会向您"com.stackoverflow.mypackage.MyClass$Companion"
,因此您需要dropLast(10)
删除$Companion
。
或者你可以这样做:
package com.stackoverflow.mypackage
class MyClass
{
val TAG = this::class.simpleName
}
但是TAG
成员变量不再是&#34;静态&#34;并且不遵循建议的命名约定。
答案 9 :(得分:1)
使用val
class YourClass {
companion object {
//if use java and kotlin both in project
//private val TAG = MyClass::class.java.simpleName
//if use only kotlin in project
private val TAG = YourClass::class.simpleName
}
}
使用像
这样的变量Log.d(YourClass.TAG, "Your message");
//or
Log.e(TAG, "Your message");
答案 10 :(得分:1)
TAG可以定义为内联扩展属性:
inline val <reified T> T.TAG: String
get() = T::class.java.simpleName
并且不要一直在Log.d(TAG, "")
中写TAG:
inline fun <reified T> T.logv(message: String) = Log.v(TAG, message)
inline fun <reified T> T.logi(message: String) = Log.i(TAG, message)
inline fun <reified T> T.logw(message: String) = Log.w(TAG, message)
inline fun <reified T> T.logd(message: String) = Log.d(TAG, message)
inline fun <reified T> T.loge(message: String) = Log.e(TAG, message)
答案 11 :(得分:0)
AnkoLogger使用接口来定义日志标记。
interface AnkoLogger {
/**
* The logger tag used in extension functions for the [AnkoLogger].
* Note that the tag length should not be more than 23 symbols.
*/
val loggerTag: String
get() = getTag(javaClass)
}
private fun getTag(clazz: Class<*>): String {
val tag = clazz.simpleName
return if (tag.length <= 23) {
tag
} else {
tag.substring(0, 23)
}
}
inline fun AnkoLogger.info(message: () -> Any?) {
val tag = loggerTag
if (Log.isLoggable(tag, Log.INFO)) {
Log.i(tag, message()?.toString() ?: "null")
}
}
你可以像这样使用它:
class MyClass : AnkoLogger {
fun someFun(){
info("logging info")
}
}
也许AnkoLogger可以为您提供实现自定义日志记录工具的一些想法。
答案 12 :(得分:0)
我将常量创建为伴侣对象:
companion object {
val TAG = "SOME_TAG_VALUE"
}
然后,我可以这样使用它:
MyClass.TAG
答案 13 :(得分:0)
在Android Studio中,重命名的通常方法是右键单击名称,然后选择“重构”->“重命名”。所以,我认为做这样的事情很好,
class MyClass {
companion object {
private const LOG_TAG = "MyClass"
}
}
因为如果您像我描述的那样重命名类MyClass
,那么IDE也会建议重命名LOG_TAG字符串。
使用此方法与其他方法相比,最终有优缺点。由于LOG_TAG是字符串,因此无需导入kotlin-reflect.jar,就像将LOG_TAG
设置为MyClass::class.simpleName
一样。另外,由于使用const
关键字将该变量声明为编译时常量,因此生成的字节码较小,因为它不需要生成更多的隐藏getter,如this article中所述。
答案 14 :(得分:0)
我喜欢TAG
作为Fredy Mederos建议的扩展功能。
扩展他的答案以支持匿名类:
/**
* extension function to provide TAG value
*/
val Any.TAG: String
get() {
return if (!javaClass.isAnonymousClass) {
val name = javaClass.simpleName
if (name.length <= 23) name else name.substring(0, 23)// first 23 chars
} else {
val name = javaClass.name
if (name.length <= 23) name else name.substring(name.length - 23, name.length)// last 23 chars
}
}
答案 15 :(得分:0)
您可以尝试以下方法:
companion object {
val TAG = ClearCacheTask::class.java.simpleName as String
}
答案 16 :(得分:0)
这是我在kotlin中的扩展功能,只需将其添加到扩展文件中即可。
val Any.TAG: String
get() {
return if (!javaClass.isAnonymousClass) {
val name = javaClass.simpleName
if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) name else
name.substring(0, 23)// first 23 chars
} else {
val name = javaClass.name
if (name.length <= 23 || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
name else name.substring(name.length - 23, name.length)// last 23 chars
}
}
然后您可以在以下任何类中使用TAG:
Log.d(TAG, "country list")
答案 17 :(得分:0)
我定义了一个接口,它将 TAG 定义为具有默认 getter 实现的属性。 接口既可以由类“实现”,也可以由它的伴随对象“实现”:
//Prefix allows easier filtering in LogCat
private const val PREFIX = "somePrefix.";
interface HasLogTag {
val TAG: String
get() {
val name = javaClass.canonicalName?.removeSuffix(".Companion")?.substringAfterLast(".")
return "$PREFIX${name}"
}
}
接口使用如下:
import yourPackage.HasLogTag
....
class MyClass : HasLogTag {
...
//Alternatively: Let the companion object "implement" the interface
companion object : HasLogTag {
...
Log.e(TAG, "Some Info)
}
由于每次使用都会调用 getter,因此为伴随对象定义 TAG 没有任何好处。
注意:在之前的版本中,我使用反射来找出是类本身还是伴随对象定义了接口。
然而,这似乎严重减慢了我的应用程序的启动速度。