为什么 Swift 推荐 Bool 用 is 前缀,而 Java 常规避
最近在读阿里出品的 Java 开发手册,其中有一条规则是:
POJO 类中的任何布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列化错误。
这条规则让 iOS 开发出身的让感到好奇:为什么 Swift 推荐 Bool 用 is 前缀,而 Java 却要避免这种命名?
Java:JavaBeans 规范带来的解析差异
先从 Java 说起。JavaBeans 是一套基于命名约定的组件模型,核心是通过 getX()/isX()/setX() 的方法名推断 “属性名”,很多框架会借助 java.beans.Introspector 与 PropertyDescriptor 进行反射解析并调用访问器。
因此 Java 生态广泛依赖 JavaBeans 规范,布尔字段如果直接叫 isReady,可能被推断为 ready 或 isReady,在不同框架之间容易产生不一致。
private boolean isReady;
public boolean isReady() {
return isReady;
}
public void setReady(boolean ready) {
this.isReady = ready;
}
底层上,框架往往先解析出属性名,再按属性名绑定或序列化,这就是 is 前缀产生歧义的根因。
因此更稳妥的做法通常是:字段用 ready、enabled 这类名,getter 用 isReady(),避免字段名本身带 is。
Objective-C:getter 推荐 is,但属性名更像形容词
作为早期 iOS 开发的代表,Objective-C 的 @property 是编译期语法糖,编译器会生成 ivar 与 getter/setter,运行时通过 objc_msgSend 做消息分发,KVC 则按访问器和 ivar 规则查找属性。
Cocoa 命名规则建议 BOOL 的 getter 用 is / has / should,但属性名本身更倾向“形容词”。常见写法是用自定义 getter:
@property (nonatomic, getter=isHidden) BOOL hidden;
这样读取时是 isHidden,setter 仍然是 setHidden:,语义清晰,也避免属性名叫 isHidden 带来的 setter 命名怪异。
Swift:语义优先,不存在 JavaBeans 歧义
到了 Swift 的时代,属性访问是编译期语义。obj.property 对于存储属性会被编译为内存偏移的直接读写,计算属性则调用 getter/setter;类的动态行为主要由静态派发或虚表派发完成,只有标记 @objc 或 dynamic 时才会走 Objective-C 运行时,因此不会依赖 JavaBeans 式的命名解析。
Swift 的 API 设计指南强调“读起来像断言”,所以 isEnabled、isHidden 这类名字非常自然,也不会出现 is 前缀被剥离的歧义。
if view.isHidden {}
Python:属性访问直接对应名字
既然提起了这个问题,就连带着另外一个我经常使用的开发语言 Python 一起研究一下。
Python 的属性读取会进入 __getattribute__,按实例字典、类字典与描述符协议解析,@property 也是用描述符实现 getter/setter。由于查找基于字典与描述符,而不是命名约定,所以不会出现 JavaBeans 的歧义。
约定上常用 is_、has_ 前缀表达布尔语义,但这只是命名习惯。
class User:
def __init__(self):
self.is_ready = False
小结
Java:字段避免 is 前缀,getter 用 isX()。
Objective-C:属性名用形容词,getter 用 isX 更符合 Cocoa。
Swift:放心用 is/has/should,语义更强。
Python:用 is_ 只是风格选择,不涉及解析冲突。