zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    常用浏览器内核
    点透问题及解决
    移动端click延迟和tap事件
    CommandoVM-虚拟机映像文件 | VM打开直接用
    Crackme006
    CrackMe005-下篇 | 逆向破解分析 | 160个CrackMe(视频+图文)深度解析系列
    拼多多被薅-谈网络安全中最后的屏障
    一次VB汇编中看-溢出计算
    CM005-逆向分析过程(上篇)
    CrackMe-005全破详解(图文+源码)--上篇
  • 原文地址:https://www.cnblogs.com/JZN-dhy/p/13443773.html
Copyright © 2011-2022 走看看