27673


題名の通り、何故`static`の変数にインスタンスを使ってアクセスをしたらいけないのでしょうか。

* * *

Javaでは、`static`な変数に`非static`にアクセスしようとすると警告が出ます。

[code]

    class Instance{
      public static final name="Static Field";
    }
    class Access{
      public static void main(String[] args){
        System.out.println(new Instance().name);
        //警告(static-access)
      }
    }
    
[/code]

このコードだと、インスタンスを無駄に生成している。ということで納得いきます。

ここも参考にしました。

[Google Java Style](https://kazurof.github.io/GoogleJavaStyle-ja/#s6-3-static-
members):

> staticなメンバーを修飾する必要がある場合はクラス名を使う。そのクラスの変数や式経由で使ってはならない。

ですが次のような時はどうでしょう。

[code]

    public class Main{
      public static void main(String[] args){
        Class<?> cls = Class.forName(args[1]);
        Instance instance=(Instance)cls.newInstance();
        Load.load(instance);
      }
    }
    class Load{
      public static load(Instance instance){
        //警告発生
        System.out.print(instance.explanation);
      }
    }
    abstract class Instance{
      public static explanation;
    }
    
[/code]

このコードでは、Instanceを継承したクラスのstaticフィールドにアクセスするのが目的なのですが、`Instance`を継承したクラスの名前は決まっているわけではないので

[code]

    クラス名.フィールド名
    
[/code]

でアクセスすることが出来ない(出来るとしても少し手間がかかる)と思います。  
警告自体は

[code]

    @SuppressWarning("static-access")
    
[/code]

で抑えられるのですがどうしてなのかなと思って投稿しました。


CC BY-SA 3.0
2016-07-16T12:47:05.053
27665
2016-07-17T02:01:08.507
2016-07-17T02:01:08.507
2808
15185
question
java
何故staticの変数、メソッドにインスタンスを使ってアクセスしたらいけないのか


件名となっている質問

> 何故staticの変数、メソッドにインスタンスを使ってアクセスしたらいけないのか

の回答としては、該当メソッドを呼ぶためにインスタンスは生成する必要が無いから、ということになります。(おそらくご理解の通りかと。)

後半のコードについては、次のような形でリフレクションを使ってアクセスすることになります。

[code]

    import java.lang.reflect.Field;
    
    public class Main {
        public static void main(String[] args) throws Exception {
            Class<? extends Instance> cls = (Class<? extends Instance>) Class.forName(args[1]);
            Load.load(cls);
        }
    }
    
    class Load {
        public static void load(Class<? extends Instance> cls) throws Exception {
            Field field = cls.getField("explanation");
            System.out.print(field.get(null));
        }
    }
    
[/code]

ただ、例示されているコードを見る限り、単にインスタンス変数を使用すべき箇所で`static`変数を使用しようとしているだけのように見えます。  
(そういう誤りが発見できているという意味でも、警告が発せられているのは妥当であると言えます。)


CC BY-SA 3.0
2016-07-16T13:43:24.767
27668
2016-07-17T01:51:59.350
2016-07-17T01:51:59.350
2808
2808
27665
answer


> 何故staticの変数にインスタンスを使ってアクセスをしたらいけないのでしょうか。

`static`なフィールドはインスタンスではなくクラスに属するものです。  
インスタンス経由アクセスでコンパイラが警告をしてくれるのは、「プログラマが何か勘違いをしている可能性があり、潜在バグの可能性がある」との判断からじゃないでしょうか。

> `Instance`を継承したクラスの名前は決まっているわけではないので
[code]

>     クラス名.フィールド名
>  
[/code]

>
> でアクセスすることが出来ない(出来るとしても少し手間がかかる)と思います。

いえ、`Instance.explanation`でアクセスできます。

`static`なフィールドは継承されません。例でいうと`Instance`クラスの子クラス毎に別々の`explanation`が存在するわけではありません。


CC BY-SA 3.0
2016-07-16T14:42:02.343
27670
2016-07-16T14:42:02.343
4765
27665
answer


> `Instance`を継承したクラスの名前は決まっているわけではないので
[code]

>     クラス名.フィールド名
>  
[/code]

>
> でアクセスすることが出来ない(出来るとしても少し手間がかかる)と思います。

静的メンバは継承することはできても、派生クラスで同じ名前の静的メンバを定義した場合には基底クラスのそれを隠し、別のメンバとして扱われます。

[code]

    public static load(Instance instance){
      System.out.print(instance.explanation);
    }
    
[/code]

またこれはインスタンス経由で静的メンバにアクセスしているように見えますが、どのクラスの静的メンバにアクセスするかはコンパイル時に決定します。ここでは
`Instance` 型の変数ですから、（派生クラスではなく）`Instance.explanation` へアクセスするようコンパイルされます。

例えば次のコードで `foo` と `bar` は同じインスタンスのはずですが、どの型の変数を通してアクセスするかで結果が変わっています。

[code]

    class Sample
    {
        public static void main (String[] args)
        {
            Derived foo = new Derived();
            Base bar = foo;
            System.out.println("Derived foo: " + foo.name); // => Derived
            System.out.println("Base bar: " + bar.name); // => Base
        }
    }
    
    abstract class Base {
      public static String name = "Base";
    }
    
    class Derived extends Base {
      public static String name = "Derived";
    }
    
[/code]

実行例 <http://ideone.com/TavNp3>

ですから、冒頭のような場面でも型名の代わりに変数名を使えば動的に解決してくれる、なんてことはありません。もし「実行時の型に応じて静的フィールド
`explanation` にアクセスする」といった必要があれば、直接アクセスする代わりにインスタンスメソッドを経由すべきかと思います。（例
<http://ideone.com/heb9K0>）

インスタンスメンバと紛らわしく、あえてこのような記法をする必要性も薄いですから、ミスの可能性が高いとして警告を発するのでしょう。

参考

  * [Are static methods inherited in Java? - Stack Overflow](https://stackoverflow.com/a/10292034/2818869)
  * The Java™ Tutorials  
[Overriding and Hiding
Methods](http://docs.oracle.com/javase/tutorial/java/IandI/override.html)  
[Hiding
Fields](http://docs.oracle.com/javase/tutorial/java/IandI/hidevariables.html)


CC BY-SA 3.0
2016-07-16T15:56:01.667
27673
2016-07-16T16:15:09.647
2017-05-23T12:38:55.307
-1
8000
27665
answer