Java 转 C# 极速上手:那些你早已会了九成的东西
相信部分小伙伴都听说过C#和Java,虽然大多数人学习的技术栈都是Java的,当然也包括作者本人,现在因为工作需要学习开始学习C#,发现二者有很多相似的地方,完全可以快速上手,既然如此那我就写一篇文章来带大家快速入门C#
一、整体观感:同一个世界,不同的口音
首先消除陌生感。你会在 C# 里看到这些熟悉的面孔:
-
强类型、面向对象、类、接口、继承、多态 —— Java 有的它全有。
-
单继承 + 多接口实现 —— 一模一样。
-
namespace取代package—— 用来组织代码,用法几乎相同。 -
using取代import—— 导入命名空间。 -
垃圾回收 —— 内存管理不用你操心,同样有堆、栈、托管资源。
语法层面,{} 代码块、; 分号结尾、if/else、for、while、switch 这些控制流都完全一致。你可以把 C# 源代码直接当成看着稍有不同的 Java 来读,基本不会有理解障碍。
好,接下来我们直击关键:和 Java 不一样但你可以瞬间理解的那些地方。
二、类型系统:多了几颗糖,但本质一样
基本类型与包装类型
在 Java 里,int 是基本类型,Integer 是包装类。C# 统一了这一切——所有类型都继承自 System.Object,包括 int、bool 等。
csharp
int age = 18;
string text = age.ToString(); // 基本类型也能直接调用方法,无需装箱
| C# | Java | 备注 |
|---|---|---|
int |
int |
直接用,32 位整数 |
long |
long |
64 位 |
float |
float |
32 位浮点 |
double |
double |
64 位浮点 |
bool |
boolean |
注意名字变了 |
char |
char |
Uni code 16 位 |
string |
String |
小写开头,但都是引用类型 |
decimal |
BigDecimal(近似) |
128 位高精度小数,财务专用 |
自动属性(Auto-Properties)
Java 你经常要手写 getXxx / setXxx,或者用 Lombok。C# 直接内建了这个能力:
csharp
public class Person
{
public string Name { get; set; } // 自动实现 getter / setter
public int Age { get; private set; } // 私有 set,只读属性
}
这就是属性(Property),使用时却像字段一样自然:
csharp
var p = new Person();
p.Name = "Alice";
Console.WriteLine(p.Name);
不需要写 getName 方法了,直接在类内部使用。如果你需要在 get/set 里加逻辑,也能展开成完整属性——和 Java 写 getter/setter 类似,但用一个结构搞定。
var 关键字 —— 类似 Java 10+ 的 var
C# 从一开始就有 var,用于隐式类型推断:
csharp
var list = new List<string>(); // 编译器推导出 list 是 List<string>
字符串处理
C# 的 string 和 Java 的 String 几乎一样,不可变。但 C# 多了个逐字字符串(Verbatim string),用 @ 前缀,不用疯狂转义:
csharp
string path = @"C:\Users\name\documents"; // 反斜杠不用转义
string json = @"
{
""name"": ""Alice""
}";
// 另外 C# 11 还有原始字符串字面量 """ ... """,更方便
三、面向对象:一个体系,两个习惯
类与继承
定义类、构造方法(C# 叫“构造函数”)、继承的写法略有不同:
csharp
// Java: public class Dog extends Animal { ... }
public class Dog : Animal
{
// 构造函数
public Dog(string name) : base(name) // 调用父类构造函数
{
// 初始化
}
}
-
继承用
:而不是extends。 -
调用父类构造用
: base(...)。 -
基类关键字:Java 里是
super,C# 里是base。
访问修饰符——多了几个选项
Java 的 default(包内可见)在 C# 里对应 internal,表示同一程序集内可访问。对比:
| C# | Java | 说明 |
|---|---|---|
public |
public |
完全公开 |
private |
private |
仅类内部 |
protected |
protected |
自身及子类 |
internal |
(无,default 近似) | 同一程序集(Assembly)内可见 |
protected internal |
— | 程序集内 或 子类可访问 |
private protected |
— | 程序集内 且 子类可访问(C# 7.2+) |
虚方法、重写与隐藏
Java 中方法默认是虚的(可被重写),而 C# 中方法默认是非虚的。这可能是第一个真正的思维转换:
-
若想允许子类重写,父类方法必须标记
virtual。 -
子类重写时,必须用
override关键字。 -
如果子类想定义一个同名但无关的方法,用
new关键字来隐藏。
csharp
public class Parent
{
public virtual void Speak() => Console.WriteLine("Parent");
}
public class Child : Parent
{
public override void Speak() => Console.WriteLine("Child"); // 重写
}
最佳实践:在 Java 里你习惯依赖 @Override 注解来防止失误,在 C# 里强制用 override 关键字。忘记写 override 会变成隐藏,编译器会给出警告。
抽象类与接口
abstract class 完全一致。接口用 interface 定义,实现时也使用 : 跟在类后面,多个接口用逗号分隔:
csharp
public interface IMovable
{
void Move();
}
public class Car : Vehicle, IMovable, IDisposable
{
public void Move() { ... }
public void Dispose() { ... }
}
C# 接口可以包含默认实现(C# 8.0+),和 Java 的接口默认方法类似。
Object 类的方法
Java 有 toString()、equals()、hashCode()。C# 对应:
-
ToString()—— 一样 -
Equals(object obj)—— 一样 -
GetHashCode()—— 一样 -
另外还有
GetType()获取运行时类型
注意命名大写开头,所有方法都是 PascalCase。
四、集合与泛型:换了名字的老朋友
你几乎能在 C# 里找到所有 Java 集合的影子,只是名字改了:
| C# 常用集合 | Java 对应 | 类型 |
|---|---|---|
List<T> |
ArrayList<T> 或 List<T> |
动态数组 |
Dictionary<K,V> |
HashMap<K,V> |
哈希表 |
HashSet<T> |
HashSet<T> |
集合 |
Queue<T> |
Queue<T> / LinkedList<T> |
队列 |
Stack<T> |
Stack<T> |
栈 |
SortedList<K,V> |
TreeMap<K,V> |
排序字典 |
SortedSet<T> |
TreeSet<T> |
排序集合 |
遍历同样流畅,C# 有 foreach,和 Java 的增强 for 一样:
csharp
foreach (var item in list)
{
Console.WriteLine(item);
}
LINQ 是杀手锏——对应 Java 的 Stream API,但要强大且简洁得多:
csharp
var names = people
.Where(p => p.Age > 18)
.OrderBy(p => p.Name)
.Select(p => p.Name)
.ToList();
=> 是 Lambda 表达式,写法比 Java 的 -> 更常用。LINQ 还有查询表达式语法(类似 SQL),让代码更加可读。
五、异常处理:几乎照搬
try-catch-finally 结构一模一样,连语义都相同。差异只是文件小写变为大写的首字母:
csharp
try
{
int.Parse("not a number");
}
catch (FormatException ex) // Java: NumberFormatException
{
Console.WriteLine(ex.Message);
}
finally
{
// 清理
}
C# 还有 using 语句用于自动释放资源(类似 Java 的 try-with-resources):
csharp
using (var reader = new StreamReader("file.txt"))
{
string content = reader.ReadToEnd();
} // reader.Dispose() 自动调用
实现 IDisposable 接口的类都可以这样用。
六、I/O 与文件操作:换个写法,思路不变
Java 里你习惯用 FileInputStream / BufferedReader 等。C# 的 System.IO 命名空间下有极其相似的类:
-
File.ReadAllText("path")↔Files.readString(Path.of("path"))(Java 11+) -
File.WriteAllText("path", content)一步写入 -
StreamReader/StreamWriter↔BufferedReader/BufferedWriter
可以说 C# 的文件操作 API 更加简洁,静态方法 File.xxx 开箱即用。
七、并发与异步:从线程到 Task
在 Java 里你用 Thread、Runnable、ExecutorService,后来有了 CompletableFuture。C# 相应有:
-
System.Threading.Thread—— 和java.lang.Thread一样 -
ThreadPool—— 线程池 -
Task/Task<T>—— 强烈推荐使用的异步抽象,相当于CompletableFuture的加强版
但 C# 的真正杀招是 async / await,它让你用同步思维写异步代码:
csharp
public async Task<string> FetchDataAsync()
{
var client = new HttpClient();
var result = await client.GetStringAsync("https://api.example.com");
return result;
}
Java 目前也有 CompletableFuture 配合 thenApply 等,但 async/await 的易读性无与伦比,这是你转入 C# 后一定要第一时间掌握的特性。
八、委托与事件:Java 可以用接口模拟,C# 内建
Java 里常用回调接口(如 Runnable、ActionListener)或函数式接口(Consumer, Function 等)来实现行为传递。C# 直接用委托(delegate)——类型安全的函数指针:
csharp
public delegate void MyDelegate(string message);
// 可以像使用接口回调一样
MyDelegate del = Console.WriteLine;
del("Hello");
更常用的是内置泛型委托 Action、Func、Predicate,这和 Java 的函数式接口完全对应:
| C# | Java 类似 |
|---|---|
Action |
Runnable (无参无返) / Consumer (有参无返) |
Action<T> |
Consumer<T> |
Func<TResult> |
Supplier<T> |
Func<T, TResult> |
Function<T, R> |
Predicate<T> |
Predicate<T> |
事件(event)是基于委托的发布-订阅机制,替代了 Java 里手写的观察者模式。你定义一个事件,外部可以订阅,非常简洁安全:
csharp
public class Button
{
public event EventHandler Clicked;
protected virtual void OnClicked() => Clicked?.Invoke(this, EventArgs.Empty);
}
// 使用
button.Clicked += (sender, args) => Console.WriteLine("Clicked!");
九、命名规范与习惯:PascalCase 的主场
Java 中方法、变量常使用 camelCase,类名 PascalCase。C# 里一切公开成员都倾向于 PascalCase:
-
方法名:
GetUser、Calculate(PascalCase) -
属性名:
Name、Age -
接口名:必须
I开头,如IDisposable -
私有字段:常用
_camelCase前缀,如_firstName -
局部变量:
camelCase
这与 Java 的惯例不同,但很好适应,因为 IDE 会自动帮你格式化。
枚举值也是 PascalCase,而不是全大写。
十、你需要立刻记住的“小不同”
-
没有 checked exception:C# 所有异常都是运行时异常,不需要在方法签名上声明
throws。你信守的“要么捕获要么声明”规则,在这里解放了。 -
没有匿名内部类,直接有 lambda 和匿名方法:不用再写冗长的
new Runnable() { ... }。 -
==对字符串比较内容:不像 Java 中==比较引用,C# 中string的==已经重载为比较值,等同于equals。 -
枚举是强类型的命名整数,但更强大,可以定义位标志等。
-
结构体(struct):是值类型,不像 Java 全是类。用于小型数据的轻量对象,无需堆分配(在高性能场景下很关键)。
总结性思维:把你的 Java 直觉 “翻译” 过来
如果你在 C# 中要实现某个 Java 中常见的功能,只要问自己:
-
这个类在 C# 里通常叫什么?(List、Dictionary、File……)
-
名字的首字母需要大写吗?(PascalCase)
-
是不是有内建关键字取代了之前的模式?(属性取代 getter/setter,事件取代观察者)
-
有没有更现代的表达方式?(LINQ 代替 for 循环拼接集合,async/await 代替线程管理)
C# 在很多地方就是“进化后的 Java”,它从 Java 乃至整个 C/C++ 生态中吸收了大量优点,并在这个基础上加上了语法糖和现代特性。你已有的面向对象思维、设计模式、架构原则,通通可以移植,只是换一套惯用语。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)