C# 与 Java 语言机制与语法的异同
本文是 从 C# 到 Java 系列的文章。此系列文章是为了方便从 C# 转到 Java 平台的工程师快速学习新的语言和平台。整个系列的目录请点击此处浏览。
这篇文章从基础的语言机制、语法层面来分析 C# 和 Java 的不同。部分与虚拟机(CLR | JVM)有关的不同会放在相关的另一篇里,详见总目录。
命名规范
Java
中的方法和变量,无论是否为public
,都要以小写字母开头,其余与 C#
大体相当。
那些简单的同义词或近义词
下面的词汇,在 Java
和 C#
中是 同义
或 近义
的:
- C# 中获取一个对象的类型使用
typeof
关键词,Java 中使用.class
,如String.class
;C# 也可以使用对象实例的GetType
方法,Java 中对应的是getClass
方法。参考链接; - 代表一个对象的类型的类型,C# 为
Type
类型,Java 则为Class
类型。参考链接。 - C# 中的
const
(编译时常量)和readonly
(运行时常量)在Java
中都是final
,同时还代表了一个类不能被继承(等同于C#
的sealed
)。 - Java 中的
native
关键字(声明使用 native 实现的代码)类似于 C# 中的extern
(当声明非托管的外部方法,如动态链接库时使用)。 string
与String
:在 Java 只有后者,在 C# 中前后两者是同义词。- Java 中的
synchronized
等同于 C# 语句块中的lock
,以及 方法体上的特性MethodImplOptions.Synchronized
。 - Java 中的
transient
(短暂)等同于 C# 的NonSerializableAttribute
,代表在序列化中跳过。 - Java 的
...
操作符等同于 C# 的params
。例如:String... args
,则 args 为一个所有参数组成的数组。
值类型与装箱
Java
的值类型(Value Types)仅限于原生类型,如 int
、boolen
等。Java
不允许自定义值类型,即 Java
不存在 C# 中的 struct
。
值类型
的作用可以从以下几个方面来考虑:
- 性能:C# 中的
struct
类型有助于减少 GC、减少内存使用、提高性能,但Java
强大的虚拟机JVM
通过优化部分缓解了这个问题。 - 语义:原生类型无法为
null
,且通过传值方式赋值。
但是,由于 C# 中的值类型通过传值类型赋值造成了意外错误的可能(例如用类似类的方式在杯传递后的值类型中修改成员,试图影响到原有的值),使用值类型要警惕。
值类型在 Java
中不继承于 Object,但 C# 中却继承,这是通过自动装箱实现的。Java 的值类型可以通过装箱变为类实例,比如:
int
=>Integer
float
=>Float
byte
=>Byte
Java
具体的数据类型方面的内容,可以参考本系列文章中的另一篇:数据结构(文章末尾有目录导航)。
泛型
Java
支持泛型,但其支持的方式和 .NET
差别比较大。Java
的泛型使用 类型擦除
实现。所以,你虽然可以设置某个方法或类有一个类型参数 T
,但是你在其实现内部却无法获知与该类型的任何信息,解决方法就是使用一个补偿的 class
类型(类似于 C# 中的 Type
类型)参数手工传递数据类型。
委托,事件
C# 中的委托(delegate
)用于指向固定某个方法原型(一系列参数、某种返回值)的指针(姑且这么叫吧)。Java
中没有 delegate
的概念。
Java 中一般通过接口来实现类似委托的效果。
例如,C#
中假如有下面的定义:
// 定义委托
public delegate void onClickListener(View v);
// 定义委托的实现
public void listener(View v) {
// foo
}
// 使用委托
onClickListener = listener;
onClickListener(this);
在 Java 中可以这样实现。先定义一个接口:
public interface OnClickListener {
void onClick(View v);
}
然后,使用这个接口来存储一个匿名类
,其中带有具体的实现,例如:
OnClickListener listener = new OnClickListener() {
@Override
void onClick(View v) {
// 在此书写代码
}
};
// 调用接口
listener.onClick(someView);
除了使用匿名类,也可以让某个命名类继承此接口:
public class TestClass implements OnClickListener {
void OnClick(View v) {
// 在此书写代码
}
void init() {
OnClickListener listener = this;
// 调用接口
listener.onClick(someView);
}
}
C# 支持事件(event
),其内部是通过委托来实现的。Java 中没有事件的概念。
一般来说,用于事件或委托的情况,Java 会使用接口
来实现。
例如,C# 中的事件:
public event EventHandler SomeEvent; // 事件的发出者
// 事件监听
someInstance.SomeEvent += (sender, args) => { /* xxx */ };
大约等价于 Java
中的方法:
// 先定义接口
public interface SomeEventListener {
void onEvent(int arg);
}
// 搞一个东西用来存储接口的具体实现对象
private ArrayList<SomeEventListener> someEventListeners = new ArrayList<>();
// 在要产生事件的类中,添加一对方法用于监听或取消监听
public void addSomeEventListener(SomeEventListener listener) {
someEventListeners.add(listener);
}
public void removeSomeEventListener(SomeEventListener listener) {
someEventListeners.remove(listener);
}
// 触发事件
for (int i = 0; i < someEventListeners,size(); ++i) {
someEventListeners.get(i).onEvent(5);
}
// 事件监听者,使用 Java8 中才支持的 Lambd 表达式
someInstance.addSomeEventListener(() -> { /* xxx */ });
// 事件监听者,使用 Java7 以前版本的 匿名类
someInstance.addSomeEventListener(new SomeEventListener() {
@Override
void onEvent(int arg) {
// 代码逻辑
}
});
也可以参考这篇文章。
本文是 从 C# 到 Java 系列的文章。此系列文章是为了方便从 C# 转到 Java 平台的工程师快速学习新的语言和平台。整个系列的目录请点击此处浏览。
题外话:我帮你整理了包括 AI 写作、绘画、视频(自媒体制作)零门槛 AI 课程 + 国内可直接顺畅使用的软件。想让自己快速用上 AI 工具来降本增效,辅助工作和生活?限时报名。
© 转载需附带本文链接,依据 CC BY-NC-SA 4.0 发布。