- - PR -
新人SEのためのJava講座についての質問
| 投稿者 | 投稿内容 | ||||||||
|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2002-12-16 19:31
static なメソッドやインスタンスを持つクラスの例として
よく使われるものの一つに,Mathがありますね。 ・数学関数の処理は別に変更する必要がなく,共通で使える ・円周率なども共通で使える(値は不変なのでfinal) staticを使うにあたって,なんとなくイメージがつくと思います。 また,外部ライブラリなどを読み込むときにも, 何度もライブラリをロードする必要が無いので, 読み込む部分をstatic にしたりします。 #脱線かな? | ||||||||
|
投稿日時: 2002-12-16 21:40
そのクラス内でフィールドに対して値を変更するメソッドが存在せず、 なおかつそのメソッドあるいはメソッド内部でsynchronizedが使われないなら 複数クラスの同時アクセスでも基本的には大丈夫です。 synchronizedに関しては話がややこしくなるのでここは置かせていただいて、 例えば以下のような場合、
上記のメソッドでAさんがまずsetValue( 1 )とセットしました。 次にBさんがsetValue( 2 )とセットしました。 そしてAさんが「自分がセットした1がClassA.getValue()で返ってくるんだろうな」と 期待してClassA.getValue()と呼ぶと、 自分が期待した1でなくBさんがセットした2が返ってきてしまいます。 staticなフィールドは全部のスレッドから共通のものにアクセスするので、 このような問題が発生する可能性はあります。 ので、staticなメソッドからはフィールドは static finalなものしか参照しないというのが基本となるかと思います。 上記のルールにのっとった上でなら、 メソッドはコールされる度にメソッド内部のローカルな処理に関しては それぞれ固有なメモリ領域で行われることになるので 複数スレッドからの同時アクセスでも問題が発生したりはしないです。 参考までに大雑把に言うなら、フィールドやメソッドがstaticであるないに関わらず、 メソッド内部の処理は基本的にメソッドが呼ばれる度に個別の領域で処理されて、 フィールド参照に関してはstaticでないものならそのインスタンスで共通、 staticなものならそのクラスで共通なものとしてアクセスしにいくことになります。 | ||||||||
|
投稿日時: 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 も役に立つかもしれません。 他にも過去ログにオブジェクトとクラスの違いなんていうのがあったような気がします。漁ってみるのも面白いですよ。 | ||||||||
|
投稿日時: 2002-12-17 11:03
unibon です。こんにちわ。
同期の問題は、メソッドが 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 用のインスタンスがひとつ暗に生成されていて、 それに対する同期になるのでしょうか。 | ||||||||
|
投稿日時: 2002-12-17 11:14
public synchronized static long sum() { コード } は、 public static long sum(){ synchronized(Hello.class){ コード } } と同じです。 public synchronized long sum(){ コード } が、 public long sum(){ synchronized(this){ コード } } と同じになるのと一緒です。 | ||||||||
|
投稿日時: 2002-12-18 09:09
unibon です。こんにちわ。
ありがとうございます。Hello.class でしたか。 今まではなんとなく、 new Hello() してできるインスタンスに近いものが static 用に別にできているのかと思っていました。 [ メッセージ編集済み 編集者: unibon 編集日時 2002-12-18 11:50 ] | ||||||||
|
投稿日時: 2002-12-18 11:34
ども,はじめまして。
raccoonです。よろしくお願いします。 本日デビューの新参者なのにイキナリ生意気なことを言うようですが, staticにすべきか否かについては,わたしは分析・設計時に自ずと決まるものだと考えています。 例えば「発泡酒」というクラスがあり,インスタンスが個々のカンを表すとします。 ここで「税率を上げる」というメソッドを作る場合,それはstaticになるでしょう。1本1本に対して税率を操作することはありえないからです。 逆に「飲む(=中身を消費する)」というメソッドがあるなら,それは非staticになるでしょう。抽象的な発泡酒というものを飲むことはできないからです。 実際には「税率」というstaticメンバと「残量」という非staticメンバを持つでしょうから,結果的にはみなさんの言うことと同じになると思いますが,考え方が違います。 メソッドは操作であり,操作の対象が「発泡酒」という一般名詞なのか,個々のカンなのかという点を明確にして,staticかどうかを自動的に決めるものでしょう。 「メンバがこうだから」とか「こう使いたいから」という,実装の観点から決めるべきものではないと考えています。 # あくまで「理論上は」の話であり,実際こうキレイに決まるものではないことは承知していますが・・・。 | ||||||||
|
投稿日時: 2002-12-18 19:44
unibon です。こんにちわ。
いろいろ static について考えてみたのですが、 static なものはフィールドとメソッドがありますが、 まず static なメソッドについては、 結局はアクセスのし易さのためにあるものであり、 インスタンスに依存しないようなコードの入れ場所、 という程度の意味合いしかないと思います。 (結局のところ、static メソッドはどうでもいい、というような感じです。) #static な class もあるそうですが、考えないことにします。 一方、static なフィールドは、 複数のインスタンスから共有される唯一のインスタンスとして使われ、 アクセスする際にそのフィールドのインスタンスを書かなくてよいなど、 簡便に使えて便利ですが、後述するような弊害のほうが大きいと思いますので、 static なフィールドは使わないほうがよいと考えます。 たとえば、発泡酒の例だと、 税率はたまたまひとつで良いのかもしれませんが、 揚げ足取りになるかもしれませんが、輸出することを考えると、 国によって税率が変わるなどで、 複数の税率を管理する必要が出てきます。 このように、現時点での分析・設計では、ひとつしかないから、 という理由で static なフィールドを使ってしまうと、 このように、ひとつを超えるものを扱う必要が出てきた場合に、 拡張性が乏しくなる可能性があります。 煩雑になるかもしれませんが、static のフィールドは一切使わずに、 それに代わるようなインスタンスをひとつ new して、 そのインスタンスを参照して使うほうが、 明示的に参照できるので良いと考えます。 ただ、こうすると、そのインスタンスを引数で渡したり、 中継するクラスのフィールドで参照させたりと、 コードが煩雑になってしまいますが、でも、将来の拡張には強いと考えます。 なお、将来のことは今考えなくてもそのときに対処すればよい (なまじ将来を見越すのは逆効果である)、 というのが最近の流行のようですが、 でも、コードの途中でいきなり static のフィールドにアクセスするのは、 グローバル変数の考えの延長のような気がして、納得できません。 ただ、定数のような位置付けのものは、 さすがに static なフィールドでも良いと考えます。 じゃあ、「定数」かそうでないかの違いはなにか、 と聞かれると悩んでしまいます。 雰囲気としては、 クラスの中で自発的に生じてきたような定数は、static なフィールドでも良いが、 外部から左右されるような可能性を持った定数(上記のような税率)は、ダメ、 というふうに感じます。 #自分で読み返してみると、なんだか、うまく説明になっていないですね。 #また、なぜかここでもフィールド重視になってしまっているような気がする(笑)。 | ||||||||
