Kotlinの拡張プロパティと拡張方法
6278 ワード
拡張方法の原理
Kotlinのクラスの拡張方法は元のクラスの内部で拡張するのではなく、Javaコードに逆コンパイルすることで、その原理は装飾モードを使用して、ソースクラスのインスタンスに対する操作と包装であり、実際にはJavaで定義したツールクラスの方法に相当し、このツールクラスの方法は呼び出し者を最初のパラメータとして使用していることがわかります.次に、ツールメソッドで呼び出し元を操作します.
この呼び出し元はKotlinでthisキーワードで表される.
たとえば、Stringの拡張メソッドを定義します.thisは呼び出し元自体を表します.
Kotlinでの呼び出し方式:「aaaaa」.times(10)
対応するJavaコードに逆コンパイル:
Javaでの呼び出し方法:TestObjectKt.times(“aaaa”,10);
Kotlinでは実際に呼び出し者「aaaa」をメソッドtimesの最初のパラメータとして使用していることがわかる.
拡張プロパティの原理
クラスの拡張属性の原理は実際には拡張方法と同じであるが、定義の形式が異なるだけで、拡張属性はgetメソッドとsetメソッドを定義する必要があり、インタフェースで定義された変数と同様にbackingfieldがなく、fieldキーワードがなく、変数を格納するために使用できない.(一般的なクラスプロパティでは、オブジェクトインスタンスにメモリが割り当てられ、プロパティの値が格納されます.)
対応するJavaコード:
拡張プロパティにbacking fieldがない理由は、元のクラス内で拡張されていないツールメソッドであることがわかります.
拡張メソッドによる反復ループの実装
Iterableインタフェースを実現したクラスは、forループを使用して遍歴することができます.拡張方法により、クラスはIteratorインタフェースを実現する必要がなく、反復を実現することができる.
拡張View GroupプロパティChildViewの取得
Kotlinのクラスの拡張方法は元のクラスの内部で拡張するのではなく、Javaコードに逆コンパイルすることで、その原理は装飾モードを使用して、ソースクラスのインスタンスに対する操作と包装であり、実際にはJavaで定義したツールクラスの方法に相当し、このツールクラスの方法は呼び出し者を最初のパラメータとして使用していることがわかります.次に、ツールメソッドで呼び出し元を操作します.
この呼び出し元はKotlinでthisキーワードで表される.
たとえば、Stringの拡張メソッドを定義します.thisは呼び出し元自体を表します.
fun String.times(t:Int){
val sb = StringBuilder()
for (i in 0 until t) {
sb.append(this)
}
println(sb.toString())
}
Kotlinでの呼び出し方式:「aaaaa」.times(10)
対応するJavaコードに逆コンパイル:
public final class TestObjectKt {
public static final void times(@NotNull String $receiver, int t) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
StringBuilder sb = new StringBuilder();
IntRange var10000 = RangesKt.until(0, t);
int i = var10000.getFirst();
int var4 = var10000.getLast();
if(i <= var4) {
while(true) {
sb.append($receiver);
if(i == var4) {
break;
}
++i;
}
}
String var5 = sb.toString();
System.out.println(var5);
}
}
Javaでの呼び出し方法:TestObjectKt.times(“aaaa”,10);
Kotlinでは実際に呼び出し者「aaaa」をメソッドtimesの最初のパラメータとして使用していることがわかる.
拡張プロパティの原理
クラスの拡張属性の原理は実際には拡張方法と同じであるが、定義の形式が異なるだけで、拡張属性はgetメソッドとsetメソッドを定義する必要があり、インタフェースで定義された変数と同様にbackingfieldがなく、fieldキーワードがなく、変数を格納するために使用できない.(一般的なクラスプロパティでは、オブジェクトインスタンスにメモリが割り当てられ、プロパティの値が格納されます.)
fun main(args: Array) {
val str = "aa"
// backing field, , setXXX(str,10) str
// :aa10
str.s = 10
// :2
println(str.s)
}
var String.s: Int
get() = this.length
set(value){
//set field value,
// value , this
println(this.plus(value))
}
対応するJavaコード:
public final class ExtendsKt {
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
String str = "aa";
setS(str, 10);
int var2 = getS(str);
System.out.println(var2);
}
public static final int getS(@NotNull String $receiver) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
return $receiver.length();
}
public static final void setS(@NotNull String $receiver, int value) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
String var2 = $receiver + value;
System.out.println(var2);
}
}
拡張プロパティにbacking fieldがない理由は、元のクラス内で拡張されていないツールメソッドであることがわかります.
拡張メソッドによる反復ループの実装
Iterableインタフェースを実現したクラスは、forループを使用して遍歴することができます.拡張方法により、クラスはIteratorインタフェースを実現する必要がなく、反復を実現することができる.
fun ViewGroup.children() = object : Iterable {
override fun iterator() = object : Iterator {
var index = 0
override fun hasNext() = index < childCount
override fun next() = getChildAt(index++)
}
}
val views = // ...
for (view in views.children()) {
// TODO do something with view
}
val visibleHeight = views.children()
.filter { it.visibility == View.VISIBLE }
.sumBy { it.measuredHeight }
拡張View GroupプロパティChildViewの取得
val ViewGroup.children: List
get() = (0..childCount -1).map { getChildAt(it) }
parent.children.forEach { it.visible() }