2015-06-25 1 views
9

создать Котлин-класс с атрибутом класса, который я хочу, чтобы инициализировать в конструкторе:Котлин: Инициализировать атрибут класса в конструкторе

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 всегда делает необходимым значение NonNull с параметром "!!" или предоставить Null-check с помощью «?».

Есть ли способ избежать этого, если атрибут класса будет инициализирован в конструкторе? Я хотел бы оценить решение, как этот:

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) 
    } 
} 
+0

Второй пример работы с Котлин 0.12.213. Какую версию Kotlin вы используете? – D3xter

+0

Работает. Я уже использовал 0.12.613. Но я думаю, что я делал что-то неправильно. Сожалею! – Christopher

+0

Есть больше доступных случаев, я добавил ответ для полного покрытия. –

ответ

11

Если единственным, что вы делаете в конструкторе присваивание, , то вы можете использовать первичный конструктор с частной собственностью.

например:

public class TestClass(private var context: Context) { 

    public fun doSomeVoodoo() { 
    val text = context.getString(R.string.abc_...) 
    } 
} 
+1

Ох, круто! Я этого не знал! – Christopher

14

Как показано D3xter у вас есть возможность установить его в конструкторе. У вас также есть другие варианты. Вот они все ...

Создать свойство внутри конструктора (в соответствии с @ D3xter), это самый распространенный случай для простых свойств инициализируются непосредственно первичным конструктором:

class TestClass(private val context: Context) { 
    fun doSomeVoodoo() { 
     val text : String = context.getString() 
    } 
} 

Вы можете объявить свойство val, а не инициализировать его, если все возможные конструкторы действительно инициализируют его (согласно вашему второму примеру в заданном вопросе). Это нормально, когда у вас есть более чем один конструктор, который может инициализировать значение по-разному:

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 и не работает с примитивным типы.

Вы также можете объявить объект var, а не инициализировать его, если используете делегат, предназначенный для этой цели, такой как Delegates.notNull().Это похоже на 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() 
    } 
}