69003


以下のプログラムで質問です。  
ClassSampleクラスをstatic classとしましたが、コンパイルエラーが出てしまいます。

エラー内容

[code]

    Sample1.java:18: エラー: 修飾子staticをここで使用することはできません
    static class ClassSample {
           ^
    エラー1個
    
[/code]

私の認識ですと、static
classは、メインクラスで複数インスタンスを生成しても、全てのインスタンスで共通に使えるクラス変数、オブジェクト。一方、public
classもしくはclassは、コンストラクタを実行して生成した個々のインスタンスごとにしか使えない変数、おぶじぇくとと認識しています。  
ただ、オブジェクト指向で、クラスにstaticをつける場合とそうでない場合の使い分けができません。わかり易く教えて頂ければ幸いです。

* * *
[code]

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*; 
     
    public class Sample1 {
     
        public static void main(String[] args) { 
            for (int i = 0; i < 3; i++){
                ClassSample cs = new ClassSample(1, 1);
                cs.print();
            }
        }
    }
    
    static class ClassSample {
        private 
        int val1 = 0; 
        private  
        int val2 = 0; 
     
        // コンストラクタ　クラスがインスタンス化される度に変数に1加算する
        public ClassSample(int val1, int val2) {
            this.val1 += val1;
            this.val2 += val2; 
            //ClassSample.val2+=val2;
        }
     
        // 変数の値を表示
        public void print(){
            System.out.println("val1 = " + val1 + ", val2 = " + val2);
        }
    }
    
[/code]


CC BY-SA 4.0
2020-07-27T01:32:36.037
69001
2020-07-27T02:31:03.583
2020-07-27T01:36:00.827
3060
39688
question
java
static class とpublic classの違いについて


あなたの「認識」、意味不明なところがあるので私が読み取れていないだけかもしれませんが、根本的に誤っている、と言ってしまって良いと思います。

  * `public`は宣言の公開範囲を決めるためのものです
  * `static`は **ネストされたクラス宣言** において、内側クラスの働きを変更します
  * 両者は独立したものなので、`public static`と両方を指定することもできます

以下に「ネストされたクラス宣言」の例を挙げておきます。

[code]

    public class MyOuterClass {
        public class MyInnerClass {
            private void someInnerMethod() {
                System.out.println("someInnerMethod called" + outerField);
            }
        }
        
        private MyInnerClass inner;
        
        ///`MyOuterClass`のフィールド
        private String outerField = "test";
        
        public MyOuterClass() {
            this.inner = new MyInnerClass();
        }
        
        public void someMethod() {
            this.outerField = "ABC";
            this.inner.someInnerMethod();
        }
    }
    
[/code]

(話を簡単にするため、getter/setterなんかは定義していません。)

通常の`MyOuterClass`の中に、ネストされた形で`MyInnerClass`が定義されており、`MyInnerClass`のメソッド`someInnerMethod()`中で、別クラスである`MyOuterClass`のフィールド`outerField`にアクセスしており、期待通りに動作します。

[code]

            MyOuterClass obj = new MyOuterClass();
            obj.someMethod(); //-> someInnerMethod called:ABC
    
[/code]

なんとなくでぼんやり見ていると、できて当たり前に見えるかもしれませんが、本来は`MyOuterClass`と`MyInnerClass`は別クラスなのに、`MyOuterClass`のインスタンスを通さないで`MyOuterClass`のインスタンスフィールドにアクセス出来ると言うのはおかしいことなのです。

Javaのコンパイラーはこの「一見当たり前に思えるけど、よく考えるとできる方がおかしい」なんてことを出来るようにするために、裏でとんでもなく複雑なことをしています。

ネストされたクラス宣言の内側クラスに`static`を付けるのは、Javaのコンパイラーに「そんなややこしいことはしなくて良いですよ」と言う指示をしていることになります。

実際、上記のコードの`public class MyInnerClass {`の行に`static`を付け加えて`public static class
MyInnerClass {`と変更してやると、`someInnerMethod()`の中で、エラーが発生します。

[code]

                System.out.println("someInnerMethod called:" + outerField);
                // non-static variable outerField cannot be referenced from a static context
    
[/code]

* * *

あなたが現在の認識に至った理由がよくわかりませんが、コード例をいくつか眺めて自己流に認識したつもりになっているだけではありませんか?
きちんとしたJava言語の教科書(図書館に置いてあるようなちょっと古いものでもOKです)を読んでみることをお勧めします。

最初に書いたようにクラス宣言に対する`static`はネストされたクラス宣言に対してのみ有効です。あなたの例で言うと、こんな書き方になります。

[code]

    public class Sample1 {
        
        private static class ClassSample {
            private int val1 = 0; 
            private int val2 = 0; 
    
            // コンストラクタ　クラスがインスタンス化される度に変数に1加算する
            public ClassSample(int val1, int val2) {
                this.val1 += val1;
                this.val2 += val2; 
                //ClassSample.val2+=val2;
            }
    
            // 変数の値を表示
            public void print(){
                System.out.println("val1 = " + val1 + ", val2 = " + val2);
            }
        } 
    
        public static void main(String[] args) { 
            for (int i = 0; i < 3; i++){
                ClassSample cs = new ClassSample(1, 1);
                cs.print();
            }
        }
    }
    
[/code]

`ClassSample`の中では、`Sample1`のインスタンスメンバーにアクセスしているところはありませんから、`static`を付けることによってJavaコンパイラーに「ややこしいことはしなくて良いですよ」と指示したことになるわけです。

(当然不要な「ややこしいこと」をさせると、メモリ使用・速度などで不利になります。)

Javaのこのネストされたクラスに関する仕様は意図せぬ動作を引き起こしてバグの要因になることもあり、最近では「使わない方が良い」と言う認識をもたれる場合が多いようです。

「Javaの動作を熟知した上で、ネストされたクラスに関する特殊な動作を利用したいと言う場合以外には、内側クラスは必ず`static`をつけるもの」くらいに認識しておいた方が良いかもしれません。


CC BY-SA 4.0
2020-07-27T02:31:03.583
69003
2020-07-27T02:31:03.583
13972
69001
answer