ホームページ  >  記事  >  Java  >  Javaオブジェクト指向における継承例を詳しく解説

Javaオブジェクト指向における継承例を詳しく解説

黄舟
黄舟オリジナル
2017-09-06 10:12:301730ブラウズ

継承

概要

継承とは、既存のクラスから新しいクラスを派生させることで、新しいクラスは既存のクラスのデータ属性と動作を吸収し、新しい機能を拡張できます。継承は、しばしば is-a 関係と呼ばれます。サブクラスは親クラスの特性や動作を継承するため、親クラスのさまざまな属性やメソッドを持ちます。または、サブクラスは親クラスからメソッドを継承して、サブクラスが親クラスと同じ動作をするようにします。

例:
たとえば、最初に車というクラスを定義できます。車には次の属性があります: ボディ サイズ、色、ハンドル、タイヤ、および 2 つのクラス (車とトラック) は車のクラスから派生します。車のボックスに小さなバックアップを追加し、トラックに大きな貨物ボックスを追加します。

継承が表現するのはオブジェクト クラス間の交差関係であり、これにより、ある型のオブジェクトが別の型のオブジェクトのデータ メンバーとメンバー メソッドを継承できるようになります。クラス B がクラス A を継承する場合、B に属するオブジェクトはクラス A のプロパティ (データ属性) と関数 (操作) のすべてまたは一部を持ちます。継承されたクラス A を基本クラス、親クラス、またはスーパークラスと呼びます。継承クラス B は、A の派生クラスまたはサブクラスです。

親クラスとサブクラスを表す用語: 親クラスとサブクラス、スーパークラスとサブクラス、基底クラスと派生クラス、これらは同じ意味です。

継承が必要な理由

動物がペンギンとマウスである動物クラスを開発します。 要件は次のとおりです:
ペンギン: ​​属性 (名前、ID)、メソッド (食べる、寝る、自己紹介)
ラット: 属性(名前、ID) 、メソッド (食べる、寝る、自己紹介)
ペンギンとマウスはどちらも動物です。これでコードが非常に簡単になります。この属性を記述するために 2 つの別々のクラスを作成したいだけだと言う人もいますが、それはあなたの父親があなたに何百万ものお金をくれたのに、あなたはそのお金を捨てたのと同じです。自分で稼がなければならなかったのですから、そうしたいのなら仕方ありません。 Java には継承が備わっているため、これを有効に活用する必要があります。これにより、たとえば、保守性が向上し、コードがより簡潔になり、コードの再利用性も向上します。複数回使用できます。同じコードを複数回記述する必要はありません)。

機能:

1. 継承により重複コードを減らすことができます。たとえば、親クラスによってすでに提供されているメソッドは、実装することなくサブクラスによって直接使用できます。

2. ポリモーフィズムの前提条件は継承です。もちろん、継承を使用するとクラスの結合も改善されます。

親クラスの属性が不要な場合は、元の属性をオーバーライドできます。

Javaの継承分類

継承は単一継承と多重継承に分けられます。単一継承とは、サブクラスが最大 1 つの親クラスを持つことができることを意味します。多重継承とは、サブクラスが 3 つ以上の親クラスを持つことができることを意味します。多重継承はあいまいさをもたらす可能性があるため、実際のアプリケーションでは可能な限り単一継承を使用する必要があります。 Java 言語のクラスは単一継承のみをサポートしますが、インターフェースは多重継承をサポートします。 Java における多重継承の機能は、インターフェースを通じて間接的に実装されます。 継承の実装

継承は extends とimplements の 2 つのキーワードを使用して実現でき、すべてのクラスは java.lang.Object を継承します。クラスが 2 つのキーワードを継承しない場合、デフォルトで object を継承します。 java.lang パッケージなので、Ancestor クラスをインポートする必要はありません。

継承される初期化シーケンス:

親クラス —> 親クラスの初期化オブジェクトの属性 —> 親クラスのコンストラクター —> サブクラス —> サブクラスの初期化オブジェクトの属性 —> 子クラスの構築メソッド

構築メソッドがある場合:最初に属性を実行し、次に構築メソッドを実行します

構築メソッドで name 属性に値が割り当てられていない場合、name の値はクラス属性に割り当てられた値になります

extends キーワード

Java では、クラス継承は単一継承です。つまり、サブクラスは親クラスを 1 つだけ持つことができるため、extends は 1 つのクラスのみを継承できます。

/*动物类*/
public class Animal { 
    private String name;   
    private int id; 
    public Animal(String myName, String myid) { 
        //初始化属性值
    } 
    public void eat() {  //吃东西方法的具体实现  } 
    public void sleep() { //睡觉方法的具体实现  } 
} 
 
/*企鹅是动物,所以可以继承动物类*/
public class Penguin  extends  Animal{ 
//企鹅继承了动物类,所以拥有了动物类的属性和方法
}

implements キーワード

implements キーワードを使用すると、Java に多重継承の機能を偽装することができます。使用範囲はクラスがインターフェイスを継承する場合であり、複数のインターフェイスを同時に継承できます (カンマ区切りが使用されます)。インターフェイス間)。

public interface A {
    public void eat();
    public void sleep();
}
 
public interface B {
    public void show();
}
 
public class C implements A,B {
}

super とこのキーワード

super キーワード

: super キーワードを使用すると、現在のオブジェクトの親クラスを参照するために使用される親クラスのメンバーにアクセスできます。 注意:

1. superキーワードはコンストラクターまたはインスタンスメソッド内でのみ使用できますが、静的メソッドおよび静的コードブロック内では使用できません


2. 親クラスのメンバー変数とメソッドがプライベート型で定義されている場合、サブクラスは、親クラスのプライベート型 var 変数に super.var 形式でアクセスしようとすると、コンパイル エラーが発生します

このキーワード

: 自分自身を指す参照。このメソッドが現在呼び出されているオブジェクト参照。 注:

1. 複数のオーバーロードされたコンストラクターがあり、1 つのコンストラクターがそれを構築するために別のコンストラクターを呼び出す必要がある場合、この (param) 形式を使用して最初の行でのみ呼び出します。オブジェクト内のメソッドがオブジェクト内の他のメソッドを呼び出す必要がある場合、これをメイン チューンとして使用します。実際、デフォルトではこれをメイン チューンとして使用します。

  3.当对象属性和方法中的局部变量名称相同时,在该方法中需要显式的使用this作为主调,以表示对象的属性,若不存在此问题,可以不显式的写this。

  其实,其牵涉到的一个问题就是变量的查找规则先局部变量 => 当前类中定义的变量 => 其父类中定义的可以被子类继承的变量 => 父类...

这块要完全理解需要看上面我写的“继承的初始化顺序”从这里可以看到程序是如何初始化的。

/**
 * 父类
 * @author gacl
 *
 */
class FatherClass {
    public int value;
    public void f() {
        value=100;
        System.out.println("父类的value属性值="+value);
    }
}

/**
 * 子类ChildClass从父类FatherClass继承
 */
class ChildClass extends FatherClass {
    /**
     * 子类除了继承父类所具有的valu属性外,自己又另外声明了一个value属性,
     * 也就是说,此时的子类拥有两个value属性。
     */
    public int value;
    /**
     * 在子类ChildClass里面重写了从父类继承下来的f()方法里面的实现,即重写了f()方法的方法体。
     */
    public void f() {
        super.f();//使用super作为父类对象的引用对象来调用父类对象里面的f()方法
        value=200;//这个value是子类自己定义的那个valu,不是从父类继承下来的那个value
        System.out.println("子类的value属性值="+value);
        System.out.println(value);//打印出来的是子类自定义的那个value的值,这个值是200
        /**
         * 打印出来的是父类里面的value值,由于子类在重写从父类继承下来的f()方法时,
         * 第一句话“super.f();”是让父类对象的引用对象调用父类对象的f()方法,
         * 即相当于是这个父类对象自己调用f()方法去改变自己的value属性的值,由0变了100。
         * 所以这里打印出来的value值是100。
         */
        System.out.println(super.value);
    }
}

/**
 * 测试类
 */
public class TestInherit {
    public static void main(String[] args) {
        ChildClass cc = new ChildClass();
        cc.f();
    }
}

运行结果:
  父类的value属性值=100
  子类的value属性值=200
  200
  100

分析:
  执行   ChlidClass cc = new ChlidClass();

 首先在栈空间里面会产生一个变量cc,cc里面的值是什么这不好说,总而言之,通过这个值我们可以找到new出来的ChlidClass对象。由于子类ChlidClass是从父类FatherClass继承下来的,所以当我们new一个子类对象的时候,这个子类对象里面会包含有一个父类对象,而这个父类对象拥有他自身的属性value。这个value成员变量在FatherClass类里面声明的时候并没有对他进行初始化,所以系统默认给它初始化为0,成员变量(在类里面声明)在声明时可以不给它初始化,编译器会自动给这个成员变量初始化,但局部变量(在方法里面声明)在声明时一定要给它初始化,因为编译器不会自动给局部变量初始化,任何变量在使用之前必须对它进行初始化。

  子类在继承父类value属性的同时,自己也单独定义了一个value属性,所以当我们new出一个子类对象的时候,这个对象会有两个value属性,一个是从父类继承下来的value,另一个是自己的value。在子类里定义的成员变量value在声明时也没有给它初始化,所以编译器默认给它初始化为0。即(父类的value为0,子类的value为0;

  执行第二句话:   cc.f();

 当new一个对象出来的时候,这个对象会产生一个this的引用,这个this引用指向对象自身。如果new出来的对象是一个子类对象的话,那么这个子类对象里面还会有一个super引用,这个super指向当前对象里面的父对象。所以相当于程序里面有一个this,this指向对象自己,还有一个super,super指向当前对象里面的父对象。

  这里调用重写之后的f()方法,方法体内的第一句话:“super.f();”是让这个子类对象里面的父对象自己调用自己的f()方法去改变自己value属性的值,父对象通过指向他的引用super来调用自己的f()方法,所以执行完这一句以后,父对象里面的value的值变成了100。接着执行“value=200;”这里的vaule是子类对象自己声明的value,不是从父类继承下来的那个value。所以这句话执行完毕后,子类对象自己本身的value值变成了200。

以上がJavaオブジェクト指向における継承例を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。