- PR -

新人SEのためのJava講座についての質問

投稿者投稿内容
tarnwo
ベテラン
会議室デビュー日: 2002/10/25
投稿数: 58
投稿日時: 2002-12-16 19:31
static なメソッドやインスタンスを持つクラスの例として
よく使われるものの一つに,Mathがありますね。
・数学関数の処理は別に変更する必要がなく,共通で使える
・円周率なども共通で使える(値は不変なのでfinal)
staticを使うにあたって,なんとなくイメージがつくと思います。

また,外部ライブラリなどを読み込むときにも,
何度もライブラリをロードする必要が無いので,
読み込む部分をstatic にしたりします。

#脱線かな?
ayum
常連さん
会議室デビュー日: 2002/03/28
投稿数: 44
お住まい・勤務地: 東京
投稿日時: 2002-12-16 21:40
引用:
ちなみにstaticメソッドにしたユーティリティメソッドを別の複数のクラス
から同タイミングで使用した場合、何か不具合が発生するのでしょうか?



そのクラス内でフィールドに対して値を変更するメソッドが存在せず、
なおかつそのメソッドあるいはメソッド内部でsynchronizedが使われないなら
複数クラスの同時アクセスでも基本的には大丈夫です。
synchronizedに関しては話がややこしくなるのでここは置かせていただいて、
例えば以下のような場合、

コード:
public class ClassA {
  private static int value = 0;

  public static void setValue( int val ) { value = val;}
  public static int  getValue()          { return( value );}
}



上記のメソッドでAさんがまずsetValue( 1 )とセットしました。
次にBさんがsetValue( 2 )とセットしました。
そしてAさんが「自分がセットした1がClassA.getValue()で返ってくるんだろうな」と
期待してClassA.getValue()と呼ぶと、
自分が期待した1でなくBさんがセットした2が返ってきてしまいます。
staticなフィールドは全部のスレッドから共通のものにアクセスするので、
このような問題が発生する可能性はあります。

ので、staticなメソッドからはフィールドは
static finalなものしか参照しないというのが基本となるかと思います。

上記のルールにのっとった上でなら、
メソッドはコールされる度にメソッド内部のローカルな処理に関しては
それぞれ固有なメモリ領域で行われることになるので
複数スレッドからの同時アクセスでも問題が発生したりはしないです。

参考までに大雑把に言うなら、フィールドやメソッドがstaticであるないに関わらず、
メソッド内部の処理は基本的にメソッドが呼ばれる度に個別の領域で処理されて、
フィールド参照に関してはstaticでないものならそのインスタンスで共通、
staticなものならそのクラスで共通なものとしてアクセスしにいくことになります。
H2
ぬし
会議室デビュー日: 2001/09/06
投稿数: 586
お住まい・勤務地: 港
投稿日時: 2002-12-16 21:51
ちょっと途中で脱線している過去のスレッドですが、
「staticメソッドに関して」
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=1758&forum=12&start=0
というのもあります。

難しいかもしれませんが、並列に話題になっている
「ちょっと突っ込んだ質問ですが」
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=3044&forum=12&6
も役に立つかもしれません。

他にも過去ログにオブジェクトとクラスの違いなんていうのがあったような気がします。漁ってみるのも面白いですよ。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2002-12-17 11:03
unibon です。こんにちわ。

引用:

ひで720さんの書き込み (2002-12-16 18:38) より:
ちなみにstaticメソッドにしたユーティリティメソッドを別の複数のクラス
から同タイミングで使用した場合、何か不具合が発生するのでしょうか?
低レベルの質問で申し訳ありませんがご教授願います。



同期の問題は、メソッドが static かどうかとまったく関係がないと思います。
上記の「同タイミング」がマルチスレッドを使ってのことならば、
やはり static であっても自分で同期を意識する必要があります。
具体例としてはつぎのようなサンプルがあります。

public class Hello {
private static long s;
public /* synchronized */ static long sum() {
s = 0;
for (int i = 0; i < 10000000; i++) {
s += i;
}
return s;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
public void run() {
long a = Hello.sum();
System.out.println("a = " + a);
}
};
Thread t0 = new Thread(r);
Thread t1 = new Thread(r);
t0.start();
t1.start();
}
}

synchronized をコメントにしてありますが、
こうすると2つのスレッドが同時に動くため、
結果が2つのスレッドで異なったものになることがあります。
#運が良ければ(悪ければ?)、同じ値になりますが。

ちなみに、Thread を自分で明示的に作らなければ、
自分で書いたコードはひとつのスレッドでしか動かないので、
同時に動くことはないので、気にする必要はないです。

しかし、static は難しいですね。詳しく解説すると本が一冊書けそうな気もします。
上記のサンプルは synchronized を付けるとうまく動きますが、
でもこの synchronized は、何に対する同期なのでしょうか。
インスタンスを new で生成していないのですが、
Hello のクラス専用に static 用のインスタンスがひとつ暗に生成されていて、
それに対する同期になるのでしょうか。
t-wata
大ベテラン
会議室デビュー日: 2002/07/12
投稿数: 209
お住まい・勤務地: 東京
投稿日時: 2002-12-17 11:14
引用:

でもこの synchronized は、何に対する同期なのでしょうか。



public synchronized static long sum() {
 コード
}

は、
public static long sum(){
 synchronized(Hello.class){
  コード
 }
}
と同じです。
public synchronized long sum(){
  コード

 }
が、
public long sum(){
 synchronized(this){
  コード
 }
}
と同じになるのと一緒です。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2002-12-18 09:09
unibon です。こんにちわ。

引用:

t-wataさんの書き込み (2002-12-17 11:14) より:
public synchronized static long sum() {
 コード
}

は、
public static long sum(){
 synchronized(Hello.class){
  コード
 }
}
と同じです。



ありがとうございます。Hello.class でしたか。
今まではなんとなく、
new Hello()
してできるインスタンスに近いものが
static 用に別にできているのかと思っていました。

[ メッセージ編集済み 編集者: unibon 編集日時 2002-12-18 11:50 ]
raccoon
ベテラン
会議室デビュー日: 2002/12/18
投稿数: 58
投稿日時: 2002-12-18 11:34
ども,はじめまして。
raccoonです。よろしくお願いします。

本日デビューの新参者なのにイキナリ生意気なことを言うようですが,
staticにすべきか否かについては,わたしは分析・設計時に自ずと決まるものだと考えています。

例えば「発泡酒」というクラスがあり,インスタンスが個々のカンを表すとします。
ここで「税率を上げる」というメソッドを作る場合,それはstaticになるでしょう。1本1本に対して税率を操作することはありえないからです。
逆に「飲む(=中身を消費する)」というメソッドがあるなら,それは非staticになるでしょう。抽象的な発泡酒というものを飲むことはできないからです。

実際には「税率」というstaticメンバと「残量」という非staticメンバを持つでしょうから,結果的にはみなさんの言うことと同じになると思いますが,考え方が違います。

メソッドは操作であり,操作の対象が「発泡酒」という一般名詞なのか,個々のカンなのかという点を明確にして,staticかどうかを自動的に決めるものでしょう。
「メンバがこうだから」とか「こう使いたいから」という,実装の観点から決めるべきものではないと考えています。

# あくまで「理論上は」の話であり,実際こうキレイに決まるものではないことは承知していますが・・・。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2002-12-18 19:44
unibon です。こんにちわ。

引用:

raccoonさんの書き込み (2002-12-18 11:34) より:
本日デビューの新参者なのにイキナリ生意気なことを言うようですが,
staticにすべきか否かについては,わたしは分析・設計時に自ずと決まるものだと考えています。

例えば「発泡酒」というクラスがあり,インスタンスが個々のカンを表すとします。
ここで「税率を上げる」というメソッドを作る場合,それはstaticになるでしょう。1本1本に対して税率を操作することはありえないからです。



いろいろ static について考えてみたのですが、
static なものはフィールドとメソッドがありますが、
まず static なメソッドについては、
結局はアクセスのし易さのためにあるものであり、
インスタンスに依存しないようなコードの入れ場所、
という程度の意味合いしかないと思います。
(結局のところ、static メソッドはどうでもいい、というような感じです。)
#static な class もあるそうですが、考えないことにします。

一方、static なフィールドは、
複数のインスタンスから共有される唯一のインスタンスとして使われ、
アクセスする際にそのフィールドのインスタンスを書かなくてよいなど、
簡便に使えて便利ですが、後述するような弊害のほうが大きいと思いますので、
static なフィールドは使わないほうがよいと考えます。

たとえば、発泡酒の例だと、
税率はたまたまひとつで良いのかもしれませんが、
揚げ足取りになるかもしれませんが、輸出することを考えると、
国によって税率が変わるなどで、
複数の税率を管理する必要が出てきます。

このように、現時点での分析・設計では、ひとつしかないから、
という理由で static なフィールドを使ってしまうと、
このように、ひとつを超えるものを扱う必要が出てきた場合に、
拡張性が乏しくなる可能性があります。
煩雑になるかもしれませんが、static のフィールドは一切使わずに、
それに代わるようなインスタンスをひとつ new して、
そのインスタンスを参照して使うほうが、
明示的に参照できるので良いと考えます。
ただ、こうすると、そのインスタンスを引数で渡したり、
中継するクラスのフィールドで参照させたりと、
コードが煩雑になってしまいますが、でも、将来の拡張には強いと考えます。

なお、将来のことは今考えなくてもそのときに対処すればよい
(なまじ将来を見越すのは逆効果である)、
というのが最近の流行のようですが、
でも、コードの途中でいきなり static のフィールドにアクセスするのは、
グローバル変数の考えの延長のような気がして、納得できません。

ただ、定数のような位置付けのものは、
さすがに static なフィールドでも良いと考えます。
じゃあ、「定数」かそうでないかの違いはなにか、
と聞かれると悩んでしまいます。
雰囲気としては、
クラスの中で自発的に生じてきたような定数は、static なフィールドでも良いが、
外部から左右されるような可能性を持った定数(上記のような税率)は、ダメ、
というふうに感じます。

#自分で読み返してみると、なんだか、うまく説明になっていないですね。
#また、なぜかここでもフィールド重視になってしまっているような気がする(笑)。

スキルアップ/キャリアアップ(JOB@IT)