首页 > 其他分享 >Kotlin内部实现-01-companion_object

Kotlin内部实现-01-companion_object

时间:2023-12-22 16:45:41浏览次数:40  
标签:u0002 01 Kotlin object Companion import companion

Kotlin内部实现_01_companion object

1. companion object 概述

在 Kotlin 中,companion object 是一种特殊的对象声明,它用于在类内部创建静态成员。这是 Kotlin 对 Java 中静态成员的一种替代方案,因为 Kotlin 自身不直接支持传统意义上的静态方法或属性。

主要用途和特点包括:

  1. 静态方法和属性companion object 允许你在不创建类的实例的情况下,通过类名直接访问这些方法和属性。

  2. 实现接口:与普通对象一样,companion object 可以实现接口。

  3. 工厂方法和单例:常用于创建工厂方法或实现单例模式。

  4. Java 兼容性:对于 Java 代码来说,companion object 中的成员看起来就像是传统的静态方法和属性。

为什么需要 companion object

  • 语言设计哲学:Kotlin 设计上倾向于更明确和安全的编程范式。通过将静态成员放在 companion object 中,Kotlin 确保了静态部分和实例部分的明确区分。
  • 功能丰富:与 Java 的静态成员相比,companion object 提供了更多的灵活性和功能,如实现接口、继承等。
  • 互操作性:这种设计同时保证了与 Java 的良好互操作性,因为 Java 代码可以像访问静态成员一样访问 companion object 的成员。

总之,companion object 是 Kotlin 对 Java 静态成员概念的一种扩展和增强,使代码更加灵活和表达力更强。

2. companion object 底层实现

companion object 在底层是通过静态内部类实现的,但它提供了比传统的静态内部类更多的功能和灵活性。 在 Kotlin 中,companion object 的底层实现确实与 Java 中的静态内部类相似,但有一些独特之处。

  1. 静态内部类的类似性:在 JVM 字节码层面,companion object 被编译成其外部类的一个静态内部类。这意味着,尽管在 Kotlin 语言层面你看不到传统的静态方法和属性,但在编译后的 Java 字节码中,它们是作为静态内部类实现的。

  2. 实例化机制:每个包含 companion object 的类都会自动拥有一个名为 Companion 的静态内部类的实例。这个实例在类加载时被创建,并且是单例的。当你在 Kotlin 代码中访问 companion object 的成员时,实际上是在访问这个单例实例的成员。

  3. 成员访问:当从 Kotlin 访问 companion object 的成员时,可以直接通过外部类的名称进行访问,这与访问 Java 中的静态成员类似。但从 Java 代码中访问时,需要通过 Companion 实例来访问这些成员,除非使用 @JvmStatic 注解。

  4. @JvmStatic 注解:如果你想让 companion object 中的某个成员真正成为 JVM 静态成员,可以使用 @JvmStatic 注解。这样,从 Java 代码中访问这些成员时就不需要通过 Companion 实例。

  5. 接口实现和扩展性companion object 可以实现接口和拥有自己的扩展函数,这些都是传统的静态内部类无法做到的。

3. companion object 深入验证

  1. 在Android Studio中编写一个测试类:MainActivity
package com.yongdaimi.kt.kotlintest

import android.os.Bundle
import android.view.LayoutInflater
import androidx.appcompat.app.AppCompatActivity
import com.yongdaimi.kx.kotlintest.databinding.ActivityMainBinding

class MainActivity : AppCompatActivity() {

    private lateinit var mViewBinding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        mViewBinding = ActivityMainBinding.inflate(LayoutInflater.from(this))
        setContentView(mViewBinding.root)
    }

    companion object {
        const val WRITE_FILE_NAME: String = "myData"
        fun getNameValue() = "20"
    }

}
  1. 依次点击菜单栏“Tools”-"Kotlin"-"Show Kotlin Bytecode":

    image-20231222163351513

这个时候AS会自动生成MainActivity所对应的字节码文件:

image-20231222163555192

  1. 反编译:

    package com.yongdaimi.kx.kotlintest;
    
    import android.content.Context;
    import android.os.Bundle;
    import android.view.LayoutInflater;
    import android.view.View;
    import androidx.appcompat.app.AppCompatActivity;
    import com.yongdaimi.kx.kotlintest.databinding.ActivityMainBinding;
    import kotlin.Metadata;
    import kotlin.jvm.internal.DefaultConstructorMarker;
    import kotlin.jvm.internal.Intrinsics;
    import org.jetbrains.annotations.NotNull;
    import org.jetbrains.annotations.Nullable;
    
    @Metadata(
       mv = {1, 9, 0},
       k = 1,
       d1 = {"\u0000 \n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\u0018\u0000 \t2\u00020\u0001:\u0001\tB\u0005¢\u0006\u0002\u0010\u0002J\u0012\u0010\u0005\u001a\u00020\u00062\b\u0010\u0007\u001a\u0004\u0018\u00010\bH\u0014R\u000e\u0010\u0003\u001a\u00020\u0004X\u0082.¢\u0006\u0002\n\u0000¨\u0006\n"},
       d2 = {"Lcom/yongdaimi/kx/kotlintest/MainActivity;", "Landroidx/appcompat/app/AppCompatActivity;", "()V", "mViewBinding", "Lcom/yongdaimi/kx/kotlintest/databinding/ActivityMainBinding;", "onCreate", "", "savedInstanceState", "Landroid/os/Bundle;", "Companion", "app_debug"}
    )
    public final class MainActivity extends AppCompatActivity {
       private ActivityMainBinding mViewBinding;
       @NotNull
       public static final String WRITE_FILE_NAME = "myData";
       @NotNull
       public static final Companion Companion = new Companion((DefaultConstructorMarker)null);
    
       protected void onCreate(@Nullable Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          ActivityMainBinding var10001 = ActivityMainBinding.inflate(LayoutInflater.from((Context)this));
          Intrinsics.checkNotNullExpressionValue(var10001, "ActivityMainBinding.infl…ayoutInflater.from(this))");
          this.mViewBinding = var10001;
          var10001 = this.mViewBinding;
          if (var10001 == null) {
             Intrinsics.throwUninitializedPropertyAccessException("mViewBinding");
          }
    
          this.setContentView((View)var10001.getRoot());
       }
    
       @Metadata(
          mv = {1, 9, 0},
          k = 1,
          d1 = {"\u0000\u0014\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0002\b\u0086\u0003\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\u0006\u0010\u0005\u001a\u00020\u0004R\u000e\u0010\u0003\u001a\u00020\u0004X\u0086T¢\u0006\u0002\n\u0000¨\u0006\u0006"},
          d2 = {"Lcom/yongdaimi/kx/kotlintest/MainActivity$Companion;", "", "()V", "WRITE_FILE_NAME", "", "getNameValue", "app_debug"}
       )
       public static final class Companion {
          @NotNull
          public final String getNameValue() {
             return "20";
          }
    
          private Companion() {
          }
    
          // $FF: synthetic method
          public Companion(DefaultConstructorMarker $constructor_marker) {
             this();
          }
       }
    }
    
    
  2. 注意这几处:

       @NotNull
       public static final String WRITE_FILE_NAME = "myData";
       @NotNull
       public static final Companion Companion = new Companion((DefaultConstructorMarker)null);
    
       public static final class Companion {
          @NotNull
          public final String getNameValue() {
             return "20";
          }
    
          private Companion() {
          }
    
          // $FF: synthetic method
          public Companion(DefaultConstructorMarker $constructor_marker) {
             this();
          }
       }
    
  3. 明白了它的原理之后,就知道在java层该如何访问了:

    public class SplashActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_splash);
    
            String writeFileName = MainActivity.WRITE_FILE_NAME;
            String nameValue = MainActivity.Companion.getNameValue();
        }
    
    }
    

<完>

标签:u0002,01,Kotlin,object,Companion,import,companion
From: https://www.cnblogs.com/yongdaimi/p/17921940.html

相关文章

  • Python DRF基础使用01
    目录1,web应用模式(了解)2,restful风格介绍(了解)3,restful设计风格(了解)4,restful案例(了解)5,数据准备6,查询所有数据(理解)7,创建对象(理解)8,获取单个对象(理解)9,修改单个对象(理解)10,删除单个对象(理解)11,DRF魅力展示(了解)12,序列化器概述(了解)13,序列化器定义(掌握)1......
  • 01--python基础回顾
    一关于爬虫的特殊性1.网站的多变性:这个是爬虫的魅力.要全方位的去思考.就像找漏洞一样.思维逻辑不可能是固定的达到目的即可,不要死磕牛角尖2.访问频率调低爬虫程序如果编写的不够完善.访问频率过高.很有可能会对服务器造成毁灭性打击所以不要死盯着一个网站干.请......
  • 重庆大学重大计算机考研917统考2016~2023年复试/录取情况
    重庆大学计算机学院917考研交流KC群进入KC群可点击下方链接:重大计算机考研KC群  添加图片注释,不超过140字(可选)  添加图片注释,不超过140字(可选)  添加图片注释,不超过140字(可选)  ......
  • 【pwn】[ZJCTF 2019]EasyHeap --fastbin攻击,house of spirit
    首先查看一下附件的保护情况可以看到,got表是可修改的状态接着看主函数的逻辑非常典型的菜单题,接着分析每一个函数的作用unsigned__int64create_heap(){inti;//[rsp+4h][rbp-1Ch]size_tsize;//[rsp+8h][rbp-18h]charbuf[8];//[rsp+10h][rbp-10h]BY......
  • c语言回溯法实现01背包问题
    w[N],p[N]中直接装的是样例,可以修改数据,别忘记修改N。#define_CRT_SECURE_NO_WARNINGS#include<stdio.h>#include<stdlib.h>#defineN5//0-1背包,用三种算法实现//动态规划,贪心,回溯,分支限界voidOutput(intbestx[]);intConstraint(intt);floatBound(inti);voidB......
  • P5289 [十二省联考 2019] 皮配 题解
    题目链接点击打开链接题目解法题意比较复杂,形式化一下题意是:一些人和一些城市,每个人属于一个城市,每个人属于\(A/B/C/D\)队,需要满足:每个城市中的人要么都属于\(AC\)或\(BD\),且\(A+C\leC_0,\;B+D\leC_1,\;A+B\leD_0,\;C+D\leD_1\)暴力\(dp\)是\(f_{i,a,b,c}\)表......
  • 记录一次openpyx使用rich_text报错AttributeError: 'TextBlock' object has no attrib
    先说解决办法:pipinstalllxml报错截图:当时在两个环境中分别使用相同版本openpyxl,相同的代码,一个环境中能成功,另外一个一直报错。排查结果如下:根据报错找到文件:File"\openpyxl\worksheet_writer.py",line147,inwrite_row在155行到158行看到如下代码:ifLXML:......
  • class073 背包dp-01背包、有依赖的背包【算法】
    class073背包dp-01背包、有依赖的背包【算法】算法讲解073【必备】背包dp-01背包、有依赖的背包code1P1048[NOIP2005普及组]采药//01背包(模版)//给定一个正数t,表示背包的容量//有m个货物,每个货物可以选择一次//每个货物有自己的体积costs[i]和价值values[i]//返回在......
  • Landsat7_C2_ST数据集2019年1月-2022年12月
    简介:Landsat7_C2_ST数据集是经大气校正后的地表温度数据,属于Collection2的二级数据产品,以开尔文为单位测量地球表面温度,是全球能量平衡研究和水文模拟中的重要地球物理参数。地表温度数据还有助于监测作物和植被健康状况,以及极端高温事件,如自然灾害(如火山爆发、野火)和城市热岛效......
  • VisualStudio2019创建Code Snippet
    CodeSnippet是什么CodeSnippet,与其称其为代码片段(CodeBlock),将它翻译成代码模板(CodeTemplate)可能更合适一些。任何一段代码都可以叫做代码片段,我们这里要讲的不是这种随性的东西,而是一种快速生成代码的快捷方式,通过它可以有效地提高我们的编程效率。举个例子,假如你在C#......