クラス (コンピュータ)
出典: フリー百科事典『ウィキペディア(Wikipedia)』
クラス(class)は、オブジェクト指向においてオブジェクトの設計図にあたるもの。抽象データ型の一つ。クラスから生成したオブジェクトのことをインスタンスという。
クラスには、保持するデータ型(メンバ変数、フィールド(UMLでは「属性」ともいう))と操作(メンバー関数、メソッド)が記述される。アクセス範囲(public、private、protectedなど)や可変かどうか(final、 constantなど)等についても、記述されている。
クラスの特徴として、継承、ポリモーフィズム, カプセル化などがある。
[編集] 継承(inheritance、extension、generalization)
あるクラスを基にして別のクラスをつくることを「継承」という。 「継承」は拡張ともいうことがあり、UMLでは「汎化(generalization)」と呼んでいる。 継承の基になったクラスを親クラス・基本クラス・スーパークラス等といい、継承してできたクラスを子クラス・派生クラス・サブクラス等という。
複数のクラスを基にしてクラスを継承することを多重継承という。多重継承は、二つのクラスの同名メソッドのオーバーライドによるコンフリクトを始めとするいくつかの問題点が指摘されており、Java、C#、D言語等では実装多重継承サポートされておらず、 インタフェース多重継承のみサポートされている。
また、オブジェクト指向を効率よく使いこなすためには継承だけでなく集約(aggregation)、委譲(delegation)を 理解する必要がある。
[編集] ポリモーフィズム(polymorphism)
継承する際に、親クラスの関数を子クラスの関数で置き換えることをオーバーライドという。オーバーライドをうまく使うと、オブジェクトによって、実質的に実行される関数が変わるようにできる。このようにして、見かけが一緒なのに動作が違うようにできることをポリモーフィズム(ポリモルフィズム)・多様性・多態性などという。
[編集] カプセル化(encapsulation)
クラス内のフィールド、メソッドにアクセス権を指定することで、 外部から勝手にフィールドを変更できないようにすることができ、メソッドの使用を 特定のクラス、パッケージ内でしか使用できないようにすることでプログラムの堅牢性、拡張性、 移植性、汎用性、安全性、信頼性を高めることができる。
たとえば、Javaを例にとると、
以下のようなクラスがあったとき、
class NonEncapsulatedClass { public int x; public NonEncapsulatedClass(){ x = 100; } public int getX(){ return x; } }
このクラスを外部から利用するには
NonEncapsulatedClass nec = new NonEncapsulatedClass();
とすることでインスタンスを生成し、
System.out.println(nec.x);
とすることでNonEncapsulatedClass
クラスのpublic
なフィールドx
にアクセスできコンソールに実行結果として100
と表示することができる。 また、getX()
メソッドを使って
System.out.println(nec.getX());
とすることでもフィールドx
にアクセスし同じ実行結果を返すことができる。 また、 public
な変数なため当然、
nec.x = -20; System.out.println(nec.x);
とすることでフィールド値を100
から-20
に変えて表示することもできる。
このクラスはフィールド変数x
がpublic
になっているため簡単にx
にアクセスでき、 簡単にデータを変えることができてしまい、カプセル化されていない。
ここで上記のクラスを以下のように変更すると
public final class NonEncapsulatedClass { private int x; public NonEncapsulatedClass(){ x = 100; } public int getX(){ return x; } public void setX(int x) { try { if(x < 0){ throw new ArithmeticException("負の値は入力しないでください。"); } else if( x > 200){ throw new ArithmeticException("このクラスは200より大きな値はサポートしていません。"); } else { this.x = x; } } catch (ArithmeticException e){ e.printStackTrace(); } catch (Exception e){ e.printStackTrace(); } finally { System.out.println("The end."); } } }
このクラスを他のクラスから呼び出すとき
System.out.println(nec.x);
としただけでコンパイルエラーが発生する。フィールド変数x
はアクセス権がprivate
なので 同一クラス内からしかアクセスできない。それに違反しているためこの時点でコンパイルエラーとなる。
ここではgetX()
メソッドを使って間接的にしかフィールド変数にアクセスすることができない。
System.out.println(nec.getX());
このx
を以下のようにして変更しようとすると、
nec.x = -20;
この時点でもコンパイルエラーが発生する。 ここでフィールド変数x
を変更するには、フィールド変数はprivate
になっており、 クラスの修飾子にはfinalがついているため継承が禁止されておりサブクラスからフィールド変数にアクセスすることもできない。 ここではsetX(int x)
メソッドを使わなくてはx
にアクセスしてxの値を変更することはできない。 では、 ここでsetX(int x)
を以下のように実行したらどうなろうだろうか。
nec.setX(-20);
プログラムソースコードのコンパイルは通る。しかし実行時に ArithmeticException
例外が生じてプログラムが終了してしまうだろう。 なぜならそのようにプログラムされているからだ。 同様に
nec.setX(201);
としてもArithmeticException
例外が生じて終了してしまうだろう。 このようにフィールド変数xに代入できる数値範囲を計器やバルブの調節ツマミの安全弁のように限定したいとき、 安全のため、セキュリティのため、不用意にこの変数に特定の値を入れたくないときカプセル化は役立つのである。