プリミティブ型のオブジェクト化とラッパークラス
Javaの型システムでは、メモリ効率を優先したプリミティブ型と、コレクションやジェネリクスで要求される参照型を橋渡しするためにラッパークラスが提供されています。これらのクラスはプリミティブ値をカプセル化し、メソッドチェーンや自動ボックスリング/アンボックスリングによって参照型と同様の操作を可能にします。
特に注目すべきは内部的な整数キャッシュ機構です。範囲が-128〜127の整数値に対しては、JVMが事前生成されたインスタンスを共有するため、参照比較演算子(==)で真を返すことがあります。それ以外の値やnew演算子を使用した場合、それぞれ独立したヒープメモリ領域に確保されるため、値の等価性を確認するにはequals()メソッドの適用が必須となります。
package utility.demo.wrapper;
public class WrapperBehaviorDemo {
public static void main(String[] args) {
// 整数キャッシュの動作確認
Integer cachedA = 100;
Integer cachedB = 100;
Integer overflowA = 250;
Integer overflowB = 250;
System.out.println("キャッシュ範囲内参照比較: " + (cachedA == cachedB)); // true
System.out.println("キャッシュ範囲外参照比較: " + (overflowA == overflowB)); // false
System.out.println("値の等価性判定: " + overflowA.equals(overflowB)); // true
// 生成方法によるインスタンスの差異
Integer factoryRef = Integer.valueOf("42");
Integer directRef = new Integer("42");
System.out.println("ファクトリとコンストラクタの参照比較: " + (factoryRef == directRef)); // false
// 型変換と文字列解析の実装
double rawNumeric = 98.765;
int truncatedVal = (int) rawNumeric; // 明示的キャストによる小数点以下切り捨て
int parsedVal = Integer.parseInt("77"); // 文字列リテラルの数値への変換
System.out.println("キャスト適用後: " + truncatedVal);
System.out.println("文字列解析後: " + parsedVal);
}
}
数学関数と高精度数値処理
基本的な数値演算や乱数生成はjava.lang.Mathクラスの静的メソッド群でカバーされます。単例設計により直接呼び出せるこれらのメソッドは、切り上げ・切り捨て・四捨五入・絶対値・平方根計算など、日常的な計算ロジックを短時間で実装できるよう最適化されています。
ただし、プリミティブ浮動小数点数(floatやdouble)はIEEE 754準拠のため、金融計算や桁数の多い科学計算では丸め誤差が発生します。そのようなシナリオでは、オーバフローを防止するBigIntegerおよび高精度演算を支援するBigDecimalクラスの利用が標準的です。これらのクラスは不変(イミュータブル)な設計であるため、演算結果は常に新しいインスタンスとして返却されます。
package utility.demo.math;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.Random;
public class MathAndPrecisionDemo {
public static void main(String[] args) {
// Mathクラスの代表的な演算メソッド
double target = -1.5;
System.out.println("絶対値取得: " + Math.abs(target));
System.out.println("上限丸め(ceil): " + Math.ceil(2.3));
System.out.println("下限丸め(floor): " + Math.floor(2.7));
System.out.println("最近傍の偶数(rint): " + Math.rint(2.5));
System.out.println("四捨五入(round): " + Math.round(2.5));
// 擬似乱数の制御生成
Random rng = new Random();
System.out.println("範囲指定乱数(0-99): " + rng.nextInt(100));
// 巨大整数の演算処理
BigInteger massiveNum = new BigInteger("12345678901234567890");
BigInteger factor = BigInteger.valueOf(99);
System.out.println("大数乗算結果: " + massiveNum.multiply(factor));
// 高精度小数の除算と桁数制御
BigDecimal numerator = new BigDecimal("10.0");
BigDecimal denominator = new BigDecimal("3.0");
BigDecimal divisionResult = numerator.divide(denominator, RoundingMode.HALF_UP);
System.out.println("高精度除算: " + divisionResult);
BigDecimal scaledResult = divisionResult.setScale(2, RoundingMode.DOWN);
System.out.println("桁数固定処理: " + scaledResult);
}
}
日時データの操作とフォーマット
システム時刻の取得にはSystem.currentTimeMillis()が利用され、1970年1月1日(協定世界時)からの経過ミリ秒を返却します。この値はアプリケーションの起動時間計測やパフォーマンス分析の基準として頻繁に使用されます。
日付の表現・操作については、歴史的なjava.util.Dateと、各要素(年・月・日・時・分・秒)の独立した制御を可能にするjava.util.Calendarが標準APIとして提供されています。Calendarは内部的にタイムゾーンルールやうるう年計算を処理するため、要素単位の加算や置換ロジックを組み込む際に確実な挙動を保証します。出力時にはSimpleDateFormatを用いて、アプリケーション固有の文字列表現に整形するのが一般的です。
package utility.demo.date;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class DateTimeManipulationDemo {
public static void main(String[] args) {
// エポックタイムによる経過計測
long initialEpoch = System.currentTimeMillis();
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
long finalEpoch = System.currentTimeMillis();
System.out.println("処理経過時間(ms): " + (finalEpoch - initialEpoch));
// 現在時刻の文字列化
Date currentMoment = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
System.out.println("現在時刻出力: " + formatter.format(currentMoment));
// カレンダーによる細粒度な日時操作
Calendar scheduler = Calendar.getInstance();
scheduler.set(2024, Calendar.JANUARY, 15, 10, 30, 0);
scheduler.add(Calendar.DAY_OF_MONTH, 5); // 日付の加算
scheduler.set(Calendar.HOUR_OF_DAY, 14); // 時間の直接設定
System.out.println("操作適用後: " + formatter.format(scheduler.getTime()));
System.out.println("適用タイムゾーン: " + scheduler.getTimeZone().getDisplayName());
}
}