🤖

Java仮想マシン(JVM)を読解しながら理解する #3

に公開

https://zenn.dev/h_kohe/articles/bd8986a73b02df
こちらの記事の続きです。

よんでいる公式ドキュメント
https://docs.oracle.com/javase/specs/jvms/se17/html/jvms-2.html

2.3. Primitive Types and Values(プリミティブ型と値)

この項目に関しては個人的に新しい情報というよりなんとなく把握している内容だったので、振り返りやすいように表にまとめておきました。

📌 数値型(Numeric Types)

整数型(2.3.1. Integral Types and Values)

型名 ビット幅 表現形式 値の範囲 デフォルト値 備考
byte 8ビット 符号付き2の補数 -128127 0
short 16ビット 符号付き2の補数 -32,76832,767 0
int 32ビット 符号付き2の補数 -2,147,483,6482,147,483,647 0
long 64ビット 符号付き2の補数 -9,223,372,036,854,775,8089,223,372,036,854,775,807 0L
char 16ビット 符号なし整数(UTF-16) 065535 '\u0000' Unicode BMP範囲のみ対象

浮動小数点型(2.3.2. Floating-Point Types and Values)

型名 ビット幅 IEEE 754準拠形式 精度(N) 指数ビット(K) Emax Emin デフォルト値 備考
float 32ビット binary32 (単精度) 24 8 +127 -126 0.0f Float.NaN使用可
double 64ビット binary64 (倍精度) 53 11 +1023 -1022 0.0d Double.NaN使用可

🔎 NaN(非数)や ±0、±∞ もJVMでは扱えます。

Javaの浮動小数点(float, double)は、IEEE 754 規格に従っており、次のような特殊な値も表現できます:

  • +0.0(正のゼロ)と -0.0(負のゼロ) → 見た目は同じでも動作が異なることがある

    • 例:1.0 / +0.0+Infinity1.0 / -0.0-Infinity
  • +Infinity(正の無限大) / -Infinity(負の無限大) → オーバーフロー時などに発生

  • NaN(Not-a-Number)→ 計算不能な場合の結果

    • 例:0.0 / 0.0Math.sqrt(-1.0)

⚠️ NaNは特殊な値で、次の特徴があります:

  • NaN != NaN は true → NaNは他のどんな値とも「等しくない」扱い
  • NaN == NaN は false
  • NaNを含む計算や比較は、予期しない動作になることがあるため注意が必要

✅ Javaでは Float.NaN, Double.NaN が標準で提供されており、Float.isNaN(x) などで判定可能です。


🔁 returnAddress型(2.3.3. The returnAddress Type and Values)

型名 用途 デフォルト値 JVM命令との関係 Java言語での扱い 備考
returnAddress JVM命令へのポインタ(オペコード) なし jsr, jsr_w, retなど 使用不可 JVM独自の制御用型。Javaコードからは利用不可

🧠 論理型(2.3.4. The boolean Type)

型名 ビット幅 値の範囲 デフォルト値 JVM命令レベルでの扱い 備考
boolean JVM依存 true, false false 専用命令はなし。intで代替 配列操作はbaload, bastoreを使用

Javaプログラミング言語ではbooleanは型として扱われるが、JVMでは内部的にint型にマッピングされる。


2.4. Reference Types and Values(参照型と値)

JVMでは、reference型とは「オブジェクトや配列への参照」を扱う型のことです。Javaのあらゆるクラス・配列・インターフェース型はすべてこの reference型に分類されます。


🔷 reference型の3種類

型分類 説明
クラス型 具体的なクラスに対応する型(例:java.lang.String
配列型 要素が配列として並ぶ型(例:int[], String[][]
インターフェース型 実装クラスまたは配列が参照先となる型(例:List, Runnable

null参照とは?

  • reference型の変数は、オブジェクトを参照していない状態として null をとることができます。
  • null は「どんな reference型にも代入できる特別な値」です。
  • null 自体は 実行時型を持ちません が、任意の型にキャスト可能です。
  • reference型の変数のデフォルト値null です。
  • JVM仕様上、null内部表現(ビットパターンなど)は規定されていない

・・・・なんとなく公式ドキュメントに記載されている内容を表にまとめていましたが
気になる要素が出てきました

JVM仕様上、null内部表現(ビットパターンなど)は規定されていない

ん?? どうゆこと??🤔
GPTに確認すると以下の内容が返ってきました

項目 内容
誰が決めるか? JVMの実装(例:HotSpot、OpenJ9、GraalVMなど)null の内部表現(ビット列など)を決定します。
JVM仕様では? null の具体的なビットパターンやメモリ上の値は 一切規定されていません。つまり「0である必要がある」などの決まりはありません。
Javaバージョンとの関係 Java SE 8、11、17、21など、すべてのバージョンにおいて null は「何も参照していない」ことを保証するだけであり、内部構造には言及しません。

💡 プログラマは null値の中身(0なのか、特殊なビット列なのか)を気にする必要はなく
単に「何も参照していない参照」として扱えばOKです。

とのこと・・・
HotSpot、OpenJ9、GraalVMという初見の単語が登場してきました・・・

項目 HotSpot OpenJ9 GraalVM
開発元 Oracle IBM(現在は Eclipse 財団) Oracle Labs
特徴 - Java公式・標準実装
- 高速なJIT最適化
- 軽量で省メモリ
- 高速起動・軽量JIT
- 多言語対応(JavaScript, Python, etc.)
- AOT(ネイティブ変換)対応
用途 - 通常のJavaアプリ全般
- Spring Bootなど
- コンテナ環境
- サーバレスやIoT
- 起動速度・サイズが重要な環境
- マイクロサービス、AWS Lambda など
備考 - OpenJDK / Oracle JDKに採用 - Adoptium(旧AdoptOpenJDK)で利用可能 - native-image.exe などに変換可能
公式ドキュメント HotSpot @ Oracle Docs OpenJ9 @ Eclipse Docs GraalVM @ Oracle Docs

さて。。。まさかのJVMってOracleのみが作っているものだと思っていましたが、
Javaの仕様を満たしていれば誰でもJVMを実装してよく、さらにそのJVMで定義した内容によって
reference型のnullをどのようなビット列として扱うかは変わる(大体0らしい)つまり、JVMの実装依存とのこと・・・・

『参照型と値』の話から大きく離脱してしまいましたが、やはり知らないことばかりですね・・・・😇
ドキュメントを読んでみるのはやっぱり遅かれ早かれ必要なんだなと思う日々です。。。。

次のランタイムデータ領域の話はまた多くの情報がありそうなので翌週に回します!!

まとめ / 得た知見

  • null に関しては「JVM仕様では内部ビット列は規定されていない」つまり、JVMの実装依存
  • JVMには HotSpot(Oracle) 以外にも、OpenJ9(Eclipse財団)GraalVM(Oracle Labs) などの実装があり、それぞれ特性が異なる

Discussion