Java 面向对象程序设计 继承与多态

继承是面向对象程序设计方法中实现软件重用的一种重要手段,通过继承可以有效的组织程序结构,明确类之间的关系,并充分利用已有的类来创建新类,从而完成复杂的设计与开发。多态则可以同一多个相关类的对外接口,并在运行时根据不同的情况执行不同的操作,提高类的抽象度和灵活性。

1.继承的介绍

在面向对象技术中,继承是一个最为显著的特性,继承表示的时存在面向对象程序中的两个类之间的关系。当一个类充当另一个类的子类,这个类就自动拥有另一个类的所有非私有属性(域和方法)时,那么我们就称这两个类之间具有继承关系。

在类的定义过程中,继承是一种由已有的类创建新类的机制。继承而得到的类为子类,被继承的类为父类,父类包括所有直接或间接被继承的类。

一般面向对象程序设计语言中的继承分为:单继承和多继承,其中单继承采用树状结构,设计实现容易,而多继承采用的是网状结构、设计、实现复杂。其中Java提供的是单继承机制。这使得Java类是具有严格的层次结构的。

除Object类之外,每个类都有唯一的父类。Object类定义和实现了Java系统所需要的众多类的共同行为,它是所有类的父类,也即这个树状结构中的根类,所有的类都是由这个类继承、扩充而来的,这个Object类定义在java.lang包中。

2.继承的实现

2.1 子类的定义

定义一个子类,即在定义一个类的时候加上extends关键字,并在之后带上其父类名,其一般格式为:

[类的修饰符] class  <子类名> extends <父类名>{
    <域定义>;
    <方法定义>;
  }

新定义的子类可以从父类那里继承所有非private的域和方法作为自己的属性。

2.2 域的继承与隐藏

2.2.1 域的继承

子类可以继承父类的所有非私有域。

package study;
class bird {
    final int age = 10;
    private double weight = 10;
    public boolean fly(){
        System.out.println("bird can fly");
        return true;
    };
}
class eagle extends bird{
    public void features(){
        System.out.println("Eagle is fierce");
    }
}
public class fly{
    public static void main(String[] args) {
        eagle a = new eagle();
        System.out.println(a.age);//10
        System.out.println(a.fly());//bird can fly
        System.out.println(a.weight);
        //报错,'weight' has private access in 'study.bird',子类无法访问父类的私有域。
    }
}

2.2.2 域的隐藏

子类重新定义一个与从父类继承来的域变量完全相同的变量,称为域的隐藏。即子类中定义了与父类同名的域变量,就是子类变量对同名父类变量的隐藏。这里所谓隐藏是指子类拥有了两个相同名字的变量,一个来自继承父类,另一个由自己定义。在这种情况下,当子类执行继承的父类方法时,处理的是父类的变量,而当子类执行它自己定义的方法时,所操作的就是它自定义的变量,而把来自继承父类的变量“隐藏”起来了。

class A {
    static int data_a = 3;
}
class B extends A {
    static int data_a = 5;
}
class C extends B {
    int data_a = 10;
    void print_out() {
        System.out.println("" + this.data_a);
        //当子类执行它自己定义的方法时,所操作的就是它自定义的变量,把父类的变量隐藏起来了。
        System.out.println("" + A.data_a);
        //当子类执行继承的父类方法时,处理的是父类的变量
        System.out.println("" + B.data_a);
    }
}
class demo {
    public static void main(String args[]) {
        C c = new C();
        c.print_out();
    }
}

2.2.3 方法的继承与覆盖

方法的继承:父类的非私有方法可以被子类所继承。
方法的覆盖:指子类重定义从父类继承来的一个同名方法,此时父类和子类中都存在一个同名方法,父类这个方法在子类中不复存在。这是子类通过重新定义与父类同名的方法,实现自身的行为。

class a {
    public double area(double x, double y) {
        return x * y;
    }
}
class b extends a {
    public double area(double x, double y) {
        return (x + y) * 2;
    }
}
public class Override {
    public static void main(String[] args) {
        b b1 = new b();
        System.out.println(b1.area(2, 3));
        //输出10.0
        //如果注释掉b类的area方法,那么输出的是6.0
    }
}

子类在重新定义父类已有的方法是,应保持与父类完全相同的方法头部声明,即完全相同的方法名、返回类型和参数列表。

方法的覆盖和域的隐藏的不同之处:域的隐藏只是子类隐藏父类的域使之不可见,父类的同名域在子类的对象中仍然占有自己的独立内存空间。而子类方法对父类方法的覆盖则是清除父类方法占用的内存空间,从而使父类方法在子类对象中不复存在。

3.多态性

3.1多态性的概念

多态性是指同名的不同方法在程序中共存。即为同一个方法名定义几个版本的实现,运行时根据不同情况执行不同的版本。调用者只需使用同一个方法名,系统会根据不同情况,调用相应的不同方法,从而实现不同的功能。
多态性又被称为“一个名字,多个方法”。

3.2多态性的实现有两种方式:

3.2.1覆盖实现多态性:

通过子类对继承父类方法的重定义来实现。使用时注意:在子类重定义父类方法时,要求与父类中方法的原型(参数个数、类型、顺序)完全相同。

在覆盖实现多态性的方式中,子类重定义父类方法,此时方法的名字、参数个数、类型、顺序完全相同。由于这些方法是存在不同的类层次结构中,在调用方法时只需要指明是调用哪个类(或对象)的方法,就很容易把它们区分开来,其调用形式为:

对象名.方法名        或         类名.方法名

3.2.2重载实现多态性:

在一个类中的定义多个同名方法的不同实现。定义方法时方法名相同,但方法的参数不同(参数的个数、类型、顺序不同)。这些方法同名的原因是具有类似的功能且目的相同,但在实现该功能的具体方式和细节方面有所不同,因此需要定义多种不同的方法体。

由于重载发生在同一个类中,不能再用类名或对象名来区分不同的方法了,所以在重载中采用的区分方法是使用不同的形式参数表,包括形式参数的个数不同、类型不同或顺序的不同。

public class Aa {
    public void Aa(){
        System.out.println("无参数方法");
    };
    public  void Aa(int a){
        System.out.println("输入一个参数"+a);
    };
    public void Aa(int a,int b){
        System.out.println("输入两个参数"+a+b);
    }
    public static void main(String[] args) {
        Aa a1 = new Aa();
        a1.Aa();
        //无参数方法
        a1.Aa(1);
        //输入一个参数1
        a1.Aa(1,5);
        //输入两个参数15
    }
}

 4.构造方法的继承与重载

4.1 构造方法的重载

构造方法的重载是指同一个类中定义不同参数的多个构造方法,以完成不同情况下对象的初始化。

一个类的若干个构造方法之间可以相互调用。当类中一个构造方法需要调用另一个构造方法时,可以使用关键字this,并且这个调用语句应该是该构造方法的第一个可执行语句。

public class Ba {
    void Ba(){
        System.out.println("无参数构造方法");
    }
    void Ba(int a){
        System.out.println("一个参数构造方法   "+ a );
    }
    void Ba(int a,int b){
        this.Ba();
        this.Ba(100);
        System.out.println("两个参数的构造方法   "+a+b);
    }
    public static void main(String[] args) {
        Ba ba = new Ba();
        ba.Ba(1,5);
    }
}
//输出
//无参数构造方法 //一个参数构造方法 100 //两个参数的构造方法 15

4.2 构造方法的继承

子类可以继承父类的构造方法,继承的方式遵循以下原则:

  • 子类无条件地继承父类的无参数的构造方法。
  • 如果子类没有定义构造方法,则它将继承父类的无参数构造方法作为自己的构造方法;如果子类定义了构造方法,则在创建新对象时,将先执行来自继承父类的无参数构造方法,然后再执行自己的构造方法。
  • 对于父类的带参数构造方法,子类可以通过在自己的构造方法中使用super关键字来调用它,但这个调用语句必须是子类构造方法的第一个可执行语句。

下面对这三个原则进行分别介绍:

  1. 前面说到,子类无条件继承父类的无参数构造方法。如果子类有无参数构造函数,那么父类一定要有无参数构造函数。若子类不适用无参数构造函数,那么父类可以没有无参数构造函数。
  2. 在创建新对象时,子类先执行来自继承父类的无参数构造方法,然后再执行自己的构造方法。系统不会在调用有参构造方法的时候自动调用无参构造方法,需要自己手动调用实现。
    class grandfather{
        public grandfather(){
            System.out.println(" String a");
        }
    }
    class father extends grandfather{
        public father(){
            System.out.println(" String b");
        }
    }
    class person extends father{
        public person(){
            System.out.println(" String c");
        }
    }
    public class ConstructorTest{
        public static void main(String args[]){
            person zhangsan = new person();
        }
    }
    //输出
    // String a
    // String b
    // String c
  3. super是表示父类对象的关键字,super表示当前对象的直接父类对象的一个引用,通过super可使用父类对象的方法或域。
    class FatherClass {
        public FatherClass() {
            System.out.println("父类 无参 构造函数");
        }
        public FatherClass(int i) {
            //this();调用自身的无参构造函数
            System.out.println("父类 一个参数构造函数      " + i);
        }
        public FatherClass(int i, String j) {
            //this(i);调用自身一个参数的构造函数
            System.out.println("父类 两个参数构造函数     " + i + "    " + j);
        }
    }
    class SonClass extends FatherClass {
        public SonClass() {
            System.out.println("子类 无参 构造函数");
        }
        public SonClass(int a) {
            //super(33, "Hello");  调用父类的两个参数构造函数
            System.out.println("子类一个参数构造函数    " + a);
        }
        public void fun(int a) {//子类中定义一个实例函数
            System.out.println("子类一个参数构造函数      " + a);
        }
    }
    public class ConstructorExtend {//测试子类继承父类的构造函数
        public static void main(String args[]) {
            SonClass son1 = new SonClass(12);
            FatherClass father = new FatherClass(12, "hello");
    
        }
    }
    //输出
    //父类 无参 构造函数
    //子类一个参数构造函数    12
    //父类 两个参数构造函数     12    hello
原文地址:https://www.cnblogs.com/JZN-dhy/p/13443773.html