[Kotlin] 为什么 kotlin 的方法名中可以有空格等特殊字符?

为什么 kotlin 的方法名中可以有空格等特殊字符?

Coding conventions 一文的 Names for test methods 部分,有如下的内容

大意是说我们在测试类中可以定义有特殊名称的方法,例如方法名可以是 ensure everything works(由于名称中有空格,所以需要把它写在一对 ````` 字符中)。 但是在 java 中,并不支持这样的语法,那么作为同样运行在 JVM 上的语言,kotlin 是如何做到这一点的呢?

我自己试了试,kotlin 中的普通类中,也可以定义名称中有特殊字符的方法(方法名要写在一对 ````` 字符中)。

结论

Java Virtual Machine Specification 中对方法名的限制比较宽松,空格(即 )等特殊字符允许出现在方法名中,所以 kotlin 并没有违反 Java Virtual Machine Specification

代码

名称中含有特殊字符的方法

我们用如下的 kotlin 代码来进行验证。(请将其保存为 C.kt

kotlin 复制代码
class C {
  fun `hello world function with a special name`(): Unit {
    println("Hello world")
  }
}

kotlinc C.kt 命令可以编译 C.kt。编译后,会生成 C.class。 我们用 javap -v -p C 来查看 C.class 的内容。 和 hello world function with a special name 方法有关的部分如下 ⬇️

text 复制代码
  public final void hello world function with a special name();
    descriptor: ()V
    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
    Code:
      stack=2, locals=1, args_size=1
         0: ldc           #13                 // String Hello world
         2: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
         5: swap
         6: invokevirtual #25                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
         9: return
      LineNumberTable:
        line 3: 0
        line 4: 9
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   LC;

利用 javap 命令给出的结果,可以手动写出对应的 java 代码如下 ⬇️

java 复制代码
// 以下内容是我手动转化出来的,不保证绝对准确,仅供参考

// C 类上有注解,这里略去
public final class C {
  public C() {
    super();
  }
  
  // 注意:实际上 java 不允许在方法名里使用空格,这里只是参考 kotlin 展示一下方法名,请读者不要误会
  public final void `hello world function with a special name`() {
    System.out.println("Hello world");
  }
}

看来在 class 文件中,那个方法的名字也是 hello world function with a special name,我们写点 java 代码来验证一下。

java 代码来调用它

请将如下代码保存为 Main.java

java 复制代码
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Main {
  public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
    C c = new C();
    for (Method method : C.class.getDeclaredMethods()) {
      System.out.println("method name is: [" + method.getName() + "]");
      method.invoke(c);
    }
  }
}

如下的两个命令可以编译 Main.java 并运行其中的 main(...) 方法。

bash 复制代码
javac -g -parameters Main.java
java Main

运行结果如下,可见我们的推测是正确的,class 文件中的文件名也是 hello world function with a special name

解释

根据我们日常写 java 的经验可知,java 代码中是不允许方法名中出现空格等特殊字符的,那么为什么 kotlin 的代码里就允许呢? 我在Java Virtual Machine Specification 的 4.2.2. Unqualified Names 找到了这样的描述

其中对方法名的限制是

  1. 方法名中至少要含有一个 Unicode 字符,且方法名中不允许 出现 . ; [ / 这4个字符
  2. 除了 <init><clinit> 这两个特殊的方法名外,方法名中不允许 出现 < > 这两个字符

这么说来,在 kotlin 中,方法名也仍旧是有限制的,比如方法名中应该不可以出现 . 这个字符。 如果我们把 C.kt 改成如下的内容,那么会发现,编译失败了

kotlin 复制代码
class C {
  fun `hello . world function with a special name`(): Unit {
    println("Hello world")
  }
}

参考资料

  1. Coding conventions 一文的 Names for test methods 部分
  2. Java Virtual Machine Specification 的 4.2.2. Unqualified Names
相关推荐
Leinwin19 小时前
OpenClaw 多 Agent 协作框架的并发限制与企业化规避方案痛点直击
java·运维·数据库
薛定谔的悦19 小时前
MQTT通信协议业务层实现的完整开发流程
java·后端·mqtt·struts
enjoy嚣士20 小时前
springboot之Exel工具类
java·spring boot·后端·easyexcel·excel工具类
罗超驿20 小时前
独立实现双向链表_LinkedList
java·数据结构·链表·linkedlist
alexhilton21 小时前
Compose中的ContentScale:终极可视化指南
android·kotlin·android jetpack
盐水冰21 小时前
【烘焙坊项目】后端搭建(12) - 订单状态定时处理,来单提醒和顾客催单
java·后端·学习
凸头21 小时前
CompletableFuture 与 Future 对比与实战示例
java·开发语言
wuqingshun31415921 小时前
线程安全需要保证几个基本特征
java·开发语言·jvm
努力也学不会java21 小时前
【缓存算法】一篇文章带你彻底搞懂面试高频题LRU/LFU
java·数据结构·人工智能·算法·缓存·面试
攒了一袋星辰21 小时前
高并发强一致性顺序号生成系统 -- SequenceGenerator
java·数据库·mysql