Javaのstaticなmethodがoverrideされない理由って?

f:id:ts0818:20201214185008j:plain

In radio astronomy, a fast radio burst (FRB) is a transient radio pulse of length ranging from a fraction of a millisecond to a few milliseconds, caused by some high-energy astrophysical process not yet understood. Astronomers estimate the average FRB releases as much energy in a millisecond as the sun puts out in 3 days. While extremely energetic at their source, the strength of the signal reaching Earth has been described as 1,000 times less than from a mobile phone on the Moon. 

https://en.wikipedia.org/wiki/Fast_radio_burst

The first FRB was discovered by Duncan Lorimer and his student David Narkevic in 2007 when they were looking through archival pulsar survey data, and it is therefore commonly referred to as the Lorimer Burst. Many FRBs have since been recorded, including several that have been detected to repeat in seemingly irregular ways. Nonetheless, one FRB has been detected to repeat in a regular way: particularly, FRB 180916 seems to pulse every 16.35 days. Most FRBs are extragalactic, but the first Milky Way FRB was detected by the CHIME radio telescope in April 2020.

https://en.wikipedia.org/wiki/Fast_radio_burst

⇧日本語だと「高速電波バースト」と言うらしいんですが、メカニズムは解明されてないそうな、宇宙は謎が多いな~、どうもボクです。 

というわけで、今回もJavaについてです。

レッツトライ~。 

 

Javaのプログラミング実行の仕組みって?

Javaのstaticなmethodがoverrideされないって話なのですが、

その前に、Javaのプログラミングが実行される仕組みは、どうなんだい?ってことを整理して参りましょうかね。

以下のサイト様が参考になりそうですと。

www.flexiprep.com

■一般的なソフトウェアのプログラミングの実行の仕組み

 

Javaのプログラミングの実行の仕組み

⇧ ってな感じで、Javaの場合、「COMPILER」が直接「MACHINE CODE」に変換するわけでなく、「COMPILER」は一旦、「中間コード」っていう形に変換し、その「中間コード」を「JAVA INTERPRETER」ないしは「JUST IN COMPILER」ってもので実行して「MACHINE CODE」に変換されて、プログラミング処理が実行されるってことかと。

上図だと「Runtime」が見当たらないんですが、

stackoverflow.com

When does java interpret the bytecode and when does it compile it? The application code is initially interpreted, but the JVM monitors which sequences of bytecode are frequently executed and translates them to machine code for direct execution on the hardware. For bytecode which is executed only a few times, this saves the compilation time and reduces the initial latency; for frequently executed bytecode, JIT compilation is used to run at high speed, after an initial phase of slow interpretation. Additionally, since a program spends most time executing a minority of its code, the reduced compilation time is significant. Finally, during the initial code interpretation, execution statistics can be collected before compilation, which helps to perform better optimization.

https://stackoverflow.com/questions/1326071/is-java-a-compiled-or-an-interpreted-programming-language

⇧ ってな感じで、Javaの場合、「Runtime System」が「MACHINE CODE」を実施するようなイメージなんですかね?

ただ、「MACHINE CODE」の定義が広いみたいで、

qastack.jp

マシンコード:これは最も明確なものです。これは、プロセッサ(実際の作業を行う物理的な金属片)が直接理解して実行するバイトコード命令を使用するコードです。他のすべてのコードは、マシンで実行する前に、マシンコードに変換または変換する必要があります。

https://qastack.jp/programming/3434202/what-is-the-difference-between-native-code-machine-code-and-assembly-code

ネイティブコード:この用語は、マシンコード(上記を参照)を意味する場所で使用されることがあります。ただし、アンマネージコードを意味する場合もあります(下記参照)。

https://qastack.jp/programming/3434202/what-is-the-difference-between-native-code-machine-code-and-assembly-code

アンマネージコードマネージコード: アンマネージコードとは、CやC ++などのプログラミング言語で書かれたコードを指し、マシンコードに直接コンパイルされます。これは、C#、VB.NETJavaなどで記述され、ソフトウェアでプロセッサを「シミュレート」する仮想環境(.NETやJavaVMなど)で実行されるマネージコードとは対照的です。主な違いは、ガベージコレクションを採用し、オブジェクトへの参照を不透明に保つことで、マネージコードがリソース(主にメモリ割り当て)を「管理」することです。アンマネージコード手動でメモリを割り当てたり割り当て解除したりする必要がある種類のコードで、メモリリーク(割り当て解除を忘れた場合)や、セグメンテーションエラー(割り当て解除が早すぎる場合)が発生する場合があります。アンマネージは、通常、nullポインターの逆参照や配列の境界のオーバーフローなどの一般的なエラーのランタイムチェックがないことも意味します。

厳密に言えば、PerlPythonPHPRubyなどのほとんどの動的型付け言語もマネージコードです。ただし、それらは一般的にはそのように記述されていないため、マネージコードは、実際には非常に大きく、本格的な商用プログラミング環境(.NETおよびJava)のマーケティング用語の一部であることを示しています

https://qastack.jp/programming/3434202/what-is-the-difference-between-native-code-machine-code-and-assembly-code

アセンブリコード:この用語は一般に、バイトコードを本当に書きたいときに人々が書くソースコードの種類を指します。アセンブラ、実際のバイトコードにこのソースコードをオンにするプログラムです。変換は1対1であるため、コンパイラではありません。ただし、使用されるバイトコードの種類については、あいまいな用語であり、管理されている場合と管理されていない場合があります。管理されていない場合、結果のバイトコードマシンコードになります。管理されている場合は、.NETなどの仮想環境によって舞台裏でバイトコードが使用されます。マネージコード(C#、Javaなど)は、この特殊なバイトコード言語にコンパイルされます。これは、.NETの場合はCommon Intermediate Language(CIL)と呼ばれ、JavaではJavaバイトコードと呼ばれます。。通常、一般のプログラマーがこのコードにアクセスしたり、この言語で直接書き込んだりする必要はほとんどありませんが、アセンブラを使用してバイトコードに変換するため、人々がアクセスする場合、アセンブリコードと呼ばれることがよくあります。

https://qastack.jp/programming/3434202/what-is-the-difference-between-native-code-machine-code-and-assembly-code

プログラミング言語によって、「アンマネージコード」「マネージコード」って分類するみたいね。

マネージコード (managed code) とは、.NET Frameworkにおける共通言語基盤 (CLI) に準拠した仮想機械上で実行される命令(コード)のことである。

これに対してマネージコード以外のコードはアンマネージコード (unmanaged code) やネイティブコード (native code) と呼ばれる。

マネージコード - Wikipedia

⇧ 元は「.NET Framework」で定義された言葉っぽいですね。

JavaScalaKotlinなどのJava仮想マシン上で動作する言語もまた、中間表現であるJavaバイトコードを出力できる言語であり、管理された安全なコードを記述できるという意味でマネージ言語と呼ばれることもある

マネージコード - Wikipedia

⇧と言うか、「マネージコード」「アンマネージコード」って言葉は、「.Net Framework」環境について話すときに限定の言葉っぽい感じっすかね...

 

脱線しましたが、「Java Interpreter」と「JIT(Just In Time)Compiler」については、 

高レベルの視点では、インタプリタは、冗長な計算を排除またはスキップするための最適化(計算順序の変更など)を多数実行することはできません。また、低レベルの視点では、インタプリタは基盤プロセッサの命令セットやキャッシュ、およびメモリ・システムを最大限に活用できません。
 一方、JITコンパイラでは、これら両方のレベルでパフォーマンスの向上を見込めます。JITコンパイラは高レベルの戦略を用いて、バイトコードを、大幅に少ない計算量で同じ結果を出す同等の操作に変換します。このように変換された操作は、プロセッサ命令セットを最大限に利用して低レベルのネイティブ・マシン・コードへとエンコードされます。それと同時に、有用なデータができる限り長くプロセッサのレジスタやキャッシュ内に維持されるようにして、メモリ・システムの遅延を最小限に抑えます。また、コードの生成時に、キャッシュ・サイズやヒープ・サイズ、使用可能なプロセッサ数などの実行時定数を考慮することもできます。

https://www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-MA16-JIT.pdf

⇧ 上記のPDFが詳しいです。

 

ちなみに、AOT(Ahead Of Time)って仕組みもあるみたい。

www.shudo.net

The GNU Compiler for the Java Programming Language、略してGCJ は、 JavaのAhead-of-Time(AOT)コンパイラです。 GNU Compiler Collection(GCC)の一部として開発されていて、 GCCJavaコンパイラという位置付けとなっています。 その開発は、Java誕生から約1年半、1996年の10月にすでに始まっていました。

http://www.shudo.net/article/200507-Fedora-Core-Expert-GCJ/

Javaプログラムを実行する際、通常は javac、ecj(Eclipse Java Compiler)、JikesなどのJavaコンパイラJavaバイトコードに変換しておいて、 それをJava仮想マシンを使って実行します。 それに対して、GCJJavaバイトコードではなくてネイティブコードを生成します。 AOTコンパイラという名称は、このように実行前にネイティブコードを 生成してしまうコンパイラを指す言葉です。 生成されたネイティブコードは、プロセッサが直接実行します。

http://www.shudo.net/article/200507-Fedora-Core-Expert-GCJ/

⇧ってな感じで、「中間コード(上図だと、『.classファイル』)」を生成することなく、直接「MACHINE CODE(上図だと、『ネイティブコード』)」を生成できるらしい。

最近だと(と言ってももう登場してから結構時間が経ってますが)、

⇧「GraalVM」ってのが「JIT」「AOT」どっちも使えるらしいですね。

 

Javaのstaticなmethodがoverrideされない理由って?

脱線しまくりLa'cryma Christi(ラクリマ・クリスティー)ですが、『Javaのstaticなmethodがoverrideされない理由』ってのは、Javaの仕様らしいです、以上。

って、「ファッキンジャップぐらい分かるよ馬鹿野郎」ってお𠮟りを受けそうなので、どういう仕組みなんですか?ってところを調べてみました。

残念ながら、Javaの公式のページとかの情報が検索でヒットしないので、あくまで推測になってしまいますが、ズバリ、「コンパイル時」に解決されるか「実行時」に解決されるかっていう違いに由るということらしいです。

Javaのメソッドの呼び出しは、

  1. Static Binding(Early Binding)
    コンパイル時に決定
  2. Dynamic Binding (Late Binding)
    実行時に決定

の2パターンのいずれかになるようです。

 

stackoverflow.com

In Java (and many OOP languages, but I cannot speak for all; and some do not have static at all) all methods have a fixed signature - the parameters and types. In a virtual method, the first parameter is implied: a reference to the object itself and when called from within the object, the compiler automatically adds this.

https://stackoverflow.com/questions/2223386/why-doesnt-java-allow-overriding-of-static-methods

There is no difference for static methods - they still have a fixed signature. However, by declaring the method static you have explicitly stated that the compiler must not include the implied object parameter at the beginning of that signature. Therefore, any other code that calls this must must not attempt to put a reference to an object on the stack. If it did do that, then the method execution would not work since the parameters would be in the wrong place - shifted by one - on the stack.

https://stackoverflow.com/questions/2223386/why-doesnt-java-allow-overriding-of-static-methods

Because of this difference between the two; virtual methods always have a reference to the context object (i.e. this) so then it is possible to reference anything within the heap that belong to that instance of the object. But with static methods, since there is no reference passed, that method cannot access any object variables and methods since the context is not known.

https://stackoverflow.com/questions/2223386/why-doesnt-java-allow-overriding-of-static-methods

If you wish that Java would change the definition so that a object context is passed in for every method, static or virtual, then you would in essence have only virtual methods.

https://stackoverflow.com/questions/2223386/why-doesnt-java-allow-overriding-of-static-methods

⇧ う、う~ん...よく分からんのだけど、「コンパイル時」に「implied object parameter」ってものを含めるか含めないかという違いがあるらしい。

おそらく、その際によって「中間コード」である「.class」ファイルに差異が生まれ、「ClassLoader」によって「.class」ファイルが読み込まれた後に配置される「メモリ領域」が異なるからってことなんではないかと。

なので、「JVMJava Virtual Machine)」で処理される前の「コンパイラー」で決定してしまうってことですかね。

dzone.com

⇧上図のような感じで「ClassLoader」によって「.class」ファイルが読み込まれると「Runtime Data Areas」の中にある、

  • Method Area
  • Heap Area
  • Stack Area
  • PC Registers
  • Native Method Stack

のいずれかにJavaのプログラミングの各処理が配置されるってことになるんですかね。

というわけで、「コンパイル時」に「各処理」の配置先が確定されてしまうらしいのですが、この配属先の違いによって「staticなmethodがoverrideされない」ということになるのだと。

 

■Static Binding(Early Binding) 

 

■Dynamic Binding(Late Binding) 

 

まぁ、最終的に推測の域は出ませんが、「コンパイル時」に「.class」ファイルに含まれるらしい「implied object parameter」が「override」には必要なんじゃないかと。

「staticなmethod」の「.class」ファイルには「implied object parameter」が含まれないらしいので。

そもそも「implied object parameter」ってのが何なのかサッパリ分からんのだけどね...

Google翻訳によると「暗黙のオブジェクトパラメータ」ってことらしいんだけど...

f:id:ts0818:20201214174023p:plain

いつもながらモヤモヤ感が半端ない...

相変わらず、Javaはカオスだな~

2020年12月15日(火)追記:↓ ここから

その他の「override」のルールについては、以下を確認ですかね。(以下は、Javaのバージョンが15の場合のドキュメント)

docs.oracle.com

⇧ キーワード検索で「overrid」で調べたら、19件ぐらいヒットしました...

19件も確認したくないけど、確認せねばですかね...

2020年12月15日(火)追記:↑ ここまで 

 

今回はこのへんで。