Author of this issue:

Video: Throwing line (Zhu Kai)

Article: Hamber (Luo Qiong)

Hey, guys. I’m a throwline, and I’m out of here.

Welcome to the first Kotlin tutorial. Everyone has been waiting for a long time, in fact, I have been urged to do not want to live, but I have too many things ah. Like I want to travel? Do I have to spend time with my wife? Am I supposed to be with the baby? Am I going to spank the baby? Should I beat my wife? And as you know, I’m running an online Advanced Android course right now, so I have to put a lot of time into the course, right? I’ll be hacked to death by the team if the client’s father gives me a bad review.

Anyway, production finally started last semester, and we have some stock. No more nonsense, video service!

If you can’t see the bilibili video above, you can click ithereGo to Billie Billie orhereGo to YouTube to see.

The following is from author Hamber.

At Google I/O 2019, Google announced Kotlin as the first development language for Android. What this means for developers is that Kotlin will be preferred for all official samples in the future, and Google’s support for Kotlin in all aspects of development, build, and so on will be a higher priority.

In this environment, Kotlin has become one of the interview points for mobile development positions at many companies, and even a requirement for HR resume selection. Therefore, learning and mastering Kotlin has become a priority for Android developers.

The question “Is Kotlin really that good?” and “Should I learn Kotlin or not?” will soon become obsolete. The purpose of this program is not to learn Kotlin from you, but to learn Kotlin as quickly as possible.

Our purpose is very clear: this is a how-to guide to Kotlin for Android engineers. Among them:

  • This is a how-to guide, not a technical document. So:
    • We will take you step by step, a rhythm of learning, let you learn Kotlin relaxed and happy;
    • But there won’t be a complete API listing. If you want to check out the API, check out the official Kotlin documentation.
  • This is just a “get started” guide, and we’re not trying to get too deep, but there’s not a single technical detail you need to know.
  • We are targeting Android engineers, so all videos and articles and sample code will be based on the Android development scenario, and the development environment will be Android Studio. It would be nice if this guide could benefit Java developers in other fields by the way, but only by the way: Joy:
  • For the code snippets presented in the presentation, I will mark the areas needing attention in the code in the form of “πŸ‘†”, “πŸ‘‡”, “πŸ‘ˆ” and “πŸ‘‰”, with the words “…” Omitted code that the reader doesn’t need to care about for now.
  • Android developers use Android Studio as their DEVELOPMENT IDE, and all of the following ides refer to Android Studio.

Add Kotlin language support to the project

The first step in learning Kotlin is to add Kotlin language support to your project, which is very simple.

Create an Android project that supports Kotlin

If you want to create a new Android project that supports Kotlin, just do the following:

  • File -> New -> New Project…
  • Choose your project -> Phone and Tablet -> Empty Activity
  • Configure your project -> Language select “Kotlin”

Everything else is like creating a normal Android project, and the resulting project will be based on Kotlin.

“Kotlin based” means two things:

  1. The MainActivity that the IDE automatically creates for you is written in Kotlin:

    package org.kotlinmaster
    
    import android.os.Bundle
    import androidx.appcompat.app.AppCompatActivity
    
    class MainActivity : AppCompatActivity() {... }Copy the code

    Just glance at it, don’t read the code, we’ll talk about that later.

  2. The two bulid.gradle files in the project have a few more lines of code than the Java Android project (marked with “πŸ‘‡”), and their purpose is to add Kotlin’s dependencies:

    • Build. gradle at the root of your project:

      Buildscript {πŸ‘‡ ext.kotlin_version ='1.3.41'
          repositories {
              ...
          }
          dependencies {
              classpath 'com. Android. Tools. Build: gradle: 3.5.0 - beta05'
              πŸ‘‡
              classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"}}Copy the code
    • Build. gradle in app directory:

      apply plugin: 'com.android.application'
      πŸ‘‡
      apply plugin: 'kotlin-android'. android { ... } dependencies { implementation fileTree(dir: 'libs'.include: ['*.jar'])
          πŸ‘‡
          implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version". }Copy the code

That is, if you are creating a new project, select Kotlin as the language, and after the project is created you can write it in Kotlin.

Add Kotlin support to existing projects

If an existing project supports Kotlin, just do the same as above and paste the code labeled in the two build.gradle tags into your project.

I recommend starting a New Kotlin-based project and practicing the steps above.

First MainActivity. Kt

As mentioned earlier, if the new project is based on Kotlin, the IDE will create MainActivity for us, which actually has a.kt file suffix (visible when opened).

Kotlin files end in.kt, just like Java files end in.java.

Let’s take a look at what’s in mainActivity.kt:

packageOrg. Kotlinmaster πŸ‘†importAndroid. OS. Bundle πŸ‘†importAndroidx. Appcompat. App. AppCompatActivity πŸ‘‡class MainActivity : AppCompatActivity() {πŸ‘† πŸ‘‡ πŸ‘‡ πŸ‘‡ πŸ‘‡override fun onCreate(savedInstanceState: Bundle?). {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}
Copy the code

At first glance, Kotlin has the same Java stuff as the package Import class annotated with “πŸ‘†”; But there are some things labeled “πŸ‘‡” that are not seen in Java.

To avoid these distractions for a while, let’s create a new file ourselves.

  • Under the new Java Class entry, you can see an option called “Kotlin File/Class”, which is the entry for our new Kotlin File
  • New Kotlin File/Class
    • Name: Sample
    • Kind: Class

Sample.kt after creation:

package org.kotlinmaster

class Sample {}
Copy the code

This class contains only the package and class keywords, so let’s think of the concept as similar to Java (which it really is), so that we are familiar with it.

Next, let’s start studying basic grammar.


variable

Declaration and assignment of variables

Here’s a little tidbit about how Java and Kotlin got their names.

We know that Java is the famous Java island, Java island is rich in coffee, it is said that a group of cattle who developed the Java language when people named it because of the smell of strong coffee, so decided to use this name.

Kotlin comes from Kotlin Island in the Gulf of Finland.

Therefore, we start the snippet with “β˜•οΈ” to represent the Java snippet and “🏝️” to represent the Kotlin snippet.

To declare a variable of type View:

β˜• ️ View v.Copy the code

The format for declaring a variable in Kotlin is this:

🏝 ️var v: View
Copy the code

There are several differences:

  • There is avarThe keyword
  • Type and variable names are swapped
  • It’s separated by a colon
  • No semicolons at the end (yeah, Kotlin doesn’t need semicolons)

It looks like the syntax is a little different, but the IDE will report an error if it does:

🏝 ️class Sample {
    var v: View
    // πŸ‘† writing IDE will report the following error
    // Property must be initialized or be abstract
}
Copy the code

The hint is that a property needs to be initialized at the same time as it is declared, unless you declare it abstract.

  • So what are attributes? Here we can understand Kotlin’s Property by simply comparing it to a Java field, although they are somewhat different. Kotlin has more Property functionality.

  • How can a variable be declared abstract? Well, that’s what Kotlin does, but I’ll leave it out for now and talk about it later.

Why do attributes require initialization? Because Kotlin’s variables don’t have default values, unlike Java, where field has default values:

β˜• ️ String name;// πŸ‘ˆ The default is null
int count; // πŸ‘ˆ The default is 0
Copy the code

But Kotlin doesn’t have that. A local variable does not have a default value. If it is not initialized, an error will be reported:

β˜• ️void run(a) {
    int count;
    count++; 
    // πŸ‘†IDE error: Variable 'count' might not have been initialized
}
Copy the code

In this case, we will give it a default value of null, unfortunately you will still find the error.

🏝 ️class Sample {
    var v: View = null
    // πŸ‘† Null can not be a value of a non-null type View
}
Copy the code

The IDE tells me that I need to assign a non-null value to it. The Java stuff doesn’t work.

It’s all about Kotlin’s air safety design. Many people who tried Kotlin gave up quickly because they didn’t understand its empty security design, and the code refused to compile in various ways and eventually gave up. So before we rush, LET me tell you about Kotlin’s air safety design.

Kotlin’s air safety design

In short, the IDE prompts to avoid calling null objects and thus nullPointerExceptions. In androidx, there is an annotation to indicate whether a variable is likely to be null, and the IDE will help detect and alert you.

β˜• ️@NonNull
View view = null;
// πŸ‘†IDE will prompt warning, 'null' is assigned to a variable that is annotated with @notnull
Copy the code

By Kotlin, the language level is supported by default, and the warning level has been changed from Warning to error (reject compilation) :

🏝 ️var view: View = null
// πŸ‘†IDE error, Null can not be a value of a non-null type View
Copy the code

In Kotlin, all variables are not allowed to be null by default, and if you assign it a value of null, an error will be reported, as above.

This kind of tough demand is actually quite reasonable: you declare a variable, you use it, right? Why did you set it to null? Try to make it as usable as possible. Java is very loose in this area, and we’re used to it, but Kotlin’s stronger restrictions actually reduce a lot of runtime problems once you get used to them.

However, there are some scenarios where the value of a variable is really not guaranteed to be empty, such as when you want to take JSON data from a server and parse it into a User object:

🏝 ️class User {
    var name: String = null // πŸ‘ˆ this will report an error, but the variable is not guaranteed to be empty
}
Copy the code

At this point, null values make sense. For those variables that can be null, you can add one to the right of the type, right? To remove its non-null limit:

🏝 ️class User {
    var name: String? = null
}
Copy the code

After the question mark is added, a Kotlin variable is free, just like a Java variable, without any non-null restrictions.

You can assign a null value to it at initialization, but also anywhere in the code:

🏝 ️var name: String? = "Mike". name =null // πŸ‘ˆ is not null
Copy the code

This type is followed by? Kotlin called the nullable type.

However, a new problem arises when we use nullable variables:

The IDE raises an error when Kotlin calls a nullable variable directly, because calling a nullable reference causes a nullpointer exception:

🏝 ️var view: View? = null
view.setBackgroundColor(Color.RED)
// πŸ‘† Only safe (? .). or non-null asserted (!! .). calls are allowed on a nullable receiver of type View?
Copy the code

Kotlin is not allowed to use “possibly empty” variables. So what? We tried to check before using it, but it seems the IDE doesn’t accept this:

🏝 ️if(view ! =null) {
    view.setBackgroundColor(Color.RED)
    // πŸ‘† Smart cast to 'View' is impossible, because 'view' is a mutable property that could have been changed by this time
} 
Copy the code

This error means that even if you check for non-empty, it does not guarantee that the following call will be non-empty, because in multithreaded cases, other threads may change it to null again.

So how does Kotlin solve this problem? It doesn’t use. It uses? . :

🏝 ️ view? .setBackgroundColor(Color.RED)Copy the code

This method also does a non-null validation of the variable before calling the method, which is Kotlin’s way of writing and is thread-safe, hence the name “safe call.”

Here’s another way to use double exclamation marks:

🏝 ️ view!!!!! .setBackgroundColor(Color.RED)Copy the code

I promise you that the view here is not empty, and you don’t have to check it for me, and I’ll take the consequences myself. Such a “definitely not null” assertion is called non-null Asserted Call. Once you use non-null assertions, you are virtually identical to Java, but without the benefits of Kotlin’s null-safe design (checking at compile time instead of throwing exceptions at run time).

So that’s Kotlin’s air safety design.

Once you understand it, variable declarations are completely different from Java, just written differently.

A lot of people get confused with variable declarations when they get started, because Kotlin’s empty security design leads to these errors:

  • The variable needs to be initialized manually. If it is not initialized, an error will be reported.
  • Variables are not null by default, so an initial assignment of NULL will return an error, as will a subsequent assignment of NULL.
  • Variable with?When set to nullable, error due to “may be empty” when used.

After understanding the principle of air safety design, it is easy to solve the above problems.

The most important thing to remember about space safety is that “nullability” is all about use time, that is, “can this variable be empty while in use?”

In addition, Kotlin’s empty security design is fully compatible with Java calls. Compatibility here refers to:

  • The @nullable annotation in Java also needs to be used in Kotlin. Okay? .

    β˜• ️@Nullable
    String name;
    Copy the code
    🏝 ️ name? .lengthCopy the code
  • The @nullable and @nonNULL annotations in Java correspond to Nullable and non-nullable variables when converted to Kotlin. Android Studio provides handy (but imperfect) tools, as WE’ll see later.

    β˜• ️@Nullable
    String name;
    @NonNull
    String value = "hello";
    Copy the code
    🏝 ️var name: String? = null
    var value: String = "hello"
    Copy the code

We’ve talked a lot about empty security, but sometimes we declare a variable and we don’t make it empty, like view, but in a real world scenario we want it to be non-empty all the time, but empty doesn’t really make business sense. Use? . Affects code readability.

But if you say this in MainActivity:

🏝 ️class MainActivity : AppCompatActivity() {πŸ‘‡var view: View = findViewById(R.id.tvContent)
}
Copy the code

Although the compiler does not report an error, the program crashes once it runs because findViewById() can only be called after onCreate.

So what to do? It’s tempting to tell the compiler, “I’m pretty sure I’ll never use it empty, but I couldn’t assign it in the first place.”

Kotlin gives us an option: deferred initialization.

Lazy initialization

Here’s what it says:

🏝 ️lateinit var view: View
Copy the code

Lateinit means: tell the compiler I can’t initialize it the first time, but I’ll definitely do it before I use it.

All it does is tell the IDE not to check initialization and report errors for this variable. In other words, by adding the LateInit keyword, you initialize the variable on your own and the compiler doesn’t check it for you.

Then we can initialize it in onCreate:

🏝 ️ πŸ‘‡lateinit var view: View
override fun onCreate(...).{... πŸ‘‡ view = findViewById(r.i.d.content)}Copy the code

Oh, and lazy initialization has no limit on how many times a variable can be assigned, you can still assign other values to the view after initialization.

Type inference

One of Kotlin’s handy things is that if you assign at declaration time, you don’t need to write the variable type:

🏝 ️var name: String = "Mike"
πŸ‘‡
var name = "Mike"
Copy the code

This feature is called “type inference”, and it’s not the same as dynamic typing. We can’t use it like we do with Groovy or JavaScript.

🏝 ️var name = "Mike"
name = 1
The integer literal does not conform to The expected type String
Copy the code
// Groovy
def a = "haha"
a = 1
// πŸ‘† assigning a string and then a number is possible in Groovy
Copy the code

“Dynamic typing” means that the type of a variable can change at run time; Type inference is when you don’t have to write variable types in your code and the compiler fills them in at compile time. Therefore, Kotlin is a static language.

In addition to the variable assignment scenario, other scenarios for type inference will be encountered later.

Val and var

Var is not the only way to declare a variable. We can also use val:

🏝 ️val size = 18
Copy the code

Val is another variable type Kotlin has added to Java’s “variable” type: read-only variable. It can only be assigned once and cannot be modified. Var is a readable and writable variable.

Var is short for variable and val is short for value.

Val is similar to Final in Java:

β˜• ️final int size = 18;
Copy the code

But they’re actually a little bit different, and we’ll talk about that later. You can’t just reassign.

visibility

In Kotlin, variables are public by default. In Kotlin, variables are public by default. In other visibility modifiers, We’ll talk about it later, but don’t worry about it here.

At this point, I’m sure you know enough about variables to give the previous examples a try.

function

In addition to variable declarations, Kotlin also declares functions differently from Java methods. Java methods are called functions in Kotlin, but there is no difference, or we can ignore the difference. In any programming language, variables are used to store data and functions are used to process data.

Declaration of functions

Let’s look at the Java method first:

β˜• ️Food cook(String name) {... }Copy the code

In Kotlin, the function is declared like this:

🏝 ️ πŸ‘‡ πŸ‘‡fun cook(name: String): Food {
    ...
}
Copy the code
  • Start with the fun keyword
  • The return value is written after the function and argument

What if there is no return value? In Java, return void:

β˜• ️void main(a) {... }Copy the code

Kotlin returns Unit and can be omitted:

🏝 ️ πŸ‘‡fun main(a): Unit {}
// Unit return type can be omitted
fun main(a) {}
Copy the code

Function parameters can also have nullable control. According to the above mentioned nullable safety design, we need to pay attention to when passing:

🏝 ️// πŸ‘‡ an error occurs when a nullable variable is passed to a non-nullable parameter
var myName : String? = "rengwuxian"
fun cook(name: String) : Food {}
cook(myName)
  
// πŸ‘‡ nullable variable to nullable parameter, normal operation
var myName : String? = "rengwuxian"
fun cook(name: String?). : Food {}
cook(myName)

// πŸ‘‡ non-nullable variable to non-nullable parameter, fine
var myName : String = "rengwuxian"
fun cook(name: String) : Food {}
cook(myName)
Copy the code

visibility

The default visibility range of a function without a visibility modifier is public, just like that of a variable, with the exception of the override keyword, which is covered below.

Property’s getter/setter function

As we know, fields in Java often have getter/setter functions:

β˜• ️public class User {
    String name;
    public String getName(a) {
        return this.name;
    }
    public void setName(String name) {
        this.name = name; }}Copy the code

They can be used to customize the internal implementation of a function to behave like hooks, such as the following:

β˜• ️public class User {
    String name;
    public String getName(a) {
        return this.name + " nb";
    }
    public void setName(String name) {
        this.name = "Cute "+ name; }}Copy the code

How does this getter/setter work in Kotlin?

🏝 ️class User {
    var name = "Mike"
    fun run(a) {
        name = "Mary"
        // πŸ‘† is actually called πŸ‘‡
        // setName("Mary")
        // The IDE code completion function will prompt you to type setn with name instead of setName
        
        println(name)
        // πŸ‘† is actually called πŸ‘‡
        // print(getName())
        // IDE code completion prompts you for name instead of getName when you type getn}}Copy the code

So how do we manipulate the aforementioned “hooks”? Take a look at this code:

🏝 ️class User {
    var name = "Mike"
        πŸ‘‡
        get() {
            return field + " nb"
        }
        πŸ‘‡   πŸ‘‡ 
        set(value) {
            field = "Cute " + value
        }
}
Copy the code

There are some formatting differences from Java:

  • Getter/setter functions have special keywords get and set
  • Getter/setter functions are located below the variables declared by var
  • The setter function argument is value

In addition to this, there is something called field. So this thing is called “Backing Field”. The woman behind Jack Ma 😝 Specifically, your code:

🏝 ️class Kotlin {
  var name = "kaixue.io"
}
Copy the code

When compiled, bytecode is roughly equivalent to Java code like this:

β˜• ️public final class Kotlin {
   @NotNull
   private String name = "kaixue.io";

   @NotNull
   public final String getName(a) {
      return this.name;
   }

   public final void setName(@NotNull String name) {
      this.name = name; }}Copy the code

The String name above is a Java field that Kotlin created automatically for us. This field is invisible to the person coding it, but automatically applies to getters and setters, so it’s called the “Backing field.” I was at back you.

So, while Kotlin’s field is essentially a Java field, for Kotlin’s syntax, it is not at all the same as a Java field. In Kotlin, it is equivalent to a variable inside each var.

Val is read-only, which means that a variable declared by val cannot be reassigned. That is, setter functions cannot be called. Therefore, a variable declared by val cannot override setter functions, but it can override getters:

🏝 ️val name = "Mike"
    get() {
        return field + " nb"
    }
Copy the code

The read-only variable declared by val can still be modified when it is evaluated, which is different from final in Java.

In addition to modifying values and assignments, you can also add some logic of your own, as we do in Activity lifecycle functions.

type

With variables and functions out of the way, we can look at Kotlin’s types in a systematic way.

Basic types of

In Kotlin, everything is an object, and the basic types used in Kotlin are numbers, characters, Booleans, arrays, and strings.

🏝 ️var number: Int = 1 // πŸ‘ˆ and Double Float Long Short Byte are similar
var c: Char = 'c'
var b: Boolean = true
var array: IntArray = intArrayOf(1.2) // πŸ‘ˆ FloatArray DoubleArray CharArray is a built-in function of Kotlin
var str: String = "string"
Copy the code

There are two things that are different from Java:

  • Int in Kotlin is different from Int and Integer in Java, mainly in terms of boxing.

    In Java, int is unbox and Integer is box:

    β˜• ️int a = 1;
    Integer b = 2; // πŸ‘ˆ is automatically boxing autoboxing
    Copy the code

    In Kotlin, whether Int is boxed depends on the occasion:

    🏝 ️var a: Int = 1 // unbox
    var b: Int? = 2 // box
    var list: List<Int> = listOf(1.2) // box
    Copy the code

    Kotlin simplified Int and Integer in Java at the language level, but we still need to have an idea of the boxing or not scenario because of the performance overhead associated with running the program.

    Therefore, in everyday use, for basic types such as Int, try to use non-nullable variables.

  • Arrays in Java are also written differently from arrays in Kotlin:

    β˜• ️int[] array = new int[] {1.2};
    Copy the code

    In Kotlin, it reads like this:

    🏝 ️var array: IntArray = intArrayOf(1.2)
    // πŸ‘†
    Copy the code

To put it simply, primitive types in Java, as in Kotlin, are not boded if one of the following conditions is met:

  • Non-null type.

  • Use IntArray, FloatArray, etc.

Classes and objects

Now let’s take a look at our old friend MainActivity and reintroduce it:

🏝 ️class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?).{... }}Copy the code

We can compare Java code to see the differences:

β˜• ️public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {... }}Copy the code
  • The first is class visibility. Public in Java can be omitted in Kotlin. Kotlin classes are public by default.

  • Class inheritance is written using extends in Java and: in Kotlin, but it can also represent implement in Java.

    For example, suppose we have an interface called Imple:

    🏝 ️interface Impl {}
    Copy the code

    Defining an interface in Kotlin is no different from Java.

    β˜• ️public class Main2Activity extends AppCompatActivity implements Impl {}Copy the code
    🏝 ️class MainActivity : AppCompatActivity(), Impl {}
    Copy the code
  • Constructors are written differently.

    • The default constructor is omitted in Java:

    • β˜• ️public class MainActivity extends AppCompatActivity {
            // πŸ‘‡ default constructor
            public MainActivity(a) {}}Copy the code
    • In Kotlin, we notice that the () on AppCompatActivity is an ellipsis, which is equivalent to:

    • 🏝 ️class MainActivity constructor() : appactivity () {πŸ‘†}Copy the code

      But it’s more Java like this:

      🏝 ️// πŸ‘‡ note that there is no '()' behind AppCompatActivity
      class MainActivity : AppCompatActivity {
          constructor() {}}Copy the code

      Kotlin distinguishes constructors from other fun by using the constructor keyword alone.

  • Override the different

    • In Java@OverrideIt’s in the form of annotations.
    • In the KotlinoverrideIt becomes a keyword.
    • Kotlin omittedprotectedKeywords, that is, from KotlinoverrideThe visibility of a function is inherited from its parent class.

In addition to these obvious differences, there are a few differences that are not visible from the above code, but will be visible when you write a class that extends MainActivity:

  • The MainActivity in Kotlin cannot be inherited:

    🏝 ️// This type is final, so it cannot be inherited from
    class NewActivity: MainActivity() {}Copy the code

    The reason is that classes in Kotlin are final by default, whereas classes in Java are final only if the final keyword is added.

    Is there any way to remove the final restriction? We can use open to do this:

    🏝 ️open class MainActivity : AppCompatActivity() {}
    Copy the code

    That way, we can inherit it.

    🏝 ️class NewActivity: MainActivity() {}
    Copy the code

    Note, however, that NewActivity is still final at this point, that is, open has no superclass to subclass heritability.

    Override is hereditary:

    🏝 ️class NewActivity : MainActivity() {
        // πŸ‘‡onCreate is still override
        override fun onCreate(savedInstanceState: Bundle?).{... }}Copy the code

    To disable the heritability of Override, just do this:

    🏝 ️open class MainActivity : AppCompatActivity() {
        // πŸ‘‡ adds the final keyword, as in Java, to disable the inheritance of override
        final override fun onCreate(savedInstanceState: Bundle?).{... }}Copy the code
  • In addition to the open keyword, Kotlin has the same abstract keyword as Java. The difference between the two keys is that classes modified by the abstract keyword cannot be instantiated directly, and are usually used with the abstract modified functions. Of course, You can also do without this abstract function.

    🏝 ️abstract class MainActivity : AppCompatActivity() {
        abstract fun test(a)
    }
    Copy the code

    But subclasses need to implement this abstract function if they want to instantiate:

    🏝 ️class NewActivity : MainActivity() {
        override fun test(a){}}Copy the code

Once we have declared a class, we can instantiate it using the new keyword in Java:

β˜• ️void main(a) {
    Activity activity = new NewActivity(); 
}
Copy the code

In Kotlin, instantiating an object is much easier without the new keyword:

🏝 ️fun main(a) {
    var activity: Activity = NewActivity()
}
Copy the code

From MainActivity, we learned that the declarations of classes in Java and Kotlin focus on the following:

  • Class visibility and openness
  • A constructor
  • inheritance
  • Override function

Type judgment and strong turn

In the instantiation example, we are actually assigning a subclass object to a variable of the parent class. This concept is called polymorphism in Java, and Kotlin also has this feature, but in practice we will most likely encounter functions that require subclasses.

Let’s first define a function in a subclass:

🏝 ️class NewActivity : MainActivity() {
    fun action(a){}}Copy the code

This function cannot be called:

🏝 ️fun main(a) {
    var activity: Activity = NewActivity()
    // πŸ‘†activity cannot call the action method of NewActivity
}
Copy the code

In Java, you need to use the instanceof keyword to determine the type and then call it by strong:

β˜• ️void main(a) {
    Activity activity = new NewActivity();
    if (activity instanceofNewActivity) { ((NewActivity) activity).action(); }}Copy the code

Kotlin also has a similar solution that uses the is keyword for “type determination”, and since the compiler can do type inference, it helps to omit the strong form:

🏝 ️fun main(a) {
    var activity: Activity = NewActivity()
    if (activity is NewActivity) {
        // the strong version of πŸ‘‡ is omitted due to type inference
        activity.action()
    }
}
Copy the code

So can not type judgment, direct strong transfer to use? The as keyword can be used:

🏝 ️fun main(a) {
    var activity: Activity = NewActivity()
    (activity as NewActivity).action()
}
Copy the code

This is fine if the cast is correct, but if the cast is incorrect, the program will throw an exception.

We would prefer to be able to strong-cast safely and handle strong-cast errors more gracefully.

This, of course, was taken into account in Kotlin’s design. We could use as? To solve:

🏝 ️fun main(a) {
    var activity: Activity = NewActivity()
    / / πŸ‘‡ '(activity as? NewActivity)' is followed by an object of nullable type, so you need to use '? . 'to call
    (activity as? NewActivity)? .action() }Copy the code

This means that subsequent calls are executed if strong-cast succeeds, and not if strong-cast fails.


Well, that’s enough about Kotlin’s variables, functions, and types, leaving you with two questions to ponder:

  1. If a subclass overrides the override function of its parent class, can it change its visibility?

  2. What is the difference between the following?

    🏝 ️ activityas? NewActivity
    activity as NewActivity?
    activity as? NewActivity?
    Copy the code

exercises

  1. Use Android Studio to create a new Kotlin-based project (Empty Activity) and add a new property (type non-empty)View), initialize it in the onCreate function.
  2. Declare an argument to beView?Type method, passed in the previous oneViewType property, and prints it in the methodView?Id.