[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
相关推荐
lemon_sjdk2 小时前
LWJGL教程(2)——游戏循环
java·人工智能·算法·游戏
weixin_524749962 小时前
MVCC(多版本并发控制)介绍及实现原理
java·数据库
skylijf3 小时前
C++ Primer(第5版)- Chapter 7. Classes -004
java·开发语言
泉城老铁3 小时前
springboot+druid预防连接断开、断开后自动恢复
java·后端·架构
m1cr0wave3 小时前
javaweb的几大常见漏洞
java·安全·web
泉城老铁3 小时前
Spring Boot 中使用 Druid 连接池进行极致优化
java·后端·架构
Reggie_L3 小时前
JVM-Java
java·jvm·python
何中应3 小时前
EasyExcel使用
java·后端·excel
智_永无止境3 小时前
FastExcel:革新Java生态的高性能Excel处理引擎
java·excel·fastexcel
巴拉巴巴巴拉3 小时前
Maven 配置文件核心配置:本地仓库、镜像与 JDK 版本
java·开发语言·maven