• No se han encontrado resultados

Proceso de evaluación del programa

4.1. Diseño de la investigación

Normally, all the declarations in a class go inside curly braces. You may wonder why this class has no curly braces and instead has only a declaration in parentheses. This block of code surrounded by parentheses is called a primary constructor. It serves two purposes: specifying constructor parameters and defining properties that are initialized by those parameters. Let’s unpack what happens here and look at the most explicit code you can write that does the same thing:

class User constructor(_nickname: String) { val nickname: String

init {

nickname = _nickname } }

Primary constructor with one parameter Initializer block

In this example, you see two new Kotlin keywords:constructor andinit. The

constructor keyword begins the declaration of a primary or secondary constructor. The

init keyword introduces an initializer block. Such blocks contain initialization code that’s executed when the class is created through the primary constructor. Because the primary constructor has a constrained syntax, it can’t contain the initialization code;

that’s why you have initializer blocks. If you want to, you can declare several initializer blocks in one class.

The underscore in the constructor parameter _nickname serves to distinguish the name of the property from the name of the constructor parameter. An alternative

class User(val nickname: String)

possibility is to use the same name and write this to remove the ambiguity, as is commonly done in Java:this.nickname = nickname.

In this example, you don’t need to place the initialization code in the initializer block, because it can be combined with the declaration of thenickname property. You can also omit theconstructor keyword if there are no annotations or visibility modifiers on the primary constructor. If you apply those changes, you get the following:

Primary constructor with one parameter The property is initialized by the parameter.

This is another way to declare the same class. Note how you can refer to primary constructor parameters in property initializers and in initializer blocks.

The two previous examples declared the property by using the val keyword in the body of the class. If the property is initialized by the corresponding constructor parameter, the code can be simplified by adding the val keyword before the parameter. This replaces the property definition in the class:

"val" means the corresponding property is generated for the constructor parameter.

All the declarations of the User class are equivalent, but the last one uses the most concise syntax.

You can declare default values for constructor arguments just as you can for function arguments:

Provides a default value for the constructor parameter

To create an instance of a class, you call the constructor directly, without thenew

keyword:

class User(_nickname: String) { val nickname = _nickname }

class User(val nickname: String)

class User(val nickname: String,

val isSubscribed: Boolean = true)

>>> val alice = User("Alice")

>>> println(alice.isSubscribed) true

>>> val bob = User("Bob", isSubscribed = false)

>>> println(bob.isSubscribed) false

Uses the default value "true" for the isSubscribed parameter You can explicitly specify names for some constructor arguments.

It seems that Alice subscribed to the mailing list by default, whereas Bob read the terms and conditions carefully and deselected the default option.

If your class has a superclass, the primary constructor also needs to initialize the superclass. You can do so by providing the superclass constructor parameters after the superclass reference in the base class list:

If you don’t declare any constructors for a class, a default constructor that does nothing will be generated for you:

open class Button

The default constructor without arguments is generated.

If you inherit the Button class and don’t provide any constructors, you have to explicitly invoke the constructor of the superclass even if it doesn’t have any parameters:

That’s why you need empty parentheses after the name of the superclass. Note the difference with interfaces: interfaces don’t have constructors, so if you implement an interface, you never put parentheses after its name in the supertype list.

If you want to ensure that your class can’t be instantiated by other code, you have to

NOTE Note

If all the constructor parameters have default values, the compiler generates an additional constructor without parameters that uses all the default values. That makes it easier to use Kotlin with libraries that instantiate classes via parameterless constructors.

open class User(val nickname: String) { ... }

class TwitterUser(nickname: String) : User(nickname) { ... }

class RadioButton: Button()

make the constructor private. Here’s how you make the primary constructor private:

This class has a private constructor.

Alternatively, you can declare it in a more usual way in the body of the class:

Because the Secretive class has only a private constructor, the code outside of the class can’t instantiate it. Later in this chapter, we’ll talk about companion objects, which may be a good place to call such constructors.

In most real use cases, the constructor of a class is straightforward: it contains no parameters or assigns the parameters to the corresponding properties. That’s why Kotlin has concise syntax for primary constructors: it works great for the majority of cases. But life isn’t always that easy, so Kotlin allows you to define as many constructors as your class needs. Let’s see how this works.

4.2.2 Secondary constructors: initializing the superclass in different ways