2017-07-16 27 views
3

Kotlin 拡張機能を使用している場合は、Javaのプライベートフィールドにアクセスしたいと思います。Kotlin拡張機能アクセスJavaプライベートフィールド

JavaクラスABCとします。 ABCにはプライベートフィールドmPrivateFieldが1つしかありません。どのような理由であれ、そのフィールドを使用する拡張機能をKotlinに書きたいと思います。

public class ABC { 
    private int mPrivateField; 

} 

Kotlin関数は次のようになります。私は取得しています

private fun ABC.testExtFunc() { 
    val canIAccess = this.mPrivateField; 
} 

エラーは次のとおりです。周り制限を取得

Cannot access 'mPrivateField': It is private in 'ABC'

任意の方法?

+0

あなたがやった理由java ** private **フィールドにアクセスする必要がありますか? –

+0

これは、私のプロジェクトにソースコード全体を含めることなく拡張したい、外部のコンパイルされたライブラリからのものです。ライブラリにはAndroidカレンダーイベント用の「取得」メソッドがあり、「カレンダーイベントを挿入する」機能をクラスに追加したかったのです。 –

+1

外部のライブラリを変更する**プライベート**フィールドは危険です*。それはおそらくあなたのアプリケーションを粉砕する。フィールド値を変更するには、java [reflection](http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/package-summary.html)を使用します。 –

答えて

2

まず、あなたが必要としますFieldを取得し、それは例えば、Kotlinにアクセスことができる可能にする:

val field = ABC::class.java.getDeclaredField("mPrivateField") 

field.isAccessible = true 

T鶏、あなたが例えば、宣言したクラスのインスタンスからField#getIntによってIntとしてフィールドの値を読むことができます:

val it: ABC = TODO() 

val value = field.getInt(it) 

最後に、あなたの拡張メソッドがされては、以下のように次のようになります。

private inline fun ABC.testExtFunc():Int { 
    return javaClass.getDeclaredField("mPrivateField").let { 
     it.isAccessible = true 
     val value = it.getInt(this) 
     //todo 
     [email protected] value; 
    } 
} 
+0

これは問題を**インライン**の方法で解決するきれいな解決策です。別々の拡張ゲッターを定義する必要はありません。ありがとう –

+0

@ kosiara-BartoszKosarzyckiもちろん、あなたが好きなら、あなたは**インライン**機能にすることができます。例えば、 'testExtFunc(action:(Int) - > R)'のように、操作抽象化を行いたい場合には拡張が必要で、 'read'ロジックと' action'ロジックを分離して、read関数を再利用することができます'testExtFunc'どこでも。 'testExtFunc(foo)'や 'testExtFunc(bar)'として使うことができます。これはkotlinの 'let' /' run'/'apply'や.etcとまったく同じです。 –

5

これは設計上可能ではありません。拡張関数は基本的に、最初のパラメータとして受信側を静的関数に解決します。このように、拡張機能

fun String.foo() { 
    println(this) 
} 

のようなものにコンパイル:

public static void foo(String $receiver) { 
    System.out.println($receiver); 
} 

彼らは、よく、プライベートだので、今では、あなたが$receiverのプライベートメンバにアクセスすることはできません見て明らかです。

実際ににそのメンバーにアクセスしたい場合は、リフレクションを使用することができますが、すべての保証は失われます。 nhaarmanは、私は疑問にフィールドにアクセスするために反射を使用示唆したのと同じように

+0

私はkotlinの人たちが将来私的フィールドゲッターを単純化する反射法の生成を自動化することを願っています...ほとんどの場合、それは安全ではないと同意しますが –

+3

それは起こりません。誰もそのような反射を促すべきではありません。 – nhaarman

+6

Androidプラットフォームでの予告なしのコミット:[別の日、別のプライベートフィールドにアクセスしました](https://android.googlesource.com/platform/libcore/+/81abb6fb7332dfe62ff596ffb250d8aec61895df%5E!/)。このケースでは、Facebookはリフレクションを通じてアクセスしていたため、***プライベート***メンバーの名前をロールバックしなければなりませんでした。 – nhaarman

0

。具体的に私は、悲しいことにKotlinの拡張機能でプライベートフィールドにアクセスする(つまりABCある)

を述べたクラス上で内部反射を使用ゲッターを作成のよう2017年7月不可能です

fun ABC.testExtFunc() { 
    val canIAccess = this.getmPrivateField() 
} 

fun ABC.getmPrivateField() : Int { 
    val field = this.javaClass.declaredFields 
      .toList().filter { it.name == "mPrivateField" }.first() 
    field.isAccessible = true 
    val value = field.get(this) 
    return value as Int 
} 
+1

'Class#getDeclaredField'と' Field#getInt'を直接使うことができます。あなたが得たいフィールドを正確に知っているからです。 –

関連する問題