前置き
いつもはC#で開発をしていますが、使用するAPIにC#用のインターフェースがまだ整っていなくJavaで開発を始めてみました。
あまりJavaは触ったことがなかったため、C#でいう「xxxx」はJavaでいう「xxxx」というのをまとめてみました。
私がよく使っている予約語、実装方法が中心となっています。そのため全ての違いが網羅できているわけではありません。
C#とJavaの予約語、実装方法の違い
予約語の違い
C#、Javaでの予約語の違い、変わらない点をまとめてみました。
同じ、似ていると思った項目を横並びにして比較してみます。
差異 | C# | Java | 備考 |
---|---|---|---|
namespace | package | ||
using | import | ||
なし | class | class | |
: | extends | クラス継承 | |
なし | interface | interface | |
なし | abstract | abstract | |
virtual | なし | 継承先で関数をoverride可能にする場合、C#はvirtualを付与、Javaはなし | |
override | @Override | C#は定義に含めるが、Javaはアノテーション(C#で言う属性、Attribute) | |
readonly | final | 読み取り専用フィールド | |
const | final | 定数 | |
sealed | final | クラス継承禁止、Javaは関数のoverride禁止としても使用する | |
なし | Enum | Enum | 列挙型 |
struct | なし | 構造体 |
Javaには「struct」、「virtual」がありませんでした。
「struct」はclassでそれっぽく代用できるため問題なさそうですが、「virtual」は無いと少し困りそうです。
「virtual」については下記のタイトルでページの最後に掘り下げてみます。
・「C#のvirtualとJavaのfinal」
また、Javaの「final」がC#の複数の機能を含有しておりました。
それだけでなくJavaのみの使い方があるため、この違いについては下記タイトルでページの最後に掘り下げてみます。
・「定数の宣言、設定方法の違い」
実装方法の違い
C#での実装方法、Javaでの実装方法、どちらにしかない実装方法をまとめてみました。
こちらも同じ、似ていると思った項目を横並びにして比較してみます。
やりたいこと | C# | Java |
---|---|---|
属性自作 | Attributeの継承 | @interfaceでクラス定義 |
拡張メソッド | public static class | なし |
interfaceのデフォルト実装 |
C#8.0 (.NET Core 3.0)で追加 |
interfaceを継承し、メンバをdefaultで定義 |
リソースの自動解放 | using(Stream stream = new Stream()) | try-with-resources |
型パラメータの制約 | where T: int | <T extends Number> |
上記例)void Test<T>(T arg) | void Test<T>(T arg) where T : int | <T extends Number> void Test(T arg) |
Null許容型宣言 | Nullable<T>,T? | Optional<T> |
ラムダ式 | ()=>{ } | ()->{ } |
コールバック引数なし | Action | Runnable |
同上 引数1つ | Action<T> | Consumer<T> |
同上 引数2つ | Action<T1,T2> | BiConsumer<T,U>(引数は2つまで) |
同上 返り値あり | Function<R> | Supplier<T> |
同上 引数1つ、返り値あり | Function<T,R> | Function<T,R> |
同上 引数2つ、返り値あり | Function<T1,T2,R> | BiFunction<T,U,R>(引数は2つまで) |
今回挙げた機能については使い勝手は違えどC#、Javaの両方が同等の機能を持っていることがわかりました。
また、コメント欄でご指摘頂いている通り、C#にもinterfaceのデフォルト実装機能がC# 8.0より追加されています。
abstractとinterfaceで迷い後者で実装したけど、継承先で同じ実装を行った経験がある人はきっといるはず。私です
これは是非活用していきたいですね。
また、C#で言う「Action」、「Function」、いわゆるコールバックの使い勝手がかなり違いそうです。
「コールバック」については下記のタイトルでページの最後に掘り下げてみます。
・コールバックの使い方の違い
C#とJavaで似ているようで違う点を掘り下げる
「予約語の違い」、「実装方法の違い」で挙げた3つについて掘り下げていきます。
C#のvirtualとJavaのfinal
C#では「virtual」でoverrideを可能にし(正確には仮想メソッドとして実装)、Javaは「final」でoverrideを禁止します。
つまりJavaの関数に「final」を付けなかった場合、C#の感覚で言うと常に「virtual」での実装になります。
いつの間にかoverrideされてる!?といった状況になりたくなければ必ず「final」を付けたほうがよさそうですね。。
※追記
コメント欄でご指摘頂いているように「final」を付与しているかいないかで呼び出しコストが変わってきます。
シビアなメモリ、処理速度が求められる場合は是非付与していきましょう。
コールバックの使い方の違い
C#とJavaのコールバックの違いはざっくりとこんな感じです。
この違いを把握していればC#とJavaで混乱するとはなさそうです。
-
Javaのコールバックは引数の数に上限があり、C#は最大16個まで取れる。
-
Javaのコールバックで数値型を引数に取れないが、C#は全ての型を引数に取れる。(※1)
※1
今回記事に挙げたJavaのコールバックは参照型のみを引数に取れます。
そのためC#と違い、Javaでは数値型を引数に取ることができません。数値が設定できなくて困惑したのは私です
その代わりに数値型用のコールバックがあり下記の名前で定義されているためこちらを使います。
・「数値型」Consumer
・Obj「数値型」Consumer
・「数値型Function」
・To「数値型」Function
・To「数値型」BiFuction
定数の宣言、設定方法の違い
C#の「const」、「readonly」、Javaの「final」を定数、読み取り専用として使用する場合の違いをまとめました。
定数宣言、代入方法 | const | readonly | final |
---|---|---|---|
定数フィールドでの宣言 | 〇 | 〇 | 〇 |
定数フィールドへ宣言場所以外での代入 | × | 〇 ※1 | × |
ローカル変数での宣言 | 〇 | × | 〇 |
ローカル変数での宣言場所以外での代入 | × | × | 〇 |
引数への付与 | × | × | 〇 |
宣言時の型制限 | あり ※2 | なし | なし |
上記以外の違いとして「final」の機能はコメントでご指摘頂いている通り、再代入の禁止になります。
C#は基本的に宣言場所以外での代入をすることができないため、これに該当する機能はありません。
強いて言うのであれば、ローカル変数でも宣言できる「readonly」といったところでしょうか。
もちろんこんな機能はないため是非、C#にもほしい機能です。
※1 readonlyは宣言時以外、コンストラクタ内でのみ代入可能
※2 宣言できる型についてはこちらconst キーワード - C# リファレンス _ Microsoft Docs
参考にしたページ
・Java(tm) Platform, Standard Edition 8 API仕様
・Javaのfinalを大解剖 finalの全てがここにある!!
最後に
C#とJavaは言語のベースが同じだから似ていると聞いたことはありました。調べていく中で予約語に同じものが多かったりと確かに似ていると感じました。
また、実際にコードを書かないと気づけない違い(予約語が前後するなどの小さな違い)があったため、知識をため込むだけでなく、アウトプットのすることの大事さを改めて感じました。
ただ似た書き方をしていながら、異なる動きをする場合があるため、エラーが起きた場合に嵌らないようにしたいですね。
あと、何より情報のアップデート。。指摘して頂いた方々ありがとうございます。