Kotlin:在构造函数中初始化 class 属性
Kotlin: Initialize class attribute in constructor
我创建了一个带有 class 属性的 Kotlin-class,我想在构造函数中对其进行初始化:
public class TestClass {
private var context : Context? = null // Nullable attribute
public constructor(context : Context) {
this.context = context
}
public fun doSomeVoodoo() {
val text : String = context!!.getString(R.string.abc_action_bar_home_description)
}
}
不幸的是,我必须用“?”将属性声明为 Nullable符号,尽管该属性将在构造函数中初始化。将此属性声明为 Nullable-attribute 使得始终有必要使用“!!”强制 NonNull-value。或者用“?”提供空检查。
如果 class 属性将在构造函数中初始化,有什么办法可以避免这种情况?我想感谢这样的解决方案:
public class TestClass {
private var context : Context // Non-Nullable attribute
public constructor(context : Context) {
this.context = context
}
public fun doSomeVoodoo() {
val text : String = context.getString(R.string.abc_action_bar_home_description)
}
}
如果您在构造函数中所做的唯一事情是赋值,
那么您可以将主构造函数与私有 属性.
一起使用
例如:
public class TestClass(private val context: Context) {
public fun doSomeVoodoo() {
val text = context.getString(R.string.abc_...)
}
}
如 D3xter 所示,您可以选择在构造函数中进行设置。您还有其他选择。他们都在这里...
在构造函数中创建 属性(根据 @D3xter),这是由主构造函数直接初始化的简单属性的最常见情况:
class TestClass(private val context: Context) {
fun doSomeVoodoo() {
val text : String = context.getString()
}
}
您可以声明 val
属性 并且不对其进行初始化,假设所有可能的构造函数都确实对其进行了初始化(根据所问问题中的第二个示例)。 当您有多个可以不同地初始化值的构造函数时,这是正常的:
public class TestClass {
private val context: Context
public constructor(context : Context) {
this.context = context
}
// alternative constructor
public constructor(pre: PreContext) {
this.context = pre.readContext()
}
public fun doSomeVoodoo() {
val text : String = context.getString()
}
}
您可以传入不是 属性 声明的构造函数参数,然后在 属性 初始化中使用它们。 当您有更复杂的初始化或需要使用委托属性时,这很常见:
class TestClass(context: PreContext) {
private val context : Context by lazy { context.readContext() }
private val other: List<Items> = run {
context.items.map { it.tag }.filterNotNull()
}
private val simpleThing = context.getSimple()
fun doSomeVoodoo() {
val text : String = context.getString()
}
}
当您无法在构造期间初始化值时使用lateinit
modifier,但您确定它会在您第一次读取访问之前完成。 当依赖注入、IoC 容器或其他东西创建空版本的 class 然后立即初始化它时,这很常见:
class TestClass() {
private lateinit var context : Context // set by something else after construction
fun doSomeVoodoo() {
val text : String = context.getString()
}
}
对于 lateinit
,属性 当前必须是 var
,并且不适用于基本类型。
您还可以声明一个 var
属性 而不是初始化它,如果您使用为此目的设计的委托,例如 Delegates.notNull()
。 这与 lateinit
类似,当您想要 var
时很常见,它没有初始状态,但在构建后的未知时间点设置 :
public class TestClass() {
private var context: Context by Delegates.notNull()
public fun doSomeVoodoo() {
// if context is not set before this is called, an exception is thrown
val text : String = context.getString()
}
}
我有一个类似的问题,我不想在构造后抓住对象。使用 lazy
或 lateinit
导致字节码效率低下,所以经过一些研究后我决定采用这种方法并返回 post 答案以防它有帮助:
解决方案
class TestClass(context: Context) {
private val homeDescription: String
init {
homeDescription = context.getString(R.string.abc_action_bar_home_description)
}
fun doSomeVoodoo() {
val text : String = homeDescription
}
}
或者,以上可以进一步简化为:
class TestClass(context: Context) {
private val homeDescription: String = context.getString(R.string.abc_action_bar_home_description)
fun doSomeVoodoo() {
val text : String = homeDescription
}
}
反编译字节码
反编译后的 java 版本感觉比其他方法更容易接受,并且在构建后不保留对上下文的引用:
public final class TestClass {
private final String homeDescription;
public final void doSomeVoodoo() {
String text = this.homeDescription;
}
public TestClass(@NotNull Context context) {
Intrinsics.checkParameterIsNotNull(context, "context");
super();
String var10001 = context.getString(2131296256);
Intrinsics.checkExpressionValueIsNotNull(var10001, "context.getString(R.stri…ion_bar_home_description)");
this.homeDescription = var10001;
}
}
我创建了一个带有 class 属性的 Kotlin-class,我想在构造函数中对其进行初始化:
public class TestClass {
private var context : Context? = null // Nullable attribute
public constructor(context : Context) {
this.context = context
}
public fun doSomeVoodoo() {
val text : String = context!!.getString(R.string.abc_action_bar_home_description)
}
}
不幸的是,我必须用“?”将属性声明为 Nullable符号,尽管该属性将在构造函数中初始化。将此属性声明为 Nullable-attribute 使得始终有必要使用“!!”强制 NonNull-value。或者用“?”提供空检查。
如果 class 属性将在构造函数中初始化,有什么办法可以避免这种情况?我想感谢这样的解决方案:
public class TestClass {
private var context : Context // Non-Nullable attribute
public constructor(context : Context) {
this.context = context
}
public fun doSomeVoodoo() {
val text : String = context.getString(R.string.abc_action_bar_home_description)
}
}
如果您在构造函数中所做的唯一事情是赋值, 那么您可以将主构造函数与私有 属性.
一起使用例如:
public class TestClass(private val context: Context) {
public fun doSomeVoodoo() {
val text = context.getString(R.string.abc_...)
}
}
如 D3xter 所示,您可以选择在构造函数中进行设置。您还有其他选择。他们都在这里...
在构造函数中创建 属性(根据 @D3xter),这是由主构造函数直接初始化的简单属性的最常见情况:
class TestClass(private val context: Context) {
fun doSomeVoodoo() {
val text : String = context.getString()
}
}
您可以声明 val
属性 并且不对其进行初始化,假设所有可能的构造函数都确实对其进行了初始化(根据所问问题中的第二个示例)。 当您有多个可以不同地初始化值的构造函数时,这是正常的:
public class TestClass {
private val context: Context
public constructor(context : Context) {
this.context = context
}
// alternative constructor
public constructor(pre: PreContext) {
this.context = pre.readContext()
}
public fun doSomeVoodoo() {
val text : String = context.getString()
}
}
您可以传入不是 属性 声明的构造函数参数,然后在 属性 初始化中使用它们。 当您有更复杂的初始化或需要使用委托属性时,这很常见:
class TestClass(context: PreContext) {
private val context : Context by lazy { context.readContext() }
private val other: List<Items> = run {
context.items.map { it.tag }.filterNotNull()
}
private val simpleThing = context.getSimple()
fun doSomeVoodoo() {
val text : String = context.getString()
}
}
当您无法在构造期间初始化值时使用lateinit
modifier,但您确定它会在您第一次读取访问之前完成。 当依赖注入、IoC 容器或其他东西创建空版本的 class 然后立即初始化它时,这很常见:
class TestClass() {
private lateinit var context : Context // set by something else after construction
fun doSomeVoodoo() {
val text : String = context.getString()
}
}
对于 lateinit
,属性 当前必须是 var
,并且不适用于基本类型。
您还可以声明一个 var
属性 而不是初始化它,如果您使用为此目的设计的委托,例如 Delegates.notNull()
。 这与 lateinit
类似,当您想要 var
时很常见,它没有初始状态,但在构建后的未知时间点设置 :
public class TestClass() {
private var context: Context by Delegates.notNull()
public fun doSomeVoodoo() {
// if context is not set before this is called, an exception is thrown
val text : String = context.getString()
}
}
我有一个类似的问题,我不想在构造后抓住对象。使用 lazy
或 lateinit
导致字节码效率低下,所以经过一些研究后我决定采用这种方法并返回 post 答案以防它有帮助:
解决方案
class TestClass(context: Context) {
private val homeDescription: String
init {
homeDescription = context.getString(R.string.abc_action_bar_home_description)
}
fun doSomeVoodoo() {
val text : String = homeDescription
}
}
或者,以上可以进一步简化为:
class TestClass(context: Context) {
private val homeDescription: String = context.getString(R.string.abc_action_bar_home_description)
fun doSomeVoodoo() {
val text : String = homeDescription
}
}
反编译字节码
反编译后的 java 版本感觉比其他方法更容易接受,并且在构建后不保留对上下文的引用:
public final class TestClass {
private final String homeDescription;
public final void doSomeVoodoo() {
String text = this.homeDescription;
}
public TestClass(@NotNull Context context) {
Intrinsics.checkParameterIsNotNull(context, "context");
super();
String var10001 = context.getString(2131296256);
Intrinsics.checkExpressionValueIsNotNull(var10001, "context.getString(R.stri…ion_bar_home_description)");
this.homeDescription = var10001;
}
}