クラス属性を使用してKotlinクラスを作成します。これをコンストラクターで初期化します。
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値を強制する必要があります。または、「?」でヌルチェックを提供します。
クラス属性がコンストラクタで初期化される場合、これを回避する方法はありますか?私はこのような解決策を高く評価したいと思います:
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
プロパティを宣言して初期化しないこともできます。可能なすべてのコンストラクタが実際に初期化すると仮定します(質問の2番目の例に従って)。 これは、値を別々に初期化できる複数のコンストラクタがある場合に正常です:
_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 TestClass() {
private lateinit var context : Context // set by something else after construction
fun doSomeVoodoo() {
val text : String = context.getString()
}
}
_
lateinit
の場合、プロパティは現在var
である必要があり、プリミティブ型では機能しません。
Delegates.notNull()
などの目的で設計されたデリゲートを使用する場合は、var
プロパティを宣言して初期化しないこともできます。 これは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
を使用すると、バイトコードが非効率になったため、いくつかの調査を行った後、このアプローチに落ち着き、それが役立つ場合に備えて回答を投稿しました。
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;
}
}