Kotlin topic "Eighteen": object (object expression and object declaration)

Foreword: Reality will tell you that if you don't work hard, you will be trampled to death by life. You don't need to find any excuses. Nothing is the reason to fight.

I. Overview

  Sometimes we need to create an object that is a slight modification of some class without explicitly declaring a new subclass for it. Kotlin handles this situation with object expressions and object declarations. Using the object keyword can achieve functions similar to anonymous inner classes in Java. The purpose of Kotlin's object keyword is to generate a class object that slightly modifies the current class without declaring a new subclass.

The usage of object will be explained below from the two parts of object as an expression and as a declaration.

2. Object expression

Create an object of an anonymous class, object actually exists as an expression, and an anonymous object of type object is generated:

    interface OnClickListener {
    
    
        fun onClick(v: View?)
    }

    private fun setOnClickListener(listener: OnClickListener?) {
    
    }

	//调用
	fun test() {
    
    
	   setOnClickListener(object : OnClickListener {
    
    //匿名内部类
            override fun onClick(v: View?) {
    
    
            }
        })
	}

If the superclass has a constructor, the resulting anonymous object must pass the appropriate constructor arguments to it. If you have multiple supertypes you can specify a comma after the colon to separate them:

    open class People(name: String) {
    
    }//父类有构造函数
    
    fun test() {
    
    
        val people: OnClickListener = object : People("Android"), OnClickListener {
    
    
            override fun onClick(v: View?) {
    
    
                //TODO
            }
        }
    }

Note: If the parent class constructor has input parameters, you must pass the parameters according to the definition of the parent class constructor when generating an anonymous object; if the generated anonymous function has multiple parent implementations, you must specify the type when declaring the object, eg val people: OnClickListener.

If in any case all we need is an object, with no particular superclass, it can be as simple as:

    fun test() {
    
    
        val add = object {
    
    //没有任何超类,只是作为一个对象存在
            val numA: Int = 1
            val numB: Int = 2
        }

         println("numA + numB = ${
      
      add.numA + add.numB}") //打印数据:3
    }

Anonymous objects can only be used as types in local and private declarations. If an anonymous object is used as the return type of a public function or the type of a public property, the actual type of that function or property will be the declared supertype of the anonymous object, or Any if no supertype is declared. Members added to an anonymous object will not be accessible.

    //私有函数,返回类型为匿名对象类型
    private fun privateFoo() = object {
    
    
        val str: String = "private"
    }

    //公有函数,返回对象为超类型,如果没有超类则为Any
    public fun publicFoo() = object {
    
    
        val str: String = "public"
    }
    
    fun test() {
    
    
        val str1 = privateFoo().str // compile success,private修饰的匿名 object 返回的类型是 object 类型
        val str2 = publicFoo().str // compile error,public 修饰的匿名 object 返回的类型是其超类,如果没有超类则是 Any,而 Any 类中没有 str 字段
    }

Anonymous objects have certain restrictions when they exist as functions or properties:

  • When the anonymous object is modified as private, the type returned by its expression is the object type;
  • When an anonymous object is modified as public, the type returned by its expression is the type of its superclass, or the top-level Any type in Kotlin if there is no superclass.

Kotlin allows access to external members inside the anonymous class object. Unlike Java, the external members do not need to be declared as final (Kotlin's val).

    var name: String = "Kotlin"
    
    fun test() {
    
    
        setOnClickListener(object : OnClickListener {
    
    
            override fun onClick(v: View?) {
    
    
                println("匿名object对象访问外部成员:name = $name")//打印:Kotlin
            }
        })
    }

At this time, the external name attribute is used, and there is no need to declare it as immutable.

3. Object declaration

Singletons can be useful in some cases, and Kotlin (after Scala) makes declaring singletons simple. In Kotlin, you don't need to implement singletons yourself like Java, but provide keywords to ensure singletons. This keyword is object. When object modifies a class, the class has only one object.

    object DataProviderManager {
    
    //使用object来声明一个单例对象
        fun registerDataProvider(str: String) {
    
    
            //TODO
        }
    }

This is called an object declaration, and it always has a name after the object keyword. Like variable declarations, object declarations are not expressions and cannot be used on the right-hand side of an assignment statement.

Initialization of object declarations is thread-safe and done on first access. There is no need to consider multithreading like Java does.

If we want to refer to an object, we use its name directly:

	DataProviderManager.registerDataProvider("")

Such objects can have supertypes:

    abstract class MyAdapter {
    
    
        open fun mouseClicked() {
    
     }//open 修饰,子类可重写
    }
    
    fun test() {
    
    
        object : MyAdapter() {
    
    
            override fun mouseClicked() {
    
     }
        }
    }

Note: Object declarations cannot be local (i.e. nested directly within a function), but can be nested within other object declarations or non-inner classes.

When using object as a declaration, you need to pay attention to the following points:

  • object has no rvalue as a declaration, that is, it cannot be assigned to other variables as an expression;
  • When object is used as a declaration, local variables cannot be declared, but it can exist as a class member;
  • When object is used as a declaration, it can inherit the superclass, that is, a singleton can have a superclass.

companion object

Object declarations within a class can be marked with the companion keyword:

    class Student {
    
    
        companion object newInstance {
    
    //伴生对象
            fun create(): People = People("ALL")
        }
    }

Members of the companion object can be invoked simply using the class name as a qualifier:

val instance = Student.create()

The name of the companion object can be omitted, in which case it will be called with the name Companion:

    class Student {
    
    
        companion object {
    
     }
    }

	val companion = Student.Companion

A name used by the class itself (not as a qualifier for another name) as a reference to a companion object of the class (whether named or not). That is, no matter whether the companion object is named or not, as long as the class name containing the companion object is used for assignment, the value is actually the reference address of the internal companion object held by the class:

    class Student {
    
    
        companion object Named{
    
     }
    }
    
  	val student1 = Student
  	
    class Student {
    
    
        companion object {
    
     }
    }
    
	val student2 = Student

Note: Even though the members of a companion object look like static members in other languages, at runtime they are still instance members of the real object, for example, can implement an interface:

    interface Factory<T> {
    
    
        fun create(): T
    }

    class MyClass {
    
    
        companion object : Factory<MyClass> {
    
    //实现接口
            override fun create(): MyClass = MyClass()
        }
    }

	val factory: Factory<MyClass> = MyClass

However, on the JVM, if you use @JvmStaticthe annotation, you can generate the members of the companion object as real static methods and fields, that is, use the @JvmStaticsame as static members in Java. For example, the main method we use is all @JvmStaticannotated, because the Java main method must be static, and the members of the companion object are not static, so an additional static modifier needs to be added to tell the compiler that this is a static method.

Semantic Differences Between Object Expressions and Declarations

There is an important semantic difference between object expressions and object declarations:

  • Where an object expression is used, the object expression is immediately executed (and initialized);
  • Object declarations are lazily initialized on first access;
  • Initializes a companion object when the corresponding class is loaded (resolved), like a Java static initializer.

Source address: https://github.com/FollowExcellence/KotlinDemo-master

Pay attention, don't get lost


Well, everyone, the above is the whole content of this article. The people who can see here are all talents .

I am suming, thank you for your support and recognition, your likes are the biggest motivation for my creation, see you in the next article!

If there are any mistakes in this blog, please criticize and advise, thank you very much!

If you want to become an excellent Android developer, here is the knowledge framework you must master , and move towards your dream step by step! Keep Moving!

Guess you like

Origin blog.csdn.net/m0_37796683/article/details/109048386