从 C# 迁移到 Java 还是有不习惯的地方,虽然 C# 受到的最大批评就是“抄袭 Java”。看来 C# 还是相对优雅(如果 BCL 能小一点就好了)。话说从 VB .NET 扩展到 C# 的时候我也曾经觉得 VB .NET 好,所以当时的项目 C# 只用来处理 unchecked。现在我觉得 C# 如果写核心库不随便上 GUI 的话还是不错的,特别喜欢 unchecked、lock、unsafe 的设计。
刚上手不习惯的有:
- 没有 
delegate,用内部类实现观察者模式实在是太不优雅了,而且Callable这种东西实现更困难了。 - 所有自定义类型都是 class,而且只能传递引用副本,不存在 ValueType + 
ref。没有 struct 意味着用类似值类型的方法交互时要不断地clone()。 - byte 是有符号的(陷阱!),所有基元数值类型都是有符号的(CLS 规定的值类型中,
Byte无符号,Int16/Int32/Int64有符号,更符合习惯)。(注:SByte、UInt16、UInt32、UInt64虽然在 C# 和 VB .NET 中可用,但是不符合 CLS。) - 发生的异常未必是 throws 声明的,例如对 
HttpExchange的getRequestHeaders()进行add()实际上会触发NotSupportedOperationException,但是Headers基类型没有显式抛出该异常。 - 封装类型(
Integer/Longetc)和基元数值类型(int/longetc)不等价,而且封装类型之间不存在继承。bencode 库中我修改了对整数的解析(从Integer到Long,因为 BEncoding 规范是如此),但是运行报错不能将Integer.valueOf()的结果赋给Long——直至我使用不怎么友善的Number类型作为赋值类型才正常。 - 泛型类型擦除,都收缩到了 
Object,再加上默认虚函数,导致IEquatable<T>这种接口实际上是不能实现的(IEquatable<T>声明了一个bool Equals(T)的方法,C# 中通过自动插入类型+重载解决,Java 中会直接覆盖Object的equals(Object));- 动态类型变长数组创建不可能,
Array.newInstance()需要传递一个Class<?>,但是T.class非法,所以难以获得 T 的类型(Hibernate 中似乎有方案,不过对于现在的我来说太复杂)。 
 
今天去审查,保安很和蔼,出来的时候还问事情办好了没有。