非静的public finalフィールドの是非

このQ&Aのポイント
  • c#では非静的なpublic finalフィールドがタブーとされているが、Javaでは存在する。
  • 非静的なフィールドを公開することに疑問がある点は、セキュリティや保守性、統一性、インターフェイスとの関係などが挙げられる。
  • セキュリティや保守性の問題があるかどうか、仕様変更時の影響などを考慮して非静的なpublic finalフィールドを利用するかどうか判断する必要がある。
回答を見る
  • ベストアンサー

非静的 public final フィールドの是非

 こんにちは。c# & Java初心者です。  (長文になるのでその心積もりを)  数ヶ月前まではc#一本だったのですが、そろそろ多言語に触れるには頃合かと思い、Javaを始めました。  c#ではほとんどタブーとされる非静的protectedまたはpublicフィールドですが、Javaの配列では、public final int lengthの形で存在します(実にカルチャーショックでした)。  c#はやたらややこしいのがあるらしく、たとえreadonly(final)でも非静的なら、特殊なクラスか何かを使えば書き換え可能らしいので、readonly(final)でもpublicまたはprotectedにしてはいけないのがルールらしいです(少なくともライブラリ設計では)。  また、「コードアクセスセキュリティ要求によって保護されない」とかいうさらに面倒な理由もあるとか。  ともかく、Javaにはそういうのがないのか、平然と非静的public final フィールドが存在します。  静的にしろ、非静的にしろ、finalでないフィールドを公開するのは、Javaでも、どう考えてもご法度なのは、分かります。  静的なら、finalにしておけば定数とほぼ同じ扱いができるのもc#と変わらないので(c#にはconstがありますが)、これも分かります。  しかし、finalにすれば非静的でもpublicまたはprotectedにしてもよいのかということには疑問符です。  気になる点は4つ。  1つは、本当にセキュリティーの問題がないかどうか。つまり、書き換えられたりする恐れがないかどうか。  2つは、保守性の問題。つまり、後から変更があった際に、メソッドならその内容を変えて、そのクラスだけをコンパイルすればよいが、フィールドなら関連する全てのクラスを直し、再コンパイルする必要があること。  例えば、年齢をフィールドに持つ仕様から、生年月日を記録し、そこから年齢を取得するプロパティ(メソッド)を使う仕様に変わった場合など。  3つは、統一性の問題。Javaにある配列のlengthフィールドと、Stringクラスのlength()メソッドの使い方の揺れを代表するように、「こちらはフィールドなのに、こちらはメソッド」のような気持ちの悪い作りのために、使用者が困惑したり、不便さを感じたりしないか(特にはじめたての初心者、それも対したIDEやエディター使っていない人々に悪影響を及ぼさないか。えっ!? オ、オレじゃねぇ! オレはやってない!)。  最後はインターフェイスとの関係。これは2つめの保守性にもかかわる部分ですが、クラスが完成しかけた状態または、完成した後にインターフェイスを実装して使用するような仕様変更があった場合、例えば、sizeフィールドを持つクラスに、size()メソッドを持つインターフェイスを実装することになった場合です。  その場合、Javaにはc#でいうところの明示的実装がないらしく、暗黙的実装しかないようなので、sizeフィールドと、size()メソッドの両方を残すという気持ちの悪い形になるか、sizeフィールドをなくし(または隠蔽)、外部の呼び出しを全てsize()メソッドに書き換えていくか、という2択になります。   class Sample   {     public final int size;     //それ以外は省略   }  があって、   interface SampleInterface   {     public int size();     //それ以外は省略   }  を実装しなければいけなくなった場合、   class Sample implements SampleInterface   {     public final int size;     public int size() { return size; }     //それ以外は省略   }  または   class Sample implements SampleInterface   {     private final int size;     public int size() { return size; }     //それ以外は省略   }  ちなみにc#であればこんな感じ(飽くまでイメージ)   class Sample implements SampleInterface   {     public final int size; // publicのまま     int SampleInterface.size() { return size; } // 明示的実装     //それ以外は省略   }  以上が悩みの原因です。1は何となく大丈夫だと思います。配列がそうなので。  2と最後は、「もう絶対に仕様変更しない! これが完成形だ」というのであれば良いのでしょう。配列やInteger、色のように値のようなクラスなら仕様変更もそれ以外と比べて少ないでしょう。 そういうものなら良いのかもしれません。・・・・・・たぶん。  というのが、c#初心者上がりのJava初心者の見解です。  どなたか分かる方、いらっしゃいましたらご意見、アドバイスを頂きたいです。

  • Java
  • 回答数2
  • ありがとう数2

質問者が選んだベストアンサー

  • ベストアンサー
  • racene
  • ベストアンサー率70% (21/30)
回答No.1

いまいち何を聞きたいのかわかりませんが・・・ 1. については大丈夫です。 final 変数が書き換えられないことはコンパイラが保証しています。 さすがに実行時にクラスファイルを書き換えられた場合とかは知りませんが、普通そんなことは有り得ないので大丈夫でしょう。 2. と 3. と 4. はほぼ同じことを言っていると思うのですが、 あなたの言っているとおり public final フィールドは仕様変更しないような場所で利用するのが望ましいでしょう。 これは Java 言語の残念な点ですね。 この辺については Scala などの新しい JVM 言語では上手く対応している(Scalaでは引数なしのメソッド呼び出しは括弧を省略できる & フィールドアクセスは同名のメソッド呼び出し)ので、興味があったら使ってみると良いと思います。

koumei000
質問者

お礼

まとまりが悪くてすみません。また整理してから質問しようと思います。回答ありがとうございました。

その他の回答 (1)

  • teketon
  • ベストアンサー率65% (141/215)
回答No.2

質問が長なくて、要点を得ません。整理をお願いします。 パっと見た限り、既存の疑問に収まる範囲だと思います。 古典ではありますが、「Java 謎+落とし穴 徹底解明」と言う本は、 「なんかおかしくないか?」という事がよくまとめられていたと記憶しています。 他の言語を触れる目的ならば、Javaはよく似か寄り過ぎなので、 もっと異なるものをターゲットにしたほうが良いです。

koumei000
質問者

お礼

まとまりが悪くてすみません。また整理してから、もう一度質問してみようと思います。回答ありがとうございました。

関連するQ&A

  • 継承・実装の関係で悩んでいます。

    継承・実装の関係について悩んでいます。 ここでは、アクセス制御を考えずに、インスタンスかstaticかabstract(ここではabstract final staticやabstract classのこと)の違いで、どう継承するのか考えています。 // 継承 はメソッドのオーバーライドのことを考えます。(オーバーロードは考えない) クラスAからクラスBでオーバーライドしたメソッドは、 クラスCでさらにオーバーライドできるのでしょうか? クラスCが クラスBのクラスAからオーバーライドしたメソッド をクラスBのメソッドとして見たときに、オーバーライドすることは可能なのでしょうか? クラスA │ インスタンスフィールドA │ staticフィールドA │ │ クラスA() { } │ │ インスタンスメソッドA () { } │ staticメソッドB() { } ↓ クラスB extends クラスA │ インスタンスフィールドA // 継承 │ インスタンスフィールドB │ staticフィールドB │ │ サブクラス1() { } // コンストラクタは継承しない、super()で呼び出す │ │ インスタンスメソッドA () { } // 継承 │ │ インスタンスメソッドB () { } │ staticメソッドB () { } ↓ クラスC extends クラスB implements インタフェースD, ... ↑ インスタンスフィールドA // クラスBのフィールドを継承 │ インスタンスフィールドB // クラスBのフィールドを継承 │ インスタンスフィールドC │ staticフィールドC │ │ サブクラス2() { } │ │ インスタンスメソッドA () { } // クラスBのメソッドを継承 │ インスタンスメソッドB () { } // クラスBのメソッドを継承 │ インスタンスメソッドD () { } // インタフェースDのメソッドを実装 │ インスタンスメソッドE () { } // インタフェースDのメソッドを実装 │ │ │ インスタンスメソッドC () { } │ staticメソッドC() { } │ interface インタフェースD extends インタフェースE ↑ │ staticフィールドD // public static final │ │ インスタンスメソッドD() { } // public abstract │ インスタンスメソッドE() { } // 継承 │ interface インタフェースE staticフィールドE // public static final インスタンスメソッドE() { } // public abstract

    • ベストアンサー
    • Java
  • Javaのプログラムについての質問です。

    Listインターフェースの実装クラスの自作と、作成したクラスの全メソッドを呼び出すサンプルを作成せよ、という問題です。 注意点として、java.util.Listの実装クラスは使用出来ません(ArrayListなど)。 以下は極最初期のソースになります。 import java.util.List;  public interface Interface{   int size();   boolean add();   boolean remove();   void clear();   get();   set();  } public class LocalList implements Interface{ class Main implements LocalList {  public static void main(String[] args) {     } } Listインターフェースについてネットで調べてはいるのですが、具体的な解決方法が見えてきません。 どなたか参考ソースや考え方などを教えていただけないでしょうか。よろしくお願い致します。

  • 継承、実装についてまとめています。この図は正しいですか?

    継承、実装についてまとめています。この図は正しいですか? クラス1 から継承した クラス2のものを、クラス3で継承するのでしょうか? クラス1 │ int a; │ static int b; │ │ クラス1() { } │ │ int methodA () { } │ static int methodB() { } ↓ サブクラス1 extends クラス1 │ int a; // 継承 │ int c; │ static int d; │ │ サブクラス1() { } // コンストラクタは継承しない、super()で呼び出す │ │ int methodA () { } // 継承 │ int methodC() { } │ static int methodD() { } ↓ サブクラス2 extends サブクラス1 implements サブインタフェース1, サブインタフェース2… ↑ int a; // サブクラス1のフィールドを継承 │ int c; // 継承 │ int e; │ static int f; │ public static final int g; // 実装(サブインタフェース1) │ public static final int h; // 実装 │ │ サブクラス2() { } │ │ int methodA () { } // サブクラス1のメソッドを継承 │ int methodC() { } // 継承 │ int methodE() { } │ static int methodF() { } │ int methodG() { } // 実装(サブインタフェース1) │ int methodH() { } // 実装 │ interface サブインタフェース1 extends スーパインタフェース1... ↑ public static final int h; │ │ public abstract int methodE() { } // 継承 │ public abstract int methodH() { } │ interface スーパーインタフェース public static final int g; public abstract int methodG() { }

    • ベストアンサー
    • Java
  • 「インタフェースを実装してそれが持つ抽象メソッドをオーバーライドする」

    「インタフェースを実装してそれが持つ抽象メソッドをオーバーライドする」は正しい? はじめまして。Javaのインタフェースに関する質問です。 私はこれまで、インタフェースを使うときは、インタフェースを実装してクラスを宣言し、そのクラス、またはサブクラスでインタフェースがもつすべての抽象メソッドを定義する、と理解していました。 しかし、下の例をみてください。抽象メソッドの定義を、インタフェースの実装の以前で与えています。問題無くコンパイルでき、実行できます。実行結果も以下の通りです。 インタフェースの抽象メソッドへの定義の与え方やその実行のされ方は、メソッドのオーバーライドと同様と思っていましたので、下記のコードでは「クラスBが抽象クラスではありません」や、「インタフェースの抽象メソッドがオーバーライドされていません」などの文法エラーがでると思っていました。 そこで、質問です。 インタフェースが持つ抽象メソッドの定義を与える場所について、または、これに関する説明のあるページなど、何かご存知でしたら教えてください。 ★コード★ interface X{   void show(); } class A{   public void show(){     System.out.println("A");   } } class B extends A implements X{ } public class Main{   public static void main(String[] args){     X x=new B();     x.show();   } } ★実行結果★ >java Main A ★Java環境★ java 1.6.0_21 javac 1.6.0_16

    • ベストアンサー
    • Java
  • singletonによるインターフェイスの実装

    Java勉強中の初心者です。 標題の件についてお願いします。 以下、簡単に条件を説明させていただきます。 Aクラス = メインクラス Bクラス = インターフェイスクラス Cクラス = DとEを動的に生成するクラス Dクラス = インターフェイスを実装するクラス Eクラス = インターフェイスを実装するクラス AクラスにB.getInstance(name)があります。 for文の無限ループがあります。 Cクラス class C { public static B getInstance(String name) { // Aクラスのaと変数nameが比較して一致したら // Dクラスのインスタンス生成 // 一致しなかったらEクラスのインスタンス生成 if(A.a.equals(name)){ return D.getInstance(); }else{ return E.getInstance(); } } } Dクラス class D implements B{ private D() { } public static D getInstance() { D d = new D(); return d; } // インターフェイスでのメソッド省略します。 } Eクラス class E implements B{ private E() { } public static E getInstance() { E e = new E(); return e; } // インターフェイスでのメソッド省略します。 } この条件の時にnewするたびにインスタンスが 生成されてしまいます。 インスタンスの生成が一度だけしか 生成されないようにするには、C,D,Eクラスで どのように記述すればいいか悩んでいます。 (骨組みは書けましたが) クラスを簡単に省略してわかりづらいと 思いますがよろしくお願いします。

    • ベストアンサー
    • Java
  • sjcpの試験勉強--インナークラスの疑問

    JAVAのsjcp(310-035)の試験勉強をしています。 インナークラスの問題で、 public class A{ public void MethodA(final int a){ int b = 1; class Inner{ private void innerMethod(int c){ -----ここ------- } } } } という例題があり、質問は -----ここ-------(6行目) で参照できる変数は?というものです。 答えはfinal がついてる変数aと、自身のメソッドの引数cです。 finalがついてないメソッド内の変数bにはアクセスできません。 解説を読んで、 cは分かるんですが、 どうしてfinalがついてないとアクセスできないのでしょうか。 暗記として覚えてもいいのですが、理由が分かられる方、アドバイス宜しくお願いします。

    • ベストアンサー
    • Java
  • 【C++】継承しながら、インプリメント。

    VB.netでは、以下のように継承しつつ実装ができると思いますが、 (1)C++ では、できないのでしょうか? (2)Java では、できないのでしょうか? Class SampleClass Inherits BaseClassHoge Implements InterfaceFoo また、 Implements は、Javaでは可能ではありますが、 C++ には「Implements」はないのでしょうか? (C++ では純粋仮想関数の集合となるアブストラクトクラスを継承するという方法しかできないのでしょうか?) .

  • Strategyパターンを用いた実装について

    Strategyパターンを用いた実装について 現在Javaを勉強しており、 Strategyパターンを用いた以下の実装を考えています。 public class UseStrategy { private Strategy strategy; public void doSomthing(int num) { switch (num) { case 0: strategy = new AlphaStrategy(); break; case 1: strategy = new BetaStrategy(); break; case 2: strategy = new GammaStrategy(); break; } // 変数strategyを用いて処理を続行していく // ... } private interface Strategy { public abstract void method_1(); public abstract void method_2(); } private class AlphaStrategy implements Strategy { @Override public void method_1() { //do something } @Override public void method_2() { //do something } } private class BetaStrategy implements Strategy { @Override public void method_1() { //do something } @Override public void method_2() { //do something } } private class GammaStrategy implements Strategy { @Override public void method_1() { //do something } @Override public void method_2() { //do something } } } つきましては、以下ご質問させてください。 (1)Strategyパターンの実装において、  上記UseStrayegyクラスのように、あるクラスの入れ子クラスとして  Strategyインターフェース及び、その実装クラスを実装する方法は  普通でしょうか?    それとも、入れ子クラスとしてではなく、Strategyインターフェース、  その実装クラスを全て 別クラスファイルに分けた方が良いのでしょうか? (2)例として、  BetaStrategy.method_2()とGammaStrategy.method_2()の処理が全く  同じだったとします。その場合、共通となる処理を一つのメソッド化し、  そのメソッドをBetaStrategy.method_2()とGammaStrategy.method_2()から  コールしたいと考えております。  その際、共通となる処理メソッドの実装箇所としては、以下のいずれが良いのでしょうか。   (A)Strategyインターフェースを抽象クラス化し、二つの共通処理メソッドを実装する。  (B)UseStrategyクラスに、共通処理を実装する。    それとも、上記の様なケースがある場合Strategyパターンは不適切でしょうか。 文面に分かりづらい面や、Javaのオブジェクト指向・デザインパターンについて 理解の乏しいところがあるかと思いますが、ご回答の程よろしくお願いいたします。

    • ベストアンサー
    • Java
  • 継承したメソッドのドキュメンテーションコメント

    C#の開発を始めて日が浅いため、現場におけるお作法がわかりません。 現場におけるクラス・インターフェースを継承したメソッドのドキュメンテーションコメントの付け方に関する一般論についてお教えいただきたいです。 ※基底クラス、及びインターフェースの抽象メソッドにはドキュメンテーションコメントの記述がある物とします。 ※普段はJavaを使っている為、そこから引用している書いている部分があります。ご容赦下さい。 ・抽象クラスにおけるインターフェースから継承した抽象メソッド(実装しない場合) Javaとは違い、抽象クラスであってもインターフェースが持つの抽象メソッドを無視する事はできず、 public abstract修飾子を付けて抽象メソッドを定義してやる必要があるようなのですが、 この場合、ドキュメンテーションコメントは省略すべきでしょうか? それとも、何かしら記述するべきなのでしょうか?(Javaで言うところの@inheritDoc等・・・そのような物があるかはわかりませんが) ・新たに実装を行う場合(抽象メソッドの実装等) 省略すべきでしょうか? ・既存の実装を拡張し、変更の影響は微小かつメソッド内のみで完結し、概要やその他のメソッドの責任において表記すべき内容に変化が無い場合 省略すべきでしょうか? ・既存の実装を拡張し、想定される例外の追加等、メソッド外にも影響を及ぼす大きな変更が入った場合 新たに完全なドキュメンテーションコメントを作成するべきでしょうか? それとも差分以外は新たに作成すべきではないのでしょうか? 一般論と言っても規模や進め方によって様々だとは思いますが、 通念的に「心がけていくべき事」等あれば、是非お教え下さい。 最後に、この質問の趣旨からは外れるのですが、一つ追加で別の質問をさせてください。 私は何故抽象クラスがインターフェースの抽象メソッドを無視できないかがわかっておりません。 (インターフェース-インターフェース、抽象クラス-抽象クラスは無視できるのに) 敢えて明示的に定義を強要させている以上、何か理由あっての事だと思いますが、 それがわからず悶々村々としながら作業しております。 その理由をお教えいただけませんでしょうか。 宜しくお願い致します。

  • アブストラクトとインターフェースの簡単な一例文

    JAVAについて質問よろしくお願いします。 abstract抽象クラスとインターフェースについて下記理解なのですが、超かんたんな一例など欲しいのですが何かないでしょうか。たとえば package round1.chapter1; public class Helloworld { public static void main(String[] args) { System.out.println("こんにちは!"); } } というような一文です。 ~私の理解~ アブストラクトとは、違ったクラス内で同一メソッドがある場合は親クラスに置き、違ったメソッドがある場合は抽象クラスとして親クラスに置いて、実装はサブクラスに任せるという形式で使われる言葉 インターフェースとは、機能だけを仕様書として書いておき、定義されたとおりのメソッドを実装しないといけないという呼び出し方の統一を図る際に使われるメソッド置き場 ~~~~~ このふたつについてものすごく簡単な使用例を頂きたいです。 よろしくお願いいたします。

    • ベストアンサー
    • Java

専門家に質問してみよう