🗂

Kolinの初期化ブロックはクラスボディの順番で呼び出される

に公開

クイズ

皆さん以下のandroidのコードの誤りを見つけられるでしょうか?
Empty ActivityにInitTestClassを追加しただけです。
当然ですがバグはInitTestClassに含まれています。

package com.example.test_init_block

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.test_init_block.ui.theme.Test_init_blockTheme

class InitTestClass{

    init{
        reset()
    }

    private var test_param: MutableSet<String> = mutableSetOf()

    private fun reset(){
        test_param.clear()
    }
}


class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        var initTest = InitTestClass()
        setContent {
            Test_init_blockTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Greeting(
                        name = "Android",
                        modifier = Modifier.padding(innerPadding)
                    )
                }
            }
        }
    }
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(
        text = "Hello $name!",
        modifier = modifier
    )
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    Test_init_blockTheme {
        Greeting("Android")
    }
}

答え

題名でネタバレしている気がしますが、Kotlinの初期化ブロックはclass bodyに記載された順番のまま実行されるそうです。

During the initialization of an instance, the initializer blocks are executed in the same order as they appear in the class body, interleaved with the property initializers:

https://kotlinlang.org/docs/classes.html#constructors

今回以下で、初期化ブロックが、test_paramの初期化より先に実行されるより先に記載したのがだめなようです。

    init{
        reset()
    }

    private var test_param: MutableSet<String> = mutableSetOf() // <-これが初期化前に呼び出されている!

    private fun reset(){
        test_param.clear()
    }

こうすればOK

    private var test_param: MutableSet<String> = mutableSetOf()

    init{
        reset()
    }

    private fun reset(){
        test_param.clear()
    }

Androidの勉強中にこのエラーが出て、さっぱりわからんで困りました。

Discussion