#pragma twice

KAB-studio > プログラミング > Javaのオブジェクト指向入門 > 4. staticはどこにある? > 4.4 staticメソッドから非staticフィールドは?
 
前のページへつぎ

4.4 staticメソッドから非staticフィールドは?

del.icio.us 登録する はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数 livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数 Yahoo!ブックマーク 詳細を表示 users RSSに登録
更新日: 2008/03/31
動作確認環境:Windows XP Professional SP2, Java SE 5

staticメソッドから普通のフィールドを使う……

 前ページで紹介したstaticメソッドには、実は制限があります。
 それは「staticじゃない普通のフィールドを直接使えない」というものです。

// HasStaticAndNormalMethodRunner.java

/**
 * staticメソッドと普通のメソッドを持つクラス。
 */
class HasStaticAndNormalMethod
{
    // int型変数のstaticフィールドdataStaticを定義します。
    static int dataStatic;

    // int型変数のフィールドdataNormalを定義します。
    int dataNormal;

    /**
     * フィールドを出力するstaticメソッドです。
     */
    static void staticPrintData()
    {
        // staticフィールドを出力します。
        System.out.println( dataStatic );
        // 普通のフィールドを出力します。
        // System.out.println( dataNormal );
        // コンパイルエラー:
        // HasStaticAndNormalMethodRunner.java:22: 
        // static でない 変数 dataNormal を 
        // static コンテキストから参照することはできません。

        // staticメソッドから普通のフィールドは
        // 「わからない」ので出力できません。
    }

    /**
     * フィールドを出力する普通のメソッドです。
     */
    void normalPrintData()
    {
        // staticフィールドを出力します。
        System.out.println( dataStatic );
        // 普通のフィールドを出力します。
        System.out.println( dataNormal );
    }
}

/**
 * 実行用クラス。このクラスを実行してください。
 */
class HasStaticAndNormalMethodRunner
{
    public static void main( String[] args )
    {
        // staticフィールドに数値を入れます。
        HasStaticAndNormalMethod.dataStatic = 1;

        // インスタンスを1つ作り数値を入れます。
        HasStaticAndNormalMethod ref = new HasStaticAndNormalMethod();
        ref.dataNormal = 100;

        // staticメソッドを使って出力します。
        HasStaticAndNormalMethod.staticPrintData();
        // 出力結果:
        // 1

        // staticメソッドから普通のフィールドは
        // 「わからない」ので出力されません。

        // 普通のメソッドを使って出力します。
        ref.normalPrintData();
        // 出力結果:
        // 1
        // 100
    }
}
// HasStaticAndNormalMethodRunner.java
/**
 * staticメソッドと普通のメソッドを持つクラス。
 */
class HasStaticAndNormalMethod
{
	// int型変数のstaticフィールドdataStaticを定義します。
	static int dataStatic;
	// int型変数のフィールドdataNormalを定義します。
	int dataNormal;
	/**
	 * フィールドを出力するstaticメソッドです。
	 */
	static void staticPrintData()
	{
		// staticフィールドを出力します。
		System.out.println( dataStatic );
		// 普通のフィールドを出力します。
		// System.out.println( dataNormal );
		// コンパイルエラー:
		// HasStaticAndNormalMethodRunner.java:22: 
		// static でない 変数 dataNormal を 
		// static コンテキストから参照することはできません。
		// staticメソッドから普通のフィールドは
		// 「わからない」ので出力できません。
	}
	/**
	 * フィールドを出力する普通のメソッドです。
	 */
	void normalPrintData()
	{
		// staticフィールドを出力します。
		System.out.println( dataStatic );
		// 普通のフィールドを出力します。
		System.out.println( dataNormal );
	}
}
/**
 * 実行用クラス。このクラスを実行してください。
 */
class HasStaticAndNormalMethodRunner
{
	public static void main( String[] args )
	{
		// staticフィールドに数値を入れます。
		HasStaticAndNormalMethod.dataStatic = 1;
		// インスタンスを1つ作り数値を入れます。
		HasStaticAndNormalMethod ref = new HasStaticAndNormalMethod();
		ref.dataNormal = 100;
		// staticメソッドを使って出力します。
		HasStaticAndNormalMethod.staticPrintData();
		// 出力結果:
		// 1
		// staticメソッドから普通のフィールドは
		// 「わからない」ので出力されません。
		// 普通のメソッドを使って出力します。
		ref.normalPrintData();
		// 出力結果:
		// 1
		// 100
	}
}

 HasStaticAndNormalMethodクラスは、staticフィールドと普通のフィールド、staticメソッドと普通のメソッドを持っています。

/**
 * staticメソッドと普通のメソッドを持つクラス。
 */
class HasStaticAndNormalMethod
{
    // int型変数のstaticフィールドdataStaticを定義します。
    static int dataStatic;

    // int型変数のフィールドdataNormalを定義します。
    int dataNormal;

    /**
     * フィールドを出力するstaticメソッドです。
     */
    static void staticPrintData()
    {
        // staticフィールドを出力します。
        System.out.println( dataStatic );
        // 普通のフィールドを出力します。
        // System.out.println( dataNormal );
        // コンパイルエラー:
        // HasStaticAndNormalMethodRunner.java:22: 
        // static でない 変数 dataNormal を 
        // static コンテキストから参照することはできません。

        // staticメソッドから普通のフィールドは
        // 「わからない」ので出力できません。
    }

    /**
     * フィールドを出力する普通のメソッドです。
     */
    void normalPrintData()
    {
        // staticフィールドを出力します。
        System.out.println( dataStatic );
        // 普通のフィールドを出力します。
        System.out.println( dataNormal );
    }
}
/**
 * staticメソッドと普通のメソッドを持つクラス。
 */
class HasStaticAndNormalMethod
{
	// int型変数のstaticフィールドdataStaticを定義します。
	static int dataStatic;
	// int型変数のフィールドdataNormalを定義します。
	int dataNormal;
	/**
	 * フィールドを出力するstaticメソッドです。
	 */
	static void staticPrintData()
	{
		// staticフィールドを出力します。
		System.out.println( dataStatic );
		// 普通のフィールドを出力します。
		// System.out.println( dataNormal );
		// コンパイルエラー:
		// HasStaticAndNormalMethodRunner.java:22: 
		// static でない 変数 dataNormal を 
		// static コンテキストから参照することはできません。
		// staticメソッドから普通のフィールドは
		// 「わからない」ので出力できません。
	}
	/**
	 * フィールドを出力する普通のメソッドです。
	 */
	void normalPrintData()
	{
		// staticフィールドを出力します。
		System.out.println( dataStatic );
		// 普通のフィールドを出力します。
		System.out.println( dataNormal );
	}
}

 ちょっと長いですが、よく見るとこれまで紹介してきたものを全部組み合わせただけです。
 このプログラムでは、次の4通りの組み合わせを試しています。

 1.staticメソッドからstaticフィールドを使う
 2.staticメソッドから普通のフィールドを使う
 3.普通のメソッドからstaticフィールドを使う
 4.普通のメソッドから普通のフィールドを使う

 このうち、「2.staticメソッドから普通のフィールドを使う」だけができません

    /**
     * フィールドを出力するstaticメソッドです。
     */
    static void staticPrintData()
    {
        // staticフィールドを出力します。
        System.out.println( dataStatic );
        // 普通のフィールドを出力します。
        System.out.println( dataNormal );
        // コンパイルエラー:
        // HasStaticAndNormalMethodRunner.java:22: 
        // static でない 変数 dataNormal を 
        // static コンテキストから参照することはできません。
    }
	/**
	 * フィールドを出力するstaticメソッドです。
	 */
	static void staticPrintData()
	{
		// staticフィールドを出力します。
		System.out.println( dataStatic );
		// 普通のフィールドを出力します。
		System.out.println( dataNormal );
		// コンパイルエラー:
		// HasStaticAndNormalMethodRunner.java:22: 
		// static でない 変数 dataNormal を 
		// static コンテキストから参照することはできません。
	}

 staticPrintData()メソッドはstaticメソッドです。
 このメソッドから、普通のフィールドであるdataNormalフィールドを使うことができません。使うとコンパイルエラーになります。
 なぜ使えないかというと、それは「どのインスタンスのdataNormalフィールドかわからない」からです。

 これは静的領域とインスタンスの関係を考えれば当然のことです。
 静的領域とインスタンスは別です。離ればなれになっています。
 そして、静的領域はインスタンスを管理しているわけではありません。静的領域にとって、同じクラスのインスタンスはたくさんあって、静的領域はそれらインスタンスとまったく結びついていません。
 インスタンス内にあるフィールドやメソッドは、当然「どのインスタンスの」フィールド・メソッドか、ということを指定する必要があります。
 だから、

    static void staticPrintData()
    {
        System.out.println( dataNormal );
    }
	static void staticPrintData()
	{
		System.out.println( dataNormal );
	}

 なんてしても、静的領域にあるstaticPrintData()メソッドから見て、dataNormalフィールドが「どのインスタンスのdataNormalフィールドか」ということが指定されていないわけですから、dataNormalフィールドを使えるわけがないのです。

 ちなみにこの逆、つまり「3.普通のメソッドからstaticフィールドを使う」は問題なく使えます。
 インスタンスは「自分のクラスが何クラスか」ということを知っています。ということは「自クラスの静的領域」も見つけることができるということです。なので、その中のstaticフィールドを使うことができるというわけです。

イメージしよう!

 これらは、インスタンスと静的領域の図をイメージできれば分かることでしょう。
 重要なのは、HasStaticAndNormalMethodクラスのようなプログラムを見て、そのイメージができるかどうか、という点です。
 普通にHasStaticAndNormalMethodクラスを見ると、dataStaticフィールドとdataNormalフィールドを一緒に考えてしまうかもしれません。
 でも、「static」の有無で「静的領域に置かれるかインスタンスに置かれるか」ということを区別できれば、別々なんだということをイメージできると思います。

4.4 staticメソッドから非staticフィールドは?
このページは、Java言語を用いたオブジェクト指向プログラミングのチュートリアル解説を行う「Javaのオブジェクト指向入門」の一ページです。
詳しい説明は「Javaのオブジェクト指向入門」目次をご覧ください。