C#转Java语法差异与跨平台开发实战对比指南

引言
C#和Java作为两种主流的面向对象编程语言,都深受C++的影响,但在设计理念、语法细节和生态系统上存在显著差异。对于有C#背景的开发者转向Java,或者需要在两个平台间进行代码迁移和跨平台开发时,理解这些差异至关重要。本文将深入探讨C#与Java的语法差异,并通过实战案例展示如何在跨平台开发中有效应对这些差异。
1. 基本语法结构差异
1.1 程序入口点
C#
的程序入口点是
Main
方法,可以定义在任何类中,通常位于
Program.cs
文件:
using System;

namespace MyApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(“Hello, World!”);
}
}
}
Java
的程序入口点是
main
方法,必须是
public static void
类型,并且位于一个公共类中,类名通常与文件名相同:
public class Main {
public static void main(String[] args) {
System.out.println(“Hello, World!”);
}
}
关键差异
:
C# 的
Main
方法首字母大写,Java 的
main
方法全小写
C# 的命名空间(namespace)与Java的包(package)概念类似,但语法不同
Java要求公共类必须与文件名相同
1.2 变量声明与类型系统
C#
支持
var
关键字进行隐式类型推断,并且有值类型(struct)和引用类型(class)的明确区分:
// C# 变量声明
int number = 10;
var text = “Hello”; // 类型推断为 string
DateTime now = DateTime.Now; // 值类型
List list = new List(); // 引用类型
Java
从Java 10开始支持
var
,但类型系统更统一,所有对象都是引用类型:
// Java 变量声明
int number = 10;
var text = “Hello”; // 类型推断为 String
LocalDateTime now = LocalDateTime.now(); // 对象类型
List list = new ArrayList<>(); // 引用类型
关键差异
:
C# 的值类型(struct)在栈上分配,Java没有值类型的概念(虽然有基本类型)
C# 的
var
在方法内可用,Java的
var
仅限局部变量
C# 的泛型在运行时保留类型信息,Java使用类型擦除
1.3 属性与字段
C#
有属性(Property)的概念,结合了字段和方法的特点:
public class Person
{
private string _name;

public string Name
{
get { return _name; }
set { _name = value; }
}

// 自动属性
public int Age { get; set; }
}
Java
通常使用getter/setter方法,但从Java 14开始有record类型:
public class Person {
private String name;
private int age;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}
}

// Java 14+ record类型(简化不可变数据类)
public record PersonRecord(String name, int age) {}
2. 面向对象编程差异
2.1 继承与接口
C#
支持单继承多实现,接口可以有默认实现:
public abstract class Animal
{
public abstract void MakeSound();

public void Sleep()
{
Console.WriteLine(“Sleeping…”);
}
}

public interface IWalkable
{
void Walk(); // 抽象方法

// 接口默认实现(C# 8.0+)
void Run()
{
Console.WriteLine(“Running…”);
}
}

public class Dog : Animal, IWalkable
{
public override void MakeSound()
{
Console.WriteLine(“Woof!”);
}

public void Walk()
{
Console.WriteLine(“Walking on four legs”);
}
}
Java
支持单继承,接口从Java 8开始可以有默认方法:
public abstract class Animal {
public abstract void makeSound();

public void sleep() {
System.out.println(“Sleeping…”);
}
}

public interface Walkable {
void walk(); // 抽象方法

// 接口默认方法(Java 8+)
default void run() {
System.out.println(“Running…”);
}
}

public class Dog extends Animal implements Walkable {
@Override
public void makeSound() {
System.out.println(“Woof!”);
}

@Override
public void walk() {
System.out.println(“Walking on four legs”);
}
}
关键差异
:
C# 的接口默认实现语法更简洁
C# 支持属性在接口中定义
Java 8之前接口只能有抽象方法
2.2 异常处理
C#
的异常处理与Java类似,但checked exception(受检异常)不是强制的:
public class ExceptionExample
{
public void ReadFile(string path)
{
try
{
string content = File.ReadAllText(path);
Console.WriteLine(content);
}
catch (FileNotFoundException ex)
{
Console.WriteLine($”File not found: {ex.Message}”);
}
catch (Exception ex)
{
Console.WriteLine($”Error: {ex.Message}”);
}
finally
{
Console.WriteLine(“Cleanup operations”);
}
}

// 自定义异常
public class MyCustomException : Exception
{
public MyCustomException(string message) : base(message) { }
}
}
Java
区分checked和unchecked异常:
import java.io.*;

public class ExceptionExample {
public void readFile(String path) {
try {
String content = new String(Files.readAllBytes(Paths.get(path)));
System.out.println(content);
} catch (FileNotFoundException ex) {
System.out.println(“File not found: ” + ex.getMessage());
} catch (IOException ex) {
System.out.println(“IO Error: ” + ex.getMessage());
} finally {
System.out.println(“Cleanup operations”);
}
}

// 自定义checked异常
public class MyCustomException extends Exception {
public MyCustomException(String message) {
super(message);
}
}

// 自定义unchecked异常
public class MyRuntimeException extends RuntimeException {
public MyRuntimeException(String message) {
super(message);
}
}
}
关键差异
:
Java强制处理checked exception(继承自Exception但不是RuntimeException)
C#没有checked exception的概念,所有异常都是unchecked
C#的异常过滤器(when关键字)比Java更强大
3. 集合与数据处理
3.1 常用集合类型
C#
的集合在
System.Collections.Generic
命名空间:
using System;
using System.Collections.Generic;
using System.Linq;

public class CollectionExample
{
public void DemonstrateCollections()
{
// List
List names = new List { “Alice”, “Bob”, “Charlie” };
names.Add(“David”);
names.Remove(“Alice”);

// Dictionary
Dictionary dict = new Dictionary
{
{ 1, “One” },
{ 2, “Two” }
};

// LINQ查询
var filtered = names.Where(n => n.Length > 3).ToList();

// 扩展方法
names.ForEach(name => Console.WriteLine(name));
}
}
Java
的集合在
java.util
包,使用Stream API:
import java.util.*;
import java.util.stream.Collectors;

public class CollectionExample {
public void demonstrateCollections() {
// List
List names = new ArrayList<>(Arrays.asList(“Alice”, “Bob”, “Charlie”));
names.add(“David”);
names.remove(“Alice”);

// Map
Map map = new HashMap<>();
map.put(1, “One”);
map.put(2, “Two”);

// Stream API
List filtered = names.stream()
.filter(n -> n.length() > 3)
.collect(Collectors.toList());

// forEach
names.forEach(name -> System.out.println(name));
}
}
关键差异
:
C# 的LINQ和Java的Stream API功能相似但语法不同
C# 的集合初始化语法更简洁
Java的Stream API是函数式编程风格
3.2 数组处理
C#
数组:
int[] numbers = { 1, 2, 3, 4, 5 };
int[,] multiDimensional = new int[2, 3];
int[][] jagged = new int[3][];
Java
数组:
int[] numbers = {1, 2, 3, 4, 5};
int[][] multiDimensional = new int[2][3];
int[][] jagged = new int[3][];
4. 异步编程对比
4.1 C# 的 async/await
C#
的异步编程模型非常成熟:
using System;
using System.Net.Http;
using System.Threading.Tasks;

public class AsyncExample
{
public async Task FetchDataAsync(string url)
{
using (HttpClient client = new HttpClient())
{
try
{
// 异步等待
string result = await client.GetStringAsync(url);
return result;
}
catch (HttpRequestException ex)
{
Console.WriteLine($”Error fetching data: {ex.Message}”);
return null;
}
}
}

public async Task ProcessMultipleRequestsAsync()
{
var task1 = FetchDataAsync(“https://api.example.com/data1”);
var task2 = FetchDataAsync(“https://api.example.com/data2”);

// 并行执行
await Task.WhenAll(task1, task2);

Console.WriteLine(“Both requests completed”);
}
}
4.2 Java 的 CompletableFuture
Java
从8开始使用CompletableFuture:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class AsyncExample {
private final HttpClient httpClient = HttpClient.newHttpClient();

public CompletableFuture fetchDataAsync(String url) {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.build();

return httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.exceptionally(ex -> {
System.out.println(“Error fetching data: ” + ex.getMessage());
return null;
});
}

public void processMultipleRequestsAsync() {
CompletableFuture future1 = fetchDataAsync(“https://api.example.com/data1”);
CompletableFuture future2 = fetchDataAsync(“https://api.example.com/data2”);

// 并行执行
CompletableFuture.allOf(future1, future2).join();

System.out.println(“Both requests completed”);
}
}
关键差异
:
C# 的async/await语法更简洁直观
Java的CompletableFuture更函数式,链式调用
C# 的异步模型是语言级别的支持,Java是库级别的支持
5. 跨平台开发实战对比
5.1 UI框架选择
C#
跨平台UI框架:
MAUI
(Multi-platform App UI): 微软官方框架,支持移动和桌面
Avalonia
: 第三方框架,类似WPF
Uno Platform
: 支持WebAssembly
MAUI
示例:
// MauiProgram.cs
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp()
.ConfigureFonts(fonts =>
{
fonts.AddFont(“OpenSans-Regular.ttf”, “OpenSansRegular”);
});

return builder.Build();
}
}

// MainPage.xaml