- - PR -
interface のメソッドは、なぜ protected にできないのでしょうか?
投稿者 | 投稿内容 | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2003-07-10 11:39
unibon です。こんにちわ。
以下、わりと初歩的な質問だと思いますが、 interface のメソッドは、なぜ protected が指定できないのでしょうか。 たとえば java.awt.event.MouseListener は
となっていますが、これを implements したクラスをつぎのように作ったとします。 --- MouseTester.java ---
これをコンパイルすると、つぎのようなコンパイルエラーになります。 MouseTester.java:5: MouseTester の mouseClicked(java.awt.event.MouseEvent) は java.awt.event.MouseListener の mouseClicked(java.awt.event.MouseEvent) を実装できません。スーパークラスでの定義より弱いアクセス特権 (public) を割り当てようとしました。 かといって java.awt.event.MouseListener を
のようにすることもできません。 これは Java の言語の仕様なので、 たとえ MouseListener の作者であっても protected にできません。 私としては自分で作ったクラス MouseTester のメソッドは、 コールバックのメソッドなので、protected にしたいのです。 しかし interface の段階で protected が指定できないので、それが尾を引いてしまい、 その interface を implements した class のメソッドも protected にできません。 なぜなのでしょうか。 | ||||||||||||||||
|
投稿日時: 2003-07-10 11:57
今回の件に関して言えば protected にしてしまうと MouseListener に
イベントを通知する側が不便だからではないでしょうか? interface はあくまでも公開されるインターフェースのみを定義する、 というポリシーなのだと思います。 interface に対する不満としては 他にも interface に public static な メソッドを書けても良いじゃないか、とかいう話を聞いた事があります。 | ||||||||||||||||
|
投稿日時: 2003-07-10 12:12
interface の意義はメソッドの外部への、、なんと言うか、提供? なので、
public にしかなりえないと思います。 なので protected なメソッドを interface に定義する意味はないでしょう。 | ||||||||||||||||
|
投稿日時: 2003-07-10 12:58
protectedにしたらイベントの発生元からmouseClicked()が呼べない気がするのですが・・・。
| ||||||||||||||||
|
投稿日時: 2003-07-10 13:11
結局interfaceとは外部との関係だけを定義するもので
何らかの機能を持たせるのならば抽象クラスを使う。 という解釈でいいのでしょうか? | ||||||||||||||||
|
投稿日時: 2003-07-10 13:49
unibon です。こんにちわ。
みなさまありがとうございます。 すみません。例をあげる際に、 呼ばれるほうばかり考えていて、呼ぶほうを考えていませんでした。 新たに別の例を書きます。 まずつぎの 2 つのクラス ClassA と Class B から構成されるサンプルを考えます。 なお、protected のアクセス範囲を考慮してパッケージを故意に分けてますのでご注意ください。 --- packageA/ClassA.java ---
--- packageB/ClassB.java ---
これだと、クラス ClassA の内部のインターフェース InterfaceX のメソッド foo は、 protected にできてもよさそうですが、 でも protected にするとこのスレッドの最初に述べたように、 コンパイルエラーになってしまいます。 かといって protected にすれば、クラス ClassB のメソッド main の中から メソッド foo が呼べてしまいますが、これは避けたいです。 一方、これと対比するために、 つぎの 2 つのクラス ClassC と Class D から構成される別のサンプルを考えます。 ここでは interface ではなく abstract class を使っていますが、 これだと目論見どおりのことができます。 --- packageC/ClassC.java ---
--- packageD/ClassD.java ---
しかし、これだと interface ではないので、多重継承ができない Java では応用が効きません。 できれば interface でもこれと同じことがやりたいです。 | ||||||||||||||||
|
投稿日時: 2003-07-10 16:16
うーん、以下のようにするとClassDのmainメソッドからでも
ClassYのfooメソッドを呼ぶことができますよね。
そもそも、同じトップレベルクラスの中で宣言されたメソッドは、 たとえネストしたクラス内にあるものだとしても、 privateやprotectedなどのアクセス制限を無視して呼び出すことができる というのがJava言語の基本的なポリシーです。 # もちろんローカルクラスや匿名クラスの場合は # 宣言のスコープも影響してきますが… それよりもまず、実装クラスであるClassYの宣言を
のように変えるべきです。 このようにしても、相変わらずClassB, ClassDのmainメソッドから fooメソッドを呼び出すことはできてしまいますが、 ClassB以外のクラスから
などとすることはできなくなります。 カプセル化という観点からすると、こちらのほうがより重要だと思います。 | ||||||||||||||||
|
投稿日時: 2003-07-11 09:42
unibon です。こんにちわ。
ご指摘ありがとうございます。そしてすみません。これも私の例が悪かったと思います。 ご指摘のように呼べてしまえるのは、protected なメソッドに共通の仕様であり、 この例に限らずとも起こりうることだと思います。 (たとえば、 http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=3963&forum=12 のスレッドの私の2番目の投稿のような感じ。) これはこれで protected なメソッドはこのような場面で呼べるべきか呼べないべきか、 という議論はできるのかもしれませんが、 今回の私の最初の疑問ではそれよりも以前の段階であり、 メソッドを protected にできるかできないかを問題にしています。 #横道に逸れたくないというわけではありませんが。
ClassY を public にするか private にするかは、 ClassY を使う側の都合で決めれば、どちらでも良いと思います。 すなわち内部クラスである ClassY を囲んでいる、 (外側の) ClassB や ClassD の作りで決めることです。 以下、ご指摘されたことと重なる部分がありますが、確認のためにサンプルを追加しました。 たとえば、packageC/ClassC.java や packageD/ClassD.java は前回のまま一切変えずに(ClassY を public のままにして)、 つぎのような ClassE を追加してこの main メソッドを実行すると、 目論見どおりコンパイルエラーになります。 --- packageE/ClassE.java ---
|