当前位置: 首页 > news >正文

【解密 Kotlin 扩展函数】顶级函数和顶级属性(十五)

导读大纲

      • 1.1.1 摆脱静态实用类的束缚--顶级函数
      • 1.1.2 更改顶级声明所在的类名
      • 1.1.3 顶层属性

1.1.1 摆脱静态实用类的束缚–顶级函数

  1. 我们都知道,作为一种面向对象的语言,Java要求将所有代码都写成类的方法

    • 通常情况下,这样做效果很好,但在现实中,几乎每个大型项目
      1. 最终都会产生大量不属于任何一个类的代码
    • 有时,一个操作会与两个不同类的对象一起工作
      1. 这两个类对该操作起着同等重要的作用
    • 还有一些时候,虽然只有一个主对象
      1. 不想通过将操作添加为实例方法来臃肿其 API
    • 因此,你最终会得到不包含任何状态或实例方法的类—实用工具类
      1. 这种类只充当几个静态方法的容器
    • JDK 中的 Collections 类就是一个很好的例子
      1. 要在开源项目中找到其他例子,请查找名称中包含 Util 的类
  2. 在 Kotlin 中,不需要创建那些毫无意义的类

    • 相反,可以直接将函数放在源文件的顶层,任何类的外边
      1. 这些函数仍然是文件顶层声明的包的成员
    • 如果想从其他包中调用这些函数,仍然需要导入它们
      1. 不必要的额外嵌套层不复存在
  3. 创建一个名为 Join.kt 的文件,直接将 joinToString 函数放到 strings 包

    • 关于joinToString 函数的实现–传送门
package strings
@JvmOverloads
fun <T> joinToString(collection: Collection<T>,separator: String = ", ",prefix: String = "",postfix: String = ""
) : String {val result = StringBuilder(prefix)for ((index, elem) in collection.withIndex()){if (index > 0) result.append(separator)result.append(elem)}result.append(postfix)return result.toString()
}
  1. 现在,让我们看看编译成相同类的 Java 代码
    • <1> 可以看到,Kotlin 编译器生成的类名包含函数的文件名一致
      1. 大写以匹配 Java 的命名规范,后缀为 Kt
    • <2> 文件中的所有顶级函数被编译为该类的静态方法
    • <3> 因此, 从 Java 中调用该函数像调用其他静态方法一样简单
/* Java */
package strings;
public class JoinKt {                                       // <1>public static String joinToString(// ... ) { // ...  }  // <2>
}
===========================================================
/* Java */
import strings.JoinKt;
// ... 
JoinKt.joinToString(list, ", ", "", "");                   // <3>

1.1.2 更改顶级声明所在的类名

  1. 默认情况下,编译器生成的类名与文件名相对应,并带有 Kt 后缀
    • 更改包含 Kotlin 顶级函数的生成类名称
      1. 可以添加一个 JvmName 注解
    • <1> 将其放在文件开头,包名之前
    • <2> 此时在Java代码中导入时, 可以直接使用新命名"StringFunctions"
@file:JvmName("StringFunctions")                     // <1>
package strings
@JvmOverloads
fun <T> joinToString(collection: Collection<T>,separator: String = ", ",prefix: String = "",postfix: String = ""
) : String {val result = StringBuilder(prefix)for ((index, elem) in collection.withIndex()){if (index > 0) result.append(separator)result.append(elem)}result.append(postfix)return result.toString()
}
======================================================
import java.util.List;
import strings.StringFunctions;                                 // <2>
public class Example {public static void main(String[] args){System.out.println(StringFunctions.joinToString(List.of("1", "2")));}
}

1.1.3 顶层属性

  1. 与函数一样,属性也可以放在文件的顶层
    • 在类外部存储单个数据并不常见,但仍然很有用
    • 例如,你可以使用 var 属性来计算某些操作的执行次数
    • <1> 声明顶级属性
    • <2> 改变属性的值
    • <3> 读取属性的值
var opCount = 0                     // <1>
fun performOperation() {opCount++                       // <2>// ...
}
fun reportOperationCount() {println("Operation performed $opCount times")     // <3>
}
  1. 顶级属性还允许在代码中定义常量: val UNIX_LINE_SEPARATOR = “\n”
    • 默认情况下,顶层属性与其他属性一样
      1. 以访问器方法的形式暴露给 Java 代码
      2. val 属性的 getter 和 var 属性的 getter-setter 对
    • <1> 如果想将常量作为"public static final"字段暴露给 Java 代码
      1. 使其使用更自然,可以使用 const 修饰符对其进行标记
        • 对基本类型和String类型的属性都是允许的
    • <2> 与顶级函数一样,顶级属性在编译后会变成Java的静态字段
      1. 由于这里使用const修饰属性,所以会得到"public static final"字段*
const val UNIX_LINE_SEPARATOR = "\n"            // <1>
=============================================== // <2>
/* Java */
public static final String UNIX_LINE_SEPARATOR = "\n";
  1. 注意 Kotlin 标准库还包含几个有用的顶级函数和属性
    • kotlin.math 包就是一个例子
      1. 为典型的数学运算和三角运算提供有用的函数
    • <1> 例如用于计算两个数字最大值的 max 函数
      1. 它还提供许多数学常量,如欧拉数或圆周率
fun main() {println(max(PI, E))          // <1>// 3.141592653589793
}

相关文章:

  • 极狐GitLab 17.4 重点功能解读【一】
  • springboot基于学习行为的学生选课成绩分析系统设计与实现
  • 计算机视觉实战项目4(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)
  • oracle数据备份和导入
  • RT_Thread内核源码分析(二)——链表和对象管理
  • 2024.9.27 Python面试八股文
  • Linux权限解析
  • 自学网络安全(黑客技术)2024年 90天学习计划
  • 微信小程序加载H5页面及与H5页面通信的实战教程
  • 多旋翼无人机“仿鸟类”精确拦截飞行目标,助力低空安全
  • 鹏哥C语言55-57---二维数组+数组越界+数组传参(冒泡排序)
  • 婚恋交友小程序的设计思路与用户体验优化
  • JavaScript 从事件处理入手的优化
  • 《征服数据结构》哈夫曼树(Huffman Tree)
  • 鸿蒙开发(NEXT/API 12)【硬件(外设扩展驱动开发)】驱动开发服务
  • 「译」Node.js Streams 基础
  • 【剑指offer】让抽象问题具体化
  • express如何解决request entity too large问题
  • Facebook AccountKit 接入的坑点
  • HashMap ConcurrentHashMap
  • Java面向对象及其三大特征
  • RxJS: 简单入门
  • Storybook 5.0正式发布:有史以来变化最大的版本\n
  • Yeoman_Bower_Grunt
  • zookeeper系列(七)实战分布式命名服务
  • 测试开发系类之接口自动化测试
  • 大快搜索数据爬虫技术实例安装教学篇
  • 代理模式
  • 基于组件的设计工作流与界面抽象
  • 将 Measurements 和 Units 应用到物理学
  • 深度学习入门:10门免费线上课程推荐
  • 延迟脚本的方式
  • ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  • # Pytorch 中可以直接调用的Loss Functions总结:
  • #pragma data_seg 共享数据区(转)
  • (1)svelte 教程:hello world
  • (Pytorch框架)神经网络输出维度调试,做出我们自己的网络来!!(详细教程~)
  • (SERIES12)DM性能优化
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (笔记)M1使用hombrew安装qemu
  • (笔试题)合法字符串
  • (多级缓存)缓存同步
  • (附源码)ssm考试题库管理系统 毕业设计 069043
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)Sql Server 保留几位小数的两种做法
  • ****Linux下Mysql的安装和配置
  • .bat批处理(十一):替换字符串中包含百分号%的子串
  • .NET : 在VS2008中计算代码度量值
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .NET Framework、.NET Core 、 .NET 5、.NET 6和.NET 7 和.NET8 简介及区别
  • .NET Micro Framework初体验(二)
  • .NET/C# 使用反射注册事件
  • .NET业务框架的构建
  • .NET与 java通用的3DES加密解密方法
  • /etc/fstab和/etc/mtab的区别