[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
相关推荐
索荣荣22 分钟前
Java Session 全面指南:原理、应用与实践(含 Spring Boot 实战)
java·spring boot·后端
Amumu1213827 分钟前
Vue Router(二)
java·前端
念越1 小时前
数据结构:栈堆
java·开发语言·数据结构
千寻技术帮1 小时前
10333_基于SpringBoot的家电进存销系统
java·spring boot·后端·源码·项目·家电进存销
dear_bi_MyOnly1 小时前
【多线程——线程状态与安全】
java·开发语言·数据结构·后端·中间件·java-ee·intellij-idea
jiaguangqingpanda2 小时前
Day36-20260204
java·开发语言
tb_first2 小时前
万字超详细苍穹外卖学习笔记4
java·spring boot·笔记·学习·spring·mybatis
努力写代码的熊大2 小时前
c++异常和智能指针
java·开发语言·c++
山岚的运维笔记2 小时前
SQL Server笔记 -- 第15章:INSERT INTO
java·数据库·笔记·sql·microsoft·sqlserver
Yvonne爱编码2 小时前
JAVA数据结构 DAY5-LinkedList
java·开发语言·python