私は、この関数がで働く理由を知りたいのjavaともにkotlinでtailrec
はなく、中にkotlinなしtailrec
?
簡単に言えば、KotlinメソッドはJAVAメソッドよりも「重い」ためです。すべての呼び出しで、「挑発」する別のメソッドを呼び出しますStackOverflowError
。したがって、以下の詳細な説明を参照してください。
対応するJavaバイトコード reverseString()
KotlinとJAVAで対応するメソッドのバイトコードをチェックしました。
JavaのKotlinメソッドのバイトコード
...
public final void reverseString(@NotNull char[] s) {
Intrinsics.checkParameterIsNotNull(s, "s");
this.helper(0, ArraysKt.getLastIndex(s), s);
}
public final void helper(int i, int j, @NotNull char[] s) {
Intrinsics.checkParameterIsNotNull(s, "s");
if (i < j) {
char t = s[j];
s[j] = s[i];
s[i] = t;
this.helper(i + 1, j - 1, s);
}
}
...
JAVAのJAVAメソッドのバイトコード
...
public void reverseString(char[] s) {
this.helper(s, 0, s.length - 1);
}
public void helper(char[] s, int left, int right) {
if (left < right) {
char temp = s[left];
s[left++] = s[right];
s[right--] = temp;
this.helper(left, right, s);
}
}
...
したがって、2つの主な違いがあります。
Intrinsics.checkParameterIsNotNull(s, "s")
Kotlinバージョンhelper()
では、それぞれに対して呼び出されます。
- JAVAメソッドの左と右のインデックスは増加しますが、Kotlinでは、再帰呼び出しごとに新しいインデックスが作成されます。
それでは、Intrinsics.checkParameterIsNotNull(s, "s")
単独でどのように動作に影響するかをテストしてみましょう。
両方の実装をテストする
両方のケースで簡単なテストを作成しました。
@Test
public void testJavaImplementation() {
char[] chars = new char[20000];
new Example().reverseString(chars);
}
そして
@Test
fun testKotlinImplementation() {
val chars = CharArray(20000)
Example().reverseString(chars)
}
以下のためにJAVAのためにしながら、テストは問題なく成功しKotlinそれは無残に失敗したためStackOverflowError
。ただし、JAVAメソッドに追加Intrinsics.checkParameterIsNotNull(s, "s")
した後も失敗しました。
public void helper(char[] s, int left, int right) {
Intrinsics.checkParameterIsNotNull(s, "s"); // add the same call here
if (left >= right) return;
char tmp = s[left];
s[left] = s[right];
s[right] = tmp;
helper(s, left + 1, right - 1);
}
結論
あなたのKotlinのそれは呼び出しの方法は、より小さな再帰の深さを持っているIntrinsics.checkParameterIsNotNull(s, "s")
すべてのステップで、したがって、そのより重いJAVAの対応。この自動生成されたメソッドが必要ない場合は、ここで回答したように、コンパイル中にnullチェックを無効にすることができます
ただし、利点tailrec
がもたらすものを理解しているため(再帰呼び出しを反復呼び出しに変換する)、その呼び出しを使用する必要があります。
tailrec
か、再帰を回避することです。使用可能なスタックサイズは、実行間、JVMとセットアップ間、およびメソッドとそのパラメーターによって異なります。しかし、もしあなたが純粋な好奇心から完全に正当な理由を求めているなら、私にはわかりません。おそらくバイトコードを見る必要があるでしょう。