[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
相关推荐
聚美智数4 小时前
智能结构化识别-图片结构解析-图像结构化解析-照片结构化解析
android·java·数据库
十年Java程序媛4 小时前
Java枚举Enum完整教程|替代静态常量,开发与面试要点
java·开发语言·spring boot·后端·面试
我是人✓4 小时前
SpringBoot静态资源映射揭秘
java·spring boot·后端
土豆.exe5 小时前
nf_tables 的 verdict 被读了两次:一个十年未闭合的位域错配
java·数据库·网络安全·缓存
小坏讲微服务6 小时前
刚发布一个月的JDK 27,为什么我建议你立刻升级?
java·开发语言·spring boot·spring·架构·求职招聘·springboot4
kunicoding6 小时前
多线程编程核心概念详解:从线程基础到并发安全
java·jvm·安全
snow@li6 小时前
SpringBoot:核心注解全景梳理 / @xxx 叫“注解”(Annotation)
java·spring
devilnumber7 小时前
避坑_IDEA 提取方法(Extract Method)工具
java·ide·intellij-idea
鬼手点金7 小时前
Agent 的学习机制:后训练、上下文学习与外部化学习
java·人工智能·git·学习·自动化·nanogpt
小陈不好吃7 小时前
equals 与 hashCode 的契约关系:从 HashMap 到 Lombok 注解
java·hashmap·lombok