💡

Javaのプリミティブ型の本質に気付いた瞬間

2024/11/19に公開

Javaの"Generics"という概念を勉強する中で、自分は「型」というものに対する理解が浅いことに気付きました。そこで、Javaの型について個人的に調査した結果をここに記します。

私の<型>への理解

以前書いたポリモーフィズムとは何か?型とオブジェクトの関係を紐解くという記事の中で、Javaにおける宣言と型の関係について調査をしています。私の理解を端的に述べると次のようになります。

  • 宣言: メモリ領域にどのようなデータを保存するかを定める
  • 型: メモリ領域に格納されたデータをどのように活用するかを定める

型は目的物をどのように見るかを決めるフィルターレンズのようなものです。フィルターレンズを変更することで、親クラスにある共通メソッドのみを取り扱ったり、インターフェース経由で特有のメソッドのみに焦点をあてることが可能になります。

オブジェクト型? 参照型?

大枠では理解できましたが、プリミティブ型/参照型/オブジェクト型といった用語が登場すると、少し混乱してしましました。特に、オブジェクト型に対する呼称が複数あるため、それが混乱の原因だったようです。

  • プリミティブ型
    • プログラミング言語であらかじめ定義されている型
    • データを直接メモリに格納している
    • 「値型」とも呼ばれる
  • オブジェクト型
    • プリミティブ型以外のすべてのデータ型。
    • ヒープ領域にデータを持ち、変数に参照(ポインタ)が渡される
    • そのため、「参照型」とも呼ばれる。
    • また「非プリミティブ型」とも分類される場合もある

型の公式説明

どうやら全てはプリミティブ型に行きつくらしいということを知りましたので、改めて公式ドキュメントを参照してみました。
すると以下の8つがプリミティブ型として定義されています。

プリミティブ型 ラッパークラス サイズ (ビット) デフォルト値 主な用途と特徴
byte Byte 8 0 小さな範囲の整数を扱う。メモリ効率を重視する場合やコレクションでの利用に便利。
short Short 16 0 範囲が少し広い整数を扱う。メモリ効率を考慮しつつintほど大きくないデータに適用。
int Integer 32 0 デフォルトの整数型。数値処理全般に使用され、Integerは型変換やコレクションで便利。
long Long 64 0L より大きな範囲の整数を扱う。タイムスタンプや大きな数値を扱う際に使用される。
float Float 32 0.0f 単精度の浮動小数点数を扱う。メモリ効率を考慮しつつ、精度をそれほど必要としない場合に。
double Double 64 0.0d 倍精度の浮動小数点数を扱う。デフォルトの浮動小数点型で、精度の高い計算に適用。
boolean Boolean 1 (論理値) false true または false を扱う。条件フラグや状態管理で利用される。
char Character 16 '\u0000' Unicode文字を扱う。文字列処理や個々の文字の操作に使用される。

プリミティブ型にはそれぞれに対応するラッパークラスがあります。コレクションフレームワークやジェネリクスといったオブジェクト型でしかできない操作を行う場合、プリミティブ型では対応できないので、ラッパーが用意されているようです。加えてString型も特別対応でプリミティブ型に近い扱いを受けているようです。

プリミティブ型は原子、オブジェクト型は分子

私が「あー、なるほど」と感心したのは公式ドキュメントの以下の部分。

You may have noticed that the new keyword isn't used when initializing a variable of a primitive type. Primitive types are special data types built into the language; they are not objects created from a class. A literal is the source code representation of a fixed value; literals are represented directly in your code without requiring computation. As shown below, it's possible to assign a literal to a variable of a primitive type:

boolean result = true;  
char capitalC = 'C';  
byte b = 100;  
short s = 10000;  
int i = 100000;

この説明を読んで、私の中でプリミティブ型とオブジェクト型の関係が「原子と分子」に例えられると感じました。プリミティブ型は、プログラミング言語におけるデータ型の最小構成要素(原子)であり、それ以上分解できません。一方で、オブジェクト型はこれらの最小構成要素を組み合わせたより複雑な構造(分子)です。

プリミティブ型は「原子」のようなものであり、単体ではシンプルなデータの保持しかできません。しかし、これらを他のオブジェクト型と組み合わせてクラスを作ることで、現実世界の複雑な事象を表現できます。たとえば、以下のようなクラスです:

public class Car {
    private String brand; // オブジェクト型
    private int year;     // プリミティブ型
    private double price; // プリミティブ型
}

クラスはフィールドとしてプリミティブ型やオブジェクト型を持ち、さらにメソッドを追加することで振る舞いを定義します。このように、プリミティブ型を最小構成要素として利用することで、より複雑なデータ構造を作成することが可能になります。

この件を通じて、私は型への認識が深まりました。この記事がどなたかの参考になれば幸いです。

参考リンク

The Java™ Tutorials (Primitive Data Types)

Discussion