0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Java発展学習4日目】JVM参照とリフレクションAPI

0
Posted at

JVMの終了

Systemクラスのexit()メソッドを用いてJVMを終了し、OS終了コード(exit code)を渡すことができる。

定義

void System.exit(int status)
// パラメータ
// status: 終了コード(0は「正常終了」、0以外は「異常終了」を表す)

外部プログラムの実行

ProcessBuilderクラスを通じてシェルスクリプト(bashスクリプト)を実行することができる。
また、Processクラスを通じて結果を受け取り、BufferedReaderを介して結果を読み込むこともできる。

サンプルコード

ShellScript.java
import java.io.BufferedReader;
import java.io.InputStreamReader;

class ShellScript {
    public static void main(String[] args){
        System.out.println("Make and Run .sh");

        // ProcessBuilderオブジェクトを用いてシェルスクリプトを作成
        ProcessBuilder pb = new ProcessBuilder("sh", "-c", "echo 'Hello!'");

        try {
            // シェルスクリプトの実行
            Process pc = pb.start();

            // 実行結果を格納するStringBuilderオブジェクト
            StringBuilder output = new StringBuilder();

            // 実行結果を読み込むBufferedReaderオブジェクト
            BufferedReader reader = new BufferedReader(new InputStreamReader(pc.getInputStream()));

            // 実行結果の読み込み
            String line;
            while ((line = reader.readLine()) != null) {
                output.append(line);
            }

            // 実行結果をコンソールに出力
            System.out.println(output.toString());
        }
        catch (Exception e) {
            // 例外発生時は標準エラーストリームに出力
            e.printStackTrace();

            // プログラムを終了
            System.exit(1);
        }
    }
}
実行結果
Make and Run .sh
Hello!

システムプロパティ(system property)

システムプロパティは、JVMによって管理されるJVMOSに関するデータを、
Set<String>型のキーProperties型ので保持するグローバルプロパティであり、
Systemクラスのメソッドを通じてシステムプロパティ取得追加変更ができる。

システムプロパティがもつ主なデータは、以下の通り。

キー (=Iterator<String>型) 内容
java.version 実行中JREバージョン
java.home 実行中Javaインストール先ディレクトリ
os.name 動作中OS
line.separator 動作中OS改行コード(newline code)
user.name 実行ユーザ

定義

// 現在の「システムプロパティ一覧」の取得
Properties System.getProperties();

// システムプロパティのキー群の取得
Set<String> Properties.stringPropertyNames()

// Set型 -> Iterator型 への変換
// -> Set型は要素の抽出や走査が不可能であるため、抽出・走査が可能なIterator型に変換
Iterator<String> Set<String>.iterator()

// 「要素を走査」してキーを取得
String Iterator<String>.next()

// キーを指定してシステムプロパティを取得
String System.getProperty(String key)
// パラメータ
// key: システムプロパティを特定するキー

サンプルコード

SystemProperties.java
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;

class SystemProperties {
    public static void main(String[] args) {
        // システムプロパティ一覧の取得
        Properties p = System.getProperties();

        // システムプロパティのキー群の取得
        Set<String> keySet = p.stringPropertyNames();

        // Set<String>型 -> Iterator<String>型 への変換
        // -> Iterator<E>型は要素の走査が可能
        Iterator<String> keyItr = keySet.iterator();

        // システムプロパティ一覧の表示
        System.out.println("-- System Properties --");
        while (keyItr.hasNext()) {
            // キーの抽出
            String key = keyItr.next();

            System.out.println(key + ": " + System.getProperty(key));
        }
    }
}
実行結果(抜粋)
-- System Properties --
user.name: b150005
path.separator: :
os.version: 11.4
java.runtime.name: OpenJDK Runtime Environment
os.name: Mac OS X
java.vm.name: OpenJDK 64-Bit Server VM
user.country: JP
sun.java.command: SystemProperties
java.version: 16.0.1
user.home: /Users/b150005
user.dir: /Users/b150005/Library/Mobile Documents/com~apple~CloudDocs/Java研修/advance/Advance
user.language: ja
os.arch: x86_64
file.separator: /
line.separator: 

java.vendor: AdoptOpenJDK

ロケール(locale)

参考: Localeクラス
Localeクラスを通じて参照変更が可能な、OSがもつユーザ国コード言語コードに関する情報。

定義

// デフォルトロケールの取得
Locale Locale.getDefault()

// デフォルトロケールの設定
void Locale.setDefault(Locale newLocale)
// パラメータ
// newLocale: 「デフォルトロケール」を表すLocaleオブジェクト

// 国コードの取得
String Locale.getCountry()

// 国名の取得
String Locale.getDisplayLanguage()

// 言語コードの取得
String Locale.getLanguage()

// 言語名の取得
String Locale.getDisplayLanguage()

タイムゾーン(time zone)

TimeZoneクラスを通じて参照変更が可能な、OSがもつユーザタイムゾーンに関する情報。

定義

// デフォルトタイムゾーンの取得
TimeZone TimeZone.getDefault()

// デフォルトタイムゾーンの設定
void TimeZone.setDefault(TimeZone zone)
// パラメータ
// zone: 「デフォルトタイムゾーン」を表すTimeZoneオブジェクト

// タイムゾーンの表示名を取得
String TimeZone.getDisplayName()

// タイムゾーンがサマータイムを採用している場合はtrueを返却
boolean TimeZone.useDaylightTime()

// サマータイムを考慮せず世界標準時との時差[ms]を取得
abstract int TimeZone.getRawOffset()

// サマータイムを考慮して世界標準時との時差[ms]を取得
int TimeZone.getOffset(long date)
// パラメータ
// date: 「1970年1月1日00:00:00 GMT」との差[ms]

サンプルコード

LocaleAndTimeZone.java
import java.util.Calendar;
import java.util.Locale;
import java.util.TimeZone;


public class LocaleAndTimeZone {
    public static void main(String[] args) {
        // デフォルトロケールの取得
        Locale loc = Locale.getDefault();

        // ロケール情報の表示
        System.out.println("Locale: " + loc.getDisplayName());
        System.out.println("Country Code: " + loc.getCountry());
        System.out.println("Country Name: " + loc.getDisplayCountry());
        System.out.println("Language Code: " + loc.getLanguage());
        System.out.println("Language Name: " + loc.getDisplayLanguage());

        // デフォルトタイムゾーンの取得
        TimeZone tz = TimeZone.getDefault();

        // カレンダーの取得
        Calendar cal = Calendar.getInstance();
        // カレンダー情報の時間値[ms]
        long calDate = cal.getTimeInMillis();

        // タイムゾーン情報の表示
        System.out.println("TimeZone: " + tz.getDisplayName());
        
        // サマータイムの採用情報をもとに分岐処理
        if (tz.useDaylightTime()) {
            System.out.println("DST is adopted.");
            
            // サマータイムを考慮して世界標準時(UTC)との時差を表示
            System.out.print("time difference from UTC: ");
            System.out.println(tz.getOffset(calDate) / 3600000 + "[hrs.]");
        }
        else {
            System.out.println("DST is not adopted.");

            // サマータイムを考慮せず世界標準時(UTC)との時差を表示
            System.out.print("time difference from UTC: ");
            System.out.println(tz.getRawOffset() / 3600000 + "[hrs.]");
        }
    }
}
実行結果
Locale: 日本語 (日本)
Country Code: JP
Country Name: 日本
Language Code: ja
Language Name: 日本語
TimeZone: 日本標準時
DST is not adopted.
time difference from UTC: 9[hrs.]

メモリ状態

Runtimeクラスを利用することで、JVMの現在のメモリ状態を取得することができる。

定義

// 現在のメモリの「空き容量」[byte]を取得
long Runtime.freeMemory()

// 「現在利用可能」なメモリの「総容量」[byte]を取得
long Runtime.totalMemory()

// 利用可能なメモリの「総容量の最大値」[byte]を取得
long Runtime.maxMemory()

サンプルコード

JVMMemory.java
import java.math.BigDecimal;
import java.math.RoundingMode;

public class JVMMemory {
    public static void main(String[] args) {
        // Runtimeインスタンスの取得
        Runtime rt = Runtime.getRuntime();
        
        System.out.println("-- Information of JVM Memory --");

        // 空きメモリ容量[byte]
        long freeL = rt.freeMemory();
        double freeD = (double) freeL;
        // 総容量[byte]
        long totalL = rt.totalMemory();
        double totalD = (double) totalL;
        // 最大容量[byte]
        long maxL = rt.maxMemory();
        double maxD = (double) maxL;

        // BigDecimalを用いたメモリデータ表示
        System.out.println("Free: " + new BigDecimal(freeD / 1024 / 1024 / 1024).setScale(2, RoundingMode.HALF_UP) + "[GB]");
        System.out.println("Total: " + new BigDecimal(totalD / 1024 / 1024 / 1024).setScale(2, RoundingMode.HALF_UP) + "[GB]");
        System.out.println("Use: " + new BigDecimal((totalD - freeD) / 1024 / 1024 / 1024).setScale(2, RoundingMode.HALF_UP) + "[GB]");
        System.out.println("Maximum: " + new BigDecimal(maxD / 1024 / 1024 / 1024).setScale(2, RoundingMode.HALF_UP) + "[GB]");
    }
}
実行結果
-- Information of JVM Memory --
Free: 1.01[GB]
Total: 1.02[GB]
Use: 0.01[GB]
Maximum: 16.00[GB]

リフレクション(reflection API)

JVMがもつ実行時型情報(RTTI; run-time type information)を取得するメソッドを提供するAPI
リフレクションAPIClass<T>クラスを通じて、実行時型情報を取得することができる。

なお、実行時型情報のうち、クラス(=配列・インタフェース・列挙型を含む)情報Class<T>インスタンス、
メンバ情報(フィールドメソッドコンストラクタ修飾子)はそれぞれFieldMethodConstructorModifierインスタンスが保持する。
ただし、修飾子情報の実体はModifierクラスのint型クラス定数で表される。

定義(クラス情報の取得)

クラス情報の取得
// クラス名を「FQCN(fully-qualified class name; 完全限定名)」で指定してクラス情報を取得
Class<?> Class<T>.forName(String className)
// パラメータ
// className: FQCN

// 「クラス名」を指定してクラス情報を取得
Class<?> <クラス名>.class

// 「オブジェクト名」を指定してクラス情報を取得
Class<?> Object.getClass()

定義(クラス情報の取得)

クラス情報の取得
// 「FQCN」の取得
String Class<T>.getName()

// 「クラス名」の取得
String Class<T>.getSimpleName()

// 「所属パッケージ名」の取得
Package Class<T>.getPackage()

// 「所属モジュール名」の取得
Module Class<T>.getModule()

// 「親クラス情報」を取得
Class<? super T> Class<T>.getSuperclass()

// 「配列」であればtrueを返却
boolean Class<T>.isArray()

// 「インタフェース」であればtrueを返却
boolean Class<T>.isInterface()

// 「列挙型」であればtrueを返却
boolean Class<T>.isEnum()

定義(各メンバ情報の取得)

getDeclared*()メソッドはクラスが保持する「全てのメンバ情報」を返却するのに対し、
get*()メソッドは「publicメンバ情報のみ」を返却する。

各メンバ情報の取得
// 「フィールド情報」の一覧を取得
Field[] Class<T>.getDeclaredFields()

// 「フィールド情報」を指定して取得
Field Class<T>.getDeclaredField(String name)
// パラメータ
// name: フィールド名

// 「メソッド情報」の一覧を取得
Method[] Class<T>.getDeclaredMethods()

// 「メソッド情報」を指定して取得
// -> 多重定義されている場合があるため、「メソッド名」と「引数の型」を指定
Method Class<T>.getDeclaredMethod(String name, Class<?>... parameterTypes)
// パラメータ
// name: メソッド名
// parameterTypes: メソッドの引数の型

// 「コンストラクタ情報」の一覧を取得
Constructor<?>[] Class<T>.getDeclaredConstructors()

// 「コンストラクタ情報」を指定して取得
Constructor<T> Class<T>.getDeclaredConstructor(Class<?>... parameterTypes)
// パラメータ
// parameterTypes: コンストラクタの引数の型

// 「修飾子情報」を取得
int getModifiers()

サンプルコード

Reflection.java
import java.lang.reflect.*;

public class Reflection {
    public static void main(String[] args) throws Exception {
        // 「クラス」からクラス情報を取得
        Class<?> cStatic = ReflectionTest.class;

        // 「クラス情報」から引数を指定してコンストラクタ情報を取得
        // -> NoSuchMethodException(検査例外)が発生する可能性があるため、
        //    以下の方法でエラーハンドリングを行う必要がある
        //    1. 呼び出すメソッド(=main())に"throws文"を付与
        //    2. "try-catch文"で例外発生時の処理を記述
        Constructor<?> con = cStatic.getConstructor(String.class, int.class);

        // 「コンストラクタ情報」からオブジェクトの生成
        // -> Constructor<?>型 -> 外部クラス型 へのキャストが必要
        ReflectionTest ref = (ReflectionTest) con.newInstance("A", 5);
        System.out.println("-- Before --");
        System.out.println(ref);
        System.out.println();

        // 「オブジェクト」からクラス情報を取得
        Class<?> cDynamic = ref.getClass();

        // 「クラス情報」からフィールド情報を取得
        // -> privateなメンバを取得する場合は"getDeclared*()"メソッドを利用
        Field fStr = cStatic.getDeclaredField("str");
        Field fInt = cDynamic.getDeclaredField("i");

        // privateなフィールドのアクセス権限を変更
        fStr.setAccessible(true);
        fInt.setAccessible(true);

        // 「フィールド情報」からオブジェクトの動的フィールドの値を変更
        fStr.set(ref, "Changed");
        fInt.set(ref, 13);
        System.out.println("-- After --");
        System.out.println(ref);
        System.out.println();

        // 「クラス情報」や各「メンバ情報」の修飾子を特定
        // -> Modifierクラスの「クラス定数」を利用する場合
        switch (cStatic.getModifiers()) {
            case Modifier.PUBLIC:
                System.out.println("Class " + cStatic.getSimpleName() + " is declared as public."); break;
            case Modifier.PROTECTED:
                System.out.println("Class " + cStatic.getSimpleName() + " is declared as protected."); break;
            case Modifier.PRIVATE:
                System.out.println("Class " + cStatic.getSimpleName() + " is declared as private."); break;
            default:
                System.out.println("Class " + cStatic.getSimpleName() + " is declared as default."); break;
        }
        Field fREF_S = cDynamic.getDeclaredField("REF_STATIC");
        int modfREF_S = fREF_S.getModifiers();
        // Modifierクラスの「クラスメソッド」を利用する場合
        if (Modifier.isPrivate(modfREF_S)) {
            System.out.print("Field " + fREF_S.getName() + " is declared as private");
            if (Modifier.isStatic(modfREF_S)) {
                System.out.print(", static");
                if (Modifier.isFinal(modfREF_S)) {
                    System.out.println(", final.");
                }
            }
        }
    }
}

class ReflectionTest {
    private String str = "";
    private int i = 0;
    // 動的final変数(利用しない)
    private final String REF = "Final String(dynamic)";
    // 静的final変数
    private static final String REF_STATIC = "Final String(static)";

    // デフォルトコンストラクタ
    public ReflectionTest() {}

    // オーバーロードしたコンストラクタ
    public ReflectionTest(String str) {
        this.str = str;
    }
    public ReflectionTest(int i) {
        this.i = i;
    }
    public ReflectionTest(String str, int i) {
        this.str = str;
        this.i = i;
    }

    // オーバーロードした動的メソッド
    public void add(String addStr) {
        this.str += addStr;
    }
    public void add(int j) {
        this.i += j;
    }
    public void add(String addStr, int j) {
        this.str += addStr;
        this.i += j;
    }

    @Override
    public String toString() {
        return "ReflectionTest(" + this.str + ", " + this.i + ") " + "[" + REF + ", " + REF_STATIC + "]";
    }
}
実行結果
-- Before --
ReflectionTest(A, 5) [Final String(dynamic), Final String(static)]

-- After --
ReflectionTest(Changed, 13) [Final String(dynamic), Final String(static)]

Class ReflectionTest is declared as default.
Field REF_STATIC is declared as private, static, final.

用語集

用語 内容
システムプロパティ(system property) JVMが管理する、JVMOSに関するデータを保持するプロパティ。
環境変数(environment variable) OSが管理する、OSに関するデータを保持する変数。
実行時型情報(RTTI; Run-Time Type Information) がもつパッケージ親クラスメンバ修飾子などの情報。
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?