preface
In fact, WHEN I first got to know Kotlin, I refused in my heart. Because I was used to Java code, I felt very uncomfortable when WATCHING Kotlin code, which made me not want to learn it (in fact, I also felt the same way when I learned C language). However, since it is the official Android development language, and now the job requirements are more or less Kotlin, I have no choice but to stick to it.
1. Basic data types
In contrast to Java, Kotlin has no primitive datatypes, which can be seen as Java’s primitive wrapper class.
Java | Kotlin |
---|---|
byte | Byte |
short | Short |
int | Int |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
char | Char |
In addition, strings support templates, see the following:
fun main(a) {
val hello = "Hello"
println("$hello, World!")
println("length = ${hello.length}")}// Output: Hello, World!
// length = 5
Copy the code
An array of 2.
Kotlin does not have [] for array declaration or creation. The eight basic data types have their own array types, as follows:
Java | Kotlin |
---|---|
byte[] | ByteArray |
short[] | ShortArray |
int[] | IntArray |
long[] | LongArray |
float[] | FloatArray |
double[] | DoubleArray |
boolean[] | BooleanArray |
char[] | CharArray |
What about reference types? For example, if we want to use an Array of strings, we need a class called Array
, where generics represent the type of the Array. Similarly, basic data types can be declared with Array
, such as Array
, Array
, and so on.
Initialization can be done either with their constructors or with the global functions provided by Kotlin, arrayOf(), which takes a mutable argument, and emptyArray(), which is an emptyArray.
3. Access rights
Public, protected, private, and internal are the four main access permissions. Default is removed.
Public is the default access, so a lot of times we don’t have to write public.
Protected is unchanged compared to Java.
Private does not change except that it can modify the class level. Why can you modify classes? This is because a file in Kotlin can declare more than one class, and adding private to these classes means that they can only be used in the current file.
Internal means access at the module level, and being identified by internal means only visible to the current module, which is helpful in module encapsulation.
4. Inheritance
In Kotlin, classes, fields, and functions are final by default, except for abstract classes and interfaces. So if we want them to be inheritable, we need to prefix them with the open keyword.
For a normal class, if you want a field or function to be inheritable, it is not enough to add open to the field or function, because the class is still not inheritable, so the class needs to add open to make the field or function truly inheritable.
If you don’t want an open field or function to be inheritable, you can use the final keyword.
5. Variables and functions
Kotlin postpended the type, what does that mean? Here’s an example:
Public final class Person {public final String name; public int age; Public final void talk(String STR) {int temp = 0}} // Kotlin equivalent class Person {val name: String? = null var age: Int = 0 fun talk(str: String?) : Unit { var temp = 0 } }Copy the code
First of all, you can omit semicolons in Kotlin, of course, if you have two statements in a line, you can not omit semicolons in Kotlin, normally we are line by line, then analyze the code above.
Variables:
Since the type is postfixed, Kotlin uses the keywords val and var to represent variables. Val (value) is a read-only variable that cannot be modified after the first assignment; Var (variable) is a common variable in Java.
In Kotlin, there is no default value for a member variable, which requires manual assignment.
In addition, Kotlin supports type inference, so you can declare variables without writing the type, as long as you provide an initial value. However, Kotlin is still a strongly typed language, and mismatches can still result in errors, such as var age = 0. In this declaration, although we do not explicitly provide a type, the initial value indicates that the variable is an Int (the default integer is Int), so we can only assign Int values later.
Function:
Since the type is postpended, Kotlin uses the keyword fun to represent functions, and the argument list follows the posttype rule. Kotlin functions can have default values for arguments, such as:
fun setName(name: String = "aaronzzx"): Unit {
// ...
}
Copy the code
This: What is Unit? Unit = void; Unit = void; Unit = void; Unit = void;
fun setName(name: String = "aaronzzx") {
// ...
}
Copy the code
Functions can also perform type inference, in this case return value inference, only when shorthand functions are used, for example:
fun getAge(a): Int {
return age;
}
/ / equivalent to the
fun getAge(a) = age
// When our function has only one statement, we can abbreviate it even if there is no return value.
// If this statement is not an assignment statement, otherwise "=" conflicts
fun function(a) {
operate()
}
/ / equivalent to the
fun function(a) = operate()
// function with variable arguments
fun function(vararg strs: String) {
for (string in strs) {
println(string)
}
}
// The parameter is an interface or abstract class
fun initView(a) {
HttpUtils.request(object: Callback {
override fun onSuccess(a) {
// ...
}
override fun onFailure(a) {
// ...}})}Copy the code
Ps: You may have found a type followed by a? This means that the variable can be assigned null, which cannot be done without a question mark. This is related to Kotlin’s “empty safety”, which will be explained later.
constructors
Kotlin’s constructor may be confusing at first, but let’s look at how it compares to Java:
// Java
public class Person {
private String name;
private int age;
public Person() { } public Person(String name) { this.name = name; } public Person(String name, int age) { this.name = name; this.age = age; } } // Kotlin class Person( private var name: String? = null, private var age: Int = 0) = null, age: Int = 0 ) { private var name: String? = name private var age: Int = age init {// Optional}} // Equivalent to classPerson() { private var name: String? = null private var age: Int = 0 constructor(name: String?) :this() {
this.name = name
}
constructor(name: String?, age: Int): this() {
this.name = name
this.age = age
}
}
Copy the code
As you can see here, Kotlin has the advantage of crushing. For overloaded constructors, Kotlin needs at least four lines of code.
First, Kotlin can omit the class body, since the main constructor is assigned to the class name, and the main function may or may not have arguments. If you have a parameter, you can prefix the parameter name with the keyword val or var to indicate that the parameter is a member variable. You can modify the keyword with access permissions or annotations.
Init represents the body of the main constructor and can be omitted for no special purpose.
Constructor represents the secondary constructor, which needs to be explicitly invoked if the primary constructor is present.
7. An empty safe
When using Java, NullPointerException is a NullPointerException. So we have to always write null-detection code like this:
public String getMobile(Response response) {
String mobile = null;
if(response ! =null) {
Data data = response.getData();
if(data ! =null) { mobile = data.getMobile(); }}return mobile;
}
Copy the code
Perhaps knowing that Java programmers are in hot water, Kotlin added a language feature called empty security, using it? Nullable variables are identified without being? What about the identified variables? Of course it won’t be null, so we don’t have to write verbose null-detection code for variables that aren’t null, because it doesn’t have null-pointer exceptions.
For nullable variables, we still need to declare nullable, but not in the same way as in Java, so the above code can be written like this:
fun getMobile(response: Response?).: String? {
returnresponse? .data? .mobile }Copy the code
? . Means to call if the current object is not empty, which is much simpler than Java.
8. Partner
What is a Companion object? Take a look at the code below and you should get the idea.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val url = intent.getStringExtra(EXTRA_URL)
// ...
}
companion object {
private const val EXTRA_URL = "EXTRA_URL"
fun start(context: Context, url: String) {
val intent = Intent(context, MainActivity::class.java)
intent.putExtra(EXTRA_URL, url)
context.startActivity(intent)
}
}
}
Copy the code
This object is the Java equivalent of static, except that Kotlin does not have the term static, so if we declare static variables or static functions, we need to use the Companion Object.
In addition to the above code, there may be some things that you don’t understand, so here’s a description.
-
Inheritance and implementation, both using the: operator, separated by different classes or interfaces, and requiring explicit calls to the parent class constructor.
-
First, Kotlin creates objects by omits the new keyword and uses the constructor directly.
-
The @Override annotation in Java becomes the keyword Override in Kotlin, and rewriting is necessary.
-
For getters with no parameters, it can be written as variable names, for example, getIntent() is intent.
-
The const val keyword is used to declare constants. It is only available in Object, Companion Object, and top-level variables.
-
Object anonymous inner class and singleton keyword, if you want to create a singleton class, just write this.
object Singleton { fun exec(a) { // ...}}class Test { fun function(a) { // This is a singleton, although it looks a bit like a static call Singleton.exec() } } Copy the code
-
The top-level variable is more intuitive in code as follows:
const val TAG = "Current file" class MainActivity : AppCompatActivity() { // ... } Copy the code
Top-level variables belong to files, not classes or interfaces, and so on.
9. Branch and loop statements
9.1 Branch Statements
In Kotlin branch statements are expressions, so we can write code like this:
fun function(type: Int) {
// if-else
var str = if (type == 1) {
"Hello, World!"
} else if (type == 2) {
"Goodbye!"
} else ""
// Switch, in Kotlin the keyword becomes when
str = when (type) {
1 -> "Hello, World!"
2 -> "Goodbye!"
else -> ""
}
// Or when takes no arguments
str = when {
type == 1 -> "Hello, World!"
type == 2 -> "Goodbye!"
else -> ""}}Copy the code
When branching statements are expressions, use else unless your condition already includes all cases.
9.2 Loop Statements
While and do-while have been changed in comparison to Java, for example:
fun function(a) {
// for (int i = 0; i < 10; i++)
// Prints the same I value
for (i in 0.9.) {
println(i)
}
for (i in 0 until 10) {
println(i)
}
// The following paragraph will print 10-0 in sequence
for (i in 10 downTo 0) {
println (i)
}
// You can also control the step size
// Print 0, 2, 4, 6, 8, 10
for (i in 0.10. step 2) {
println(i)
}
}
Copy the code
10. Extension functions
We can add a new function to any type, and then call our custom extension function with this class object.
fun String.suffix(suffix: String): String {
return this + suffix
}
fun function(a) {
val str = "Hello"
val newStr = str.suffix(", World!")
println(str)
println(newStr)
}
// Will output: Hello
// Hello, World!
Copy the code
11. Higher-order functions
Higher-order functions are functions that use functions as arguments or return values.
Here we’re going to touch on one thing: closures, which are functions that can read variables inside other functions.
class Operator {
fun add(a: Int, b: Int) = a + b
fun minus(a: Int, b: Int) = a - b
fun change(
a: Int,
b: Int,
closure: (Int.Int) -> Int
): String {
return "${closure(a, b)}"}}fun main(a) {
val operator = Operator()
val add: (Int.Int) - >Int = operator::add
val str1 = operator.change(2.2, add)
val str2 = operator.change(5.2) { a: Int, b: Int ->
a - b
}
println("str1 = $str1")
println("str2 = $str2")}Str1 = 4
// str2 = 3
Copy the code
From the main function, you can see that the variable add has the function type (Int, Int) -> Int, which means that the variable can only be assigned by the function. The object name ::add indicates the type of the function that gets the function.
Then look at the following change function, the code inside the curly braces is closure, although it appears to be redefined a function, when a function’s parameter list the last parameter is a closure, can separate the closure out behind the brackets, and if the parameter list is only a closure, so the brackets can be omitted. In a closure, the -> left side represents the parameters of the closure, and the types can be omitted.
Closures actually look a bit like callbacks, so we write the code and call them in the change function.
Function types can have no arguments, but the parentheses are not omitted, including the return type. For example, a function type with no arguments and no return value can be expressed as :() -> Unit.
Function types can also be nullable, for example:
fun main(a) {
// When plus? , the function type needs to be enclosed in parentheses
val function: (() -> Unit)? = {
// ...
}
// Invoke is invokedfunction? .invoke() }Copy the code