Kotlin travel and the like with interfaces

This article is based on Kotlin’s 1.2.x concept of “functions” and “methods” without making a special distinction

Just to interrupt, the next preview of “Objects and Extensions”, please pay attention

The first article, “Kotlin drives from shallow to Deep,” provides a summary map of Kotlin’s work. Through it, we have a general idea of what place (language) it is, what attractions (features) it has, and how to play it quickly. Get on the bus, now we come to the first stop – class and object, next to see what fun things!

For those of you who have come from Java, this is a bit more familiar, but there are still a few places to explore. Here we go

Classes and interfaces

This section introduces the construction and use of classes in Kotlin, as well as the concept of Kotlin’s unique classes and attributes. After all, as a multi-paradigm language, object-oriented support is not ambiguous.

In addition, this section will also explain the necessary implementation behind it on the JVM, and see how the compiler magic sugar is implemented

The interface is similar to Java 8, providing properties that do not record state (there are no fields behind the scenes) and default methods. The rest is similar, so let’s look at the class:

Constructor and initialization

Declare a class in Java:

public class User { 

    User(String _name) {
        name = _name;
    }

    private String name;

    public String getName(a) {
        return name;
    };

    public void setName(String _name) {
        name = _name;
    };
}
Copy the code

Declare a class in Kotlin:

open class User (var name: String)
Copy the code

These two things are equivalent. Because classes in Kotlin are final by default, you need to add an open if you want them to be inherited. Note also that a property named is declared. Unlike Java fields, the property is public by default.

For Kotlin’s class declaration, the full version should look like this:

open class User constructor(var name: String) {

	var age = 18
	lateinit var message: String

	constructor() : this(name = "yy")

	init {
		message = "Hello $name"}}Copy the code

Take a look at the new things you encounter bit by bit. Constructor () {constructor () {age (); message () {age () {message (); But I haven’t been able to initialize it yet, I will initialize it later before I use it, so don’t worry about reporting an error to me. So we’re done, and we initialize message in an init block. I’m also using Kotlin’s string concatenation, which goes without saying here.

If there is a primary constructor, there is a secondary constructor. Here we formally declare a sub-constructor that has no arguments of its own and delegates to the primary constructor (which must be delegated if a class has a primary constructor), initializing the name attribute to “YY.”

In general, the init block is used when you need to run a piece of initialization code while constructing a class, such as initializing a View in Android:

Lateinit is usually used where there is a lifecycle or dependency injection initialization. It is not recommended to abuse lateInit because as your project code gets bigger, it is very likely that you will not be able to control that all calls are properly initialized. Then will be thrown a UninitializedPropertyAccessException anomalies. Of course, if you can also protect it in use, the principle is that runtime reflection takes a Boolean value recorded in the Kproperty:

if (::message.isLateinit) {
    println(message)}
Copy the code

So with that in mind, we can simply create a class, so for most of the time, when we’re designing frameworks to reuse code, we need to use inheritance, and this concept is pretty much the same in object-oriented languages, and most of what you know about inheritance in Java can be easily transferred to Kotlin, Now let’s see what Kotlin did.

inheritance

One of the most common practical examples of Android is the inheritance of various Views. Here’s an example:

  • MyView: delegates the secondary constructor to the parent constructor
  • MyView2: Delegates the primary constructor to the parent constructor
  • MyView3:@JvmOverloadsThe annotation modifier constructor represents generationJavaMultiple overloaded constructors in the familiar form. Combined with that, I’m sure you get most of it.

One thing worth mentioning here is named functions and default arguments. You can see that MyView3 only declares a primary constructor, which is equivalent to three overloaded methods in Java. But to actually generate the overloaded methods we’re familiar with on the JVM, you need to modify the main constructor with @jvMoverloads. The generated overloaded methods are generated in the default order of the parameters. You can probably guess what default arguments mean. In Kotlin, if a multi-parameter function has default arguments, we can call it just as we would in Java. The difference is that when we ignore these default arguments, they will use the default values you defined. A related concept is named functions, or named parameters, which are called by specifying the name of the parameter, and are not supported in Java.

Inheriting a parent class may require the implementation of its abstract methods or Override the default implementation of certain methods. Unlike Java, which uses the @Override annotation for weak constraints, overriding properties and methods requires explicit Override in Kotlin. Var overrides val’s attributes, but not the other way around.

There is a case where multiple implementations of the same member inherit from a direct superclass:

attribute

Properties have been mentioned many times above, and now we will analyze them in detail.

Declare the full syntax of an attribute

var <preopertyName>[: PropertyType] [= <property_initializer>]
    [<getter>]
    [<setter>]

val <preopertyName>[: PropertyType] [= <property_initializer>]
    [<getter>]
Copy the code
  • Var declares mutable properties and provides default getters and setters
  • Val declares a read-only property and provides the default getter, equivalent toJavafinal

If the PropertyType can be inferred, the PropertyType can be omitted. Initializers are not required, depending on the situation. In addition, the compiler provides default implementations of getters and setters, or it can override the implementation itself. Developing a good programming style is conducive to designing a robust system

An example of a custom property initializer is quoted from the official documentation:

val isEmpty get() = this.size == 0
Copy the code

I believe this code is self-expression, no explanation, details can refer to the official documentation.

Const attribute

  • Compile-time global constantsconstFlag, cannot be a reference type

    How are they different? Look at the bytecode corresponding toJavaThe implementation of the code is straightforward:

Kotlin has no static properties or methods, and is generally implemented with package-level functions, or with companion objects (as this guy will say in the next article).

Feature class

Kotlin has done a lot of good for us by eliminating a lot of template code, about classes, what does that do?

Data classes

Those of you who have done Java development know the famous POJO classes and Java beans. If you have counted the number of lines of code, you will find that they occupy a lot of space in your project. Getter setter methods, even if they have supports such as IDEA, are also a little tedious. Not to mention carefully overwriting their hasCode and equals methods, etc. What, you may ask, can Kotlin do for us? And look:

  • Two Java fields are generated with their corresponding getter setter methods

  • Generates the corresponding componentN function to support destructuring (also described in the following article) :

    val (name, age) = User()
    Copy the code

  • The copy function copies an instance object of a data class and allows you to modify some of its values

  • Provides an implementation of equals/hashCode pairs and toString methods (if implementations of these functions are provided, they will not be generated automatically and existing functions will be used)

This is the secret behind the compiler. As for the more detailed use of data classes, it is worth noting that some of the pits are not Kotlin’s pits.

One is that even if the attributes of your data class are declared as non-nullable versions, the runtime may be empty using deserialization frameworks such as Gson, essentially because of reflection modification at runtime:

  • The deserialization framework may not be able to find a matching constructor and initialize it. At this point, the deserialization framework will stop and return it in timenull; Some throw an exception directly; What is more (mainly)gson(Adopt regardlessJavaThe problem arises when the underlying API categorizes object memory without doing any initialization. Because it is relevant to the business, the corresponding solution will not be mentioned. For example, use the characteristics of default parameters, and find a good solution should not be a problem.
  • This indicates that the data returned by the interface also needs special attention when converting.

In addition, an all-open Gradle plugin is available that weaves a no-argument constructor into the bytecode of the required class to ensure that objects can be safely created if no suitable constructor is found.

Sealed class

A class with sealed, as its name implies, has a restricted class inheritance structure, similar to an enum class, except that it can have multiple instances of different states, which means it has more flexibility than an enum class. If you have a restricted class inheritance structure, and expect the state of the subclass to be constant, there can only be one instance, then use enumeration, otherwise closed classes will be useful.

Note that a closed class abstraction itself cannot be instantiated; a subclass is a finite collection. Of course, enumerations in when expressions are complete and you don’t need an else branch.

Nested and inner classes

If the class is nested, the default is nested class, inner class needs to be decorated. The difference is that the former is equivalent to Java’s static inner class, while the latter holds references to the outer class. The last official chart shows:

Well, today’s journey is here, I hope you are not so tired

digression

This series of articles is interpenetrating, especially for beginners. Some things may be obscure now, but in order to ensure a clear structure, some things mentioned in advance will be explained in detail later, which will be easy to understand when you come back. The next article focuses on objects and extensions:

  • Object statement
  • Object expression
  • Associated object
  • extension
  • entrust

Stay tuned


In addition, the original text has any mistakes and improvements, welcome to contact me to correct and improve, any questions can also contact me to communicate. Welcome to subscribe to like oh, not regular updates ~

Disclaimer: This is the original, please contact the author

The statement

This article was first published onMy column

The original link