比較的に似ていると言われるJavaとC#を実際に使用してみて、それぞれの違いについてちょっと戸惑ったところをまとめてみます。
Javaについて
- 1996年にサン・マイクロシステムズによって市場リリースされ、2010年に同社がオラクルに吸収合併
- ランタイム環境はJava Runtime Environment (JRE)
- JVM(Java仮想マシン)上で動作し、プラットフォーム非依存
- 最新バージョン(2024年12月現在) Java23
C#について
- マイクロソフトが開発
- ランタイム環境は、Common Language Runtime (CLR)
- Windowsの.NET Framework上で動作することを前提として開発された言語であるが、現在はクロスプラットフォームな.NETランタイム上で動作
- 最新バージョン(2024年12月現在) C#13(.NET9サポート)
ここからJavaとC#を使用してみて、戸惑ったことをまとめていきます。
package(Java)とnamespace(C#)
どちらも、クラスやインターフェイスを整理する仕組みです。
■ package
関連するクラスやインターフェイスを物理的なディレクトリ構造に基づいてグループ化します。実際のファイルシステムの階層構造と一致させる必要があります。また、ソースファイルの最初にpackageキーワードを使い定義します。
他のパッケージに含まれるクラスやインターフェイスを使用する際は、importキーワードを使用します。
■ namespace
namespaceは、ファイルシステムとは直接関係がなく、プログラム内でのクラスやインターフェイスを整理する役割があります。
名前空間を宣言するには、namespaceキーワードを使用します。.演算子を使用して区切ることも可能です。
別名前空間を呼び出す際は、usingディレクティブを使用します。
クラスの継承
■ Java
extendsキーワードを使用。
public class Animal {
public void eat() {
System.out.println("Animal is eating.");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println("ワン");
}
}
■ C#
:を使用。
public class Animal {
public void Eat() {
Console.WriteLine("Animal is eating.");
}
}
public class Dog : Animal {
public void Bark() {
Console.WriteLine("ワン");
}
}
interfaceの実装
■ Java
implementsキーワードを使用。
public interface Animal {
void bark();
}
public class Dog implements Animal {
public void bark() {
System.out.println("ワン");
}
}
■ C#
:を使用。
public interface Animal{
void bark();
}
}
public class Dog : Animal{
public void bark()
{
Console.WriteLine("ワン");
}
}
アクセス修飾子の違い
■ Java
| アクセス修飾子 | 説明 |
|---|---|
| public | どのクラスからでもアクセス可能 |
| protected | 同一パッケージ内およびサブクラスからアクセス可能 |
| デフォルト(指定なし) | 同一パッケージ内からのみアクセス可能 |
| private | 同じクラス内からのみアクセス可能 |
■ C#
| アクセス修飾子 | 説明 |
|---|---|
| public | どのクラスからでもアクセス可能 |
| protected | 同じクラスおよび派生クラス内からアクセス可能 |
| private | 同じクラス内のみアクセス可能 |
| internal | 同一アセンブリ内からのみアクセス可能 |
| protected internal | 同一アセンブリ内および派生クラスからアクセス可能 |
| private protected | 同じクラスと同じアセンブリ内の派生クラスからのみアクセス可能 |
| file | 宣言された型は現在のソース ファイルでのみ表示される |
C#では、アクセス修飾子が指定されていない場合は、既定のアクセシビリティが使用されます。
Microsoft公式ドキュメント アクセス修飾子
Microsoft公式ドキュメント アクセシビリティ レベル
プロパティ設定
■ Java
getter/setterメソッドを使用
public class User {
private String name;
private String password;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
■ C#
get/setアクセサを使用
public class User
{
public string Name { get; set; }
public string Password { get; set; }
}
文字列型のStringとstring
■ Java
文字列型の変数を宣言する際はStringを使用します。stringでは、エラー。
■ C#
String、stringのどちらでも宣言可能ではあるが、2つには違いがあります。
stringは、System.Stringのエイリアス(別名)として機能します。
・ String
System.Stringクラスを指す。大文字で始まるStringは、C#内でクラス名として使用されます。
・ string
C#のキーワードであり、文字列型を表すために使用されます。小文字で始まるstringは、C#の言語仕様において基本的なデータ型の一つとして扱われます。
String a = "aaa";
string b = "bbb";
String.IsNullOrEmpty(a);
string.IsNullOrEmpty(b);
どちらもエラーとはならないが、変数宣言の際はstring、Stringクラスのstaticメソッドを使用する際はStringを使用することが推奨されます。
拡張for文とforeach文
■ Java
int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
System.out.println(number);
}
■ C#
List<int> numbers = new List<int> {1, 2, 3, 4, 5};
foreach (int number in numbers) {
Console.WriteLine(number);
}
例外処理(チェック・非チェック例外)
■ Java
Javaには、チェック例外(Checked Exceptions)と非チェック例外(Unchecked Exceptions)の2つの分類があります。
・チェック例外
コンパイラによって強制される例外で、メソッドがスローする可能性のある例外を明示的に宣言する必要があります。呼び出し側はその例外を処理するための処理(try-catchやthrows)を記述する必要があります。代表的なチェック例外にはIOExceptionやSQLExceptionなど。
・非チェック例外
RuntimeExceptionクラスのサブクラスであり、コンパイラによってチェックされない例外。必ずしも例外処理を記述する必要はないです。代表的な非チェック例外にはNullPointerExceptionやArrayIndexOutOfBoundsExceptionなど。
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class CheckedException {
//IOExceptionは、チェック例外である為try-catchが必須(もしくはthrows句を記述)
//行わない場合、コンパイルエラーとなる
public static void main(String[] args) {
File file = new File("sample.txt");
FileReader fileReader = null;
try {
fileReader = new FileReader(file);
int data;
while ((data = fileReader.read()) != -1) {
System.out.print((char) data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// リソースを解放
//finallyでもtry-catchが必要
if (fileReader != null) {
try {
fileReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
■ C#
C#では、全ての例外が非チェック例外として扱われます。その為、柔軟にエラー処理を行うことができます。
参考