JAvaの継承メカニズム

7351 ワード

継承の基本概念
日常生活の中で、私達はいつも“1種の(IS-A)”の関係を使って知識を組織して表現して、それによって知識を組織して1種の階層があって、分類することができる体系の構造になります.例えば、アヒルの梨は1種の梨で、梨は1種の果物です;大きい葉のガジュマルは1種の木で、木は1種の植物ですなど、数え切れないほどあります.
オブジェクト指向プログラムでは、クラスとクラスの関係をIS-A関係で記述し、継承(inheritance)と呼ばれます.継承とは、子オブジェクト(インスタンス)が親のインスタンスドメインとメソッドを持つように、子オブジェクト(インスタンス)が親のインスタンスドメインとメソッドを持つように、子オブジェクトが親からメソッドを継承することであり、子が親と同じ動作を持つようにすることです.継承はjavaプログラム設計の核心技術です.
新しいクラスAを作成する必要がある場合がありますが、既存のクラスBが持つ機能と、クラスBにない機能があります.では,クラスAとクラスBにはIS−A関係,「A IS−A B」があると考えられる.Aを木にたとえ、Bを植物にたとえると、木には植物の特性があり、花や草など他の植物を区別するために木特有の特性もある.
クラスAを作成するときは、クラスBのコードをコピーして、その上にコードを追加することができます.しかし、この方法は私たちに面倒を感じさせます.オブジェクト向けの継承メカニズムを使用してこの新しいクラスを構築することもできます.固有の特徴を追加するだけでいいです.継承メカニズムを使用すると、毎回新しいクラスを最初から定義する必要はありません.この新しいクラスを1つまたは複数の既存のクラスとして拡張または特殊化します.
以上のクラスAとクラスBの例では、クラスAはクラスBを継承する、クラスBはクラスAの親(parent)、スーパークラス(super-class)、またはベースクラス(base)と呼ばれ、クラスAはクラスBの子(child)または派生クラス(derived-class)と呼ばれます.クラスの祖先クラス(ancestor)は、その親とその親の祖先クラス、クラスの子孫クラスを含みます.(descendant)は、そのサブクラスとそのサブクラスの子孫クラスを含む.クラスAはクラスBを継承してクラスAを派生したともいえる.
継承の役割
継承メカニズムは主に二重の役割を果たす:一つはクラスとしての構造メカニズムであり、二つはタイプとしての構造メカニズムである.
クラスの構造メカニズムとして,既存のクラスを拡張・組合せて新しいクラスを構築する.拡張とは、既存のクラスを形成する特例である派生クラスを指し、組合せとは、いくつかの既存のクラスの共通性を抽出して新しい抽象階層であるベースクラスを形成することを指す.
タイプの構造メカニズムとして、子が親を継承する場合、すべてのオブジェクトが親タイプであることを要求する場所でも、子タイプのオブジェクトを受け入れることができます.つまり、親オブジェクトが現れる場所を子オブジェクトに置き換えることができます.
クラスの構造メカニズムとして、継承はオブジェクト向けプログラム設計言語においてソフトウェア再利用をサポートする重要な方法であり、タイプ構造メカニズムとして、継承は動的多態性を実現する基礎である.
継承された構文
JAvaでは継承関係を保持字extendsで表す.継承された構文の形式は次のとおりです.
public class    extends   {
    //            
    //            
}

次にjavaの継承メカニズムを例に挙げて説明します.従業員とマネージャの関係を例に挙げます.
コードリスト1:Employee.java
import java.util.Date;
import java.util.GregorianCalendar;
/**
 *    
 * @version v1.0 2018-03-13
* @adthor    
*/
public class Employee {
    private String name;
    private double salary;
    private Date hireDay;

/**
 *     
 * @param n     
 * @param s     
 * @param year     
 * @param month     
 * @param day    
 */
    public Employee(String n,double s,int year,int month,int day){
        this.name=n;
        this.salary=s;
        GregorianCalendar calendar=new GregorianCalendar(year,month-1,day);
        this.hireDay=calendar.getTime();
    }

    public String getName(){
        return this.name;
    }

    public double getSalary(){
        return this.salary;
    }

    public Date getHireDay(){
        return this.hireDay;
    }

    public void raiseSalary(double byPercent){
        double raise=salary*byPercent/100;
        salary+=raise;
    }
}

コードリスト2:Manager.java
/**
 *    ,      Employee,      。
 * @version v1.0 2018-03-13
 * @author    
 */
public class Manager extends Employee{
    private double bonus;
    /**
     *     
     * @param n     
     * @param s     
     * @param year     
     * @param month     
     * @param day    
     */
    public Manager(String name,double s,int year,int month,int day){
        super(name, s, year, month, day);
        this.bonus=0;
    }
    //     =    +  
    public double getSalary(){
        double baseSalary=super.getSalary();
        return baseSalary+bonus;
    }
    //  
    public void setBonus(double b){
        bonus=b;
    }
}

コードリスト3:ManagerTest.java
public class ManagerTest {
    public static void main(String[] args){
        Manager boss=new Manager("Carl Cracker",80000,1987,12,15);
        boss.setBonus(5000);

        Employee[] staff=new Employee[3];

        staff[0]=boss;
        staff[1]=new Employee("Harry Hacker",50000,1989,10,1);
        staff[2]=new Employee("Tommy Tester",40000,1990,3,15);

        for(Employee e:staff)
            System.out.println("name:"+e.getName()+",salary="+e.getSalary());
    }
}

実行結果:
name:Carl Cracker,salary=85000.0 name:Harry Hacker,salary=50000.0 name:Tommy Tester,salary=40000.0
以上のプログラムでは、Employeeタイプのオブジェクトstaff[0]でManagerタイプのオブジェクトを参照しましたが、プログラムは正常に動作しており、プログラム内のスーパークラスが発生した場所でもサブクラスで置換できることを示しています.この例では、staff[0]はbossと同じオブジェクトを参照しますが、コンパイラは、staff[0]がEmployeeタイプのオブジェクトであり、bossはManagerタイプの対像であるため、staff[0]はマネージャクラスのメソッドを使用できません.staff[0].setbounds(5000);が誤った使い方である場合、コンパイラはエラーを報告します.
メンバー・アクセス制御の継承
継承メカニズムは、保護されたメンバーを導入し、公開(public)とプライベート(private)の間で理解できる新しいメンバーアクセス制御レベルを提供します.
継承では、サブクラスは構造関数以外のすべてのメンバーを継承し、これらのメンバーはサブクラスの継承メンバーとなります.継承メンバーには、スーパークラスで定義された共有、保護、およびプライベートメンバーだけでなく、スーパークラスの継承メンバーも含まれます.
サブクラスでは、サブクラスは自分で定義したすべてのメンバーにアクセスしたり、親スーパークラスの共有および保護された継承メンバーにアクセスしたりできますが、スーパークラスのプライベート継承メンバーにはアクセスできません.
継承メンバーのサブクラスでのアクセス制御は、スーパークラスでのアクセス制御と同じです.および元はスーパークラスで共有メンバーであり、布団クラスが継承された後に共有メンバーとみなされる.元々スーパークラスでは保護されたメンバーであり、布団クラスが継承された後も保護されたメンバーである.もともとスーパークラスではプライベートなメンバーであり,布団クラスが継承された後はプライベートなメンバーと考えられていたが,サブクラスはアクセスできなかった.データ型が子であるオブジェクトは、子とその親の保護されたメンバーにアクセスできません.
再定義
サブクラスがスーパークラスのメソッドを使用し、スーパークラスのこのメソッドがサブクラスに適していない場合は、サブクラスでこのメソッドを再定義することができます.サブクラスがスーパークラスを再定義する方法とは、サブクラスにスーパークラスのメソッドと完全に同じインタフェースを持つメソッドを定義する方法であり、サブクラスと呼ばれるこのメソッドがスーパークラスとインタフェースを再定義する方法である.メソッドインタフェースが完全に同じとは、戻りタイプ、メソッド名、およびメソッドパラメータのリストが完全に同じであることを意味します.以上の例では、ManagerクラスのgetSalary()メソッドは、スーパークラスEmployeeを再定義したgetSalary()メソッドである.
スーパークラスの再定義(先祖クラス)のメソッドの場合、メソッドのアクセス制御権限を下げることは許されません.スーパークラスでpublicのメソッドの場合、サブクラス再定義時にprotectedまたはprivateとして定義することはできません.ただしjavaは、サブクラスでメンバーデータを再定義することは、そのアクセス制御権限を下げることです.スーパークラスでpublicのデータメンバーの場合、サブクラスでprotectedまたはprivateのデータを再定義することはできますスタッフ.
メンバー・データでは、子クラスが祖先クラスと同じ名前のメンバー・データを定義している限り、祖先クラスのメンバー・データを再定義し、祖先クラスのメンバー・データをブロックしている限り、子クラスおよび子クラスの使用者はその祖先クラスのメンバー・データにアクセスできません.
thisとsuper
JAvaのthisとsuperは、各オブジェクトインスタンスの特殊なプライベートメンバーであり、参照変数であり、thisのタイプはオブジェクトインスタンスが属するクラスタイプであり、superのタイプはその属するオブジェクトインスタンスのスーパークラスタイプである.
2つの方法があります.
1つ目:クラスのデータまたはメソッドメンバーを呼び出します.thisは自分自身を呼び出すメンバーであり、superはそのスーパークラス(祖先クラス)を呼び出すデータメンバーである.上記の例のEmployeeクラスのように、そのコードの一部は以下の通りである.
    public class Employee {
        private String name;
        ......
        public Employee(String name,double s,int year,int month,int day){
            this.name=name;
            .........
        }
        .......
    }

コンストラクション関数では、パラメータリストの名前ではなく、名前が存在するクラス(Employee)で定義された名前であることを示すthis.name=name;が使用されます.この使用方法のフォーマットは、this. およびsuper. にまとめられています.スーパークラスメンバーはプライベートメンバーではありません.
2つ目は、コンストラクション関数を呼び出すことです.thisは、自身のコンストラクション関数で自身を呼び出す別のコンストラクション関数であり、superは、自身のコンストラクション関数でそのスーパークラスを呼び出すコンストラクション関数である.たとえば、Managerクラスのコンストラクション関数:
    public Manager(String name,double s,int year,int month,int day){
        super(name, s, year, month, day);//       
        this.bonus=0;
    }

このうちsuper(name, s, year, month, day);は、ManagerのコンストラクタがスーパークラスEmployeeのコンストラクタを呼び出し、継承メンバーname、salary、hireDayを初期化したものです.この使用方法のフォーマットは、this( );およびsuper( );にまとめられる.構造方法の最初の文に置かなければならないことに注意してください.
まとめ
サブクラスには、親クラスのprivate以外の属性、メソッドがあります.
サブクラスは、親を拡張できる独自の属性とメソッドを持つことができます.
子クラスは、親クラスを独自の方法で実装できます(再定義).JAvaの継承は単一の継承ですが、多重の継承が可能で、単一の継承は1つのサブクラスで1つの親しか継承できません.多重の継承は、例えばAクラスがBクラスを継承し、BクラスがCクラスを継承するので、関係によってCクラスがBクラスの親で、BクラスがAクラスの親で、これはjava継承がC++継承とは異なる特性です.しかし、インタフェースはマルチ継承を許可します.
クラス間の結合性が向上しました(継承の欠点、結合度が高いとコード間のつながりが発生します).