Java继承(extends)理解

1、在面向对象语言中,经常被提起的两个词就是类和对象,实质上我们可以将类看作对象的载体,它定义了对象所具有的功能。

2、面向对象程序设计:程序=对象+消息。1、程序一般是由类的定义和类的使用两部分组成。2、程序中的一切操作都是通过对象发送消息来实现的,对象接收到消息后,启动有关方法完成相应的操作。一个程序中涉及的类可以有设计者自己定义,也可以使用现成的类(包括类库中为用户提供的类和他人已构建好的类),尽量使用现成的类,是面向对象程序设计所倡导的。

3、现实世界:物质+意识

面向对象世界:具体事物+抽象的信息

4、面向对象程序设计的基本特征:1、抽象  2、封装  3、继承  4、多态

在现实世界中封装就是把某个事物包围起来,是外界不知道该事物的具体内容。在面向对象程序设计中,封装是把数据和方法(实现相关操作的代码)集中起来放在对象的内部,并尽可能隐蔽对象的细节。对象好像是一个不透明的黑盒子,表示对象属性的数据和实现各个操作的代码都被封装在黑盒子里,从外界是看不见的,更不能从外界直接访问或修改这些数据及代码。使用一个对象的时候,只需知道它向外界提供的接口,而无需知道他的数据结构细节和实现操作的算法。

在面向对象语言中,对象的函数名就是对象的对外接口,外界可以通过函数名来调用这些函数实现某些行为(功能)。封装的两层含义:1、将有关的数据和代码封装在一个对象中,各个对象相互独立、互不干扰。2、将对象中某些数据和操作代码对外隐蔽,即隐蔽其内部细节,只留下少量接口以便于外界联系,接受外界的消息。

5、继承是面向对象最显著的一个特性。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。继承出现的原因是为了避免代码重复。

在Java之中,如果要实现继承的关系,可以使用如下的语法:

class 子类 extends 父类 {}

子类又被称为派生类; 父类又被称为超类(Super Class)

package com.wz.extendsdemo;

class Person {
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

    public int getAge() {
        return this.age;
    }
}

class Student extends Person { // Student类继承了Person类
}

public class TestDemo {
    public static void main(String args[]) {
        Student stu = new Student(); // 实例化的是子类
        stu.setName("张三"); // Person类定义
        stu.setAge(20); // Person类定义
        System.out.println("姓名:" + stu.getName() + ",年龄:" + stu.getAge());
    }
}

运行结果:

姓名:张三,年龄:20
1
通过代码可以发现,子类(Student)并没有定义任何的操作,而在主类中所使用的全部操作都是由Person类定义的,这证明:子类即使不扩充父类,也能维持父类的操作。

在子类之中扩充父类的功能:

package com.wz.extendsdemo;

class Person {
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

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

    public int getAge() {
        return this.age;
    }
}

class Student extends Person { // Student类继承了Person类
    private String school; // 子类的属性

    public void setSchool(String school) {
        this.school = school;
    }

    public String getSchool() {
        return this.school;
    }
}

public class TestDemo {
    public static void main(String args[]) {
        Student stu = new Student(); // 实例化的是子类
        stu.setName("张三"); // Person类定义
        stu.setAge(20); // Person类定义
        stu.setSchool("清华大学"); // Student类扩充方法
        System.out.println("姓名:" + stu.getName() + ",年龄:" + stu.getAge() + ",学校:" + stu.getSchool());
    }
}

运行结果:

姓名:张三,年龄:20,学校:清华大学

 以上的代码,子类对于父类的功能进行了扩充(扩充了一个属性和两个方法)。但是思考一下:子类从外表看是扩充了父类的功能,但是对于以上的代码,子类还有一个特点:子类实际上是将父类定义的更加的具体化的一种手段。父类表示的范围大,而子类表示的范围小

三、继承的限制

虽然继承可以进行类功能的扩充,但是其在定义的时候也是会存在若干种限制的。

限制一:一个子类只能够继承一个父类,存在单继承局限。 
错误的写法:

class A {}
class B {}
class C extends A,B {}          // 一个子类继承了两个父类

以上操作称为多重继承,实际上以上的做法就是希望一个子类,可以同时继承多个类的功能,但是以上的语法不支持而已,但是可以换种方式完成同样的操作。

正确的写法:

class A {}
class B extends A {}
class C extends B {}

限制二:在一个子类继承的时候,实际上会继承父类之中的所有操作(属性、方法),但是需要注意的是,对于所有的非私有(no private)操作属于显式继承(可以直接利用对象操作),而所有的私有操作属于隐式继承(间接完成)。

package com.wz.extendsdemo;

class A {
    private String msg;

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getMsg() {
        return this.msg;
    }
}

class B extends A {
    public void print() {
        //System.out.println(msg); // 错误: msg定义为private,不可见
    }
}

public class TestDemo {
    public static void main(String args[]) {
        B b = new B();
        b.setMsg("张三");
        System.out.println(b.getMsg());
    }
}

此时对于A类之中的msg这个私有属性发现无法直接进行访问,但是却发现可以通过setter、getter方法间接的进行操作。

限制三:在继承关系之中,如果要实例化子类对象,会默认先调用父类构造,为父类之中的属性初始化,之后再调用子类构造,为子类之中的属性初始化,即:默认情况下,子类会找到父类之中的无参构造方法。

package com.wz.extendsdemo;

class A {
    public A() {         // 父类无参构造
              System.out.println("*************************") ;
    }
}
class B extends A {
    public B() {         // 子类构造
              System.out.println("#########################");
    }
}
public class TestDemo {
    public static void main(String args[]) {
              B b = new B() ;   // 实例化子类对象
    }
}

运行结果:

*************************
#########################

 这个时候虽然实例化的是子类对象,但是发现它会默认先执行父类构造,调用父类构造的方法体执行,而后再实例化子类对象,调用子类的构造方法。而这个时候,对于子类的构造而言,就相当于隐含了一个super()的形式:

class B extends A { public B() { // 子类构造 super(); // 调用父类构造 System.out.println("#########################"); } }

现在默认调用的是无参构造,而如果这个时候父类没有无参构造,则子类必须通过super()调用指定参数的构造方法:

ackage com.wz.extendsdemo;

class A {
    public A(String msg) { // 父类构造
        System.out.println("*************************");
    }
}

class B extends A {
    public B() { // 子类构造
        super("Hello"); // 调用父类构造
        System.out.println("#########################");
    }
}

public class TestDemo {
    public static void main(String args[]) {
        B b = new B(); // 实例化子类对象
    }
}

运行结果:

*************************
#########################

在任何的情况下,子类都逃不出父类构造的调用,很明显,super调用父类构造,这个语法和this()很相似:super调用父类构造时,一定要放在构造方法的首行上。 

猜你喜欢

转载自blog.csdn.net/weixin_42194284/article/details/89976379