「Java SE」继承


继承

语法和概念

修饰符 class 子类名 extends 父类名
  • 子类从它的父类中继承所有的数据域和方法,也可以添加新的数据域和新的方法
  • 如果类 B 从类 A 派生,或者说类 B 扩展自类 A,或者说类 B 继承类 A,
    • 称类 A 为"父类",也称为超类、基类;
    • 称类 B 为"子类",也称为次类、扩展类、派生类。

继承的注意点

  1. 子类不是父类的子集,子类一般比父类包含更多的数据域和方法, 子类可以对父类进行扩展,也可以用自己的方式实现父类的方法(即下面要讲的重写)

  2. 子类对象确实拥有父类对象中的所有属性和方法,但是父类对象中的private属性和方法,子类是无法访问到的,只是拥有,但不能使用。
    若想访问private属性,则需要在父类中提供用来访问其私有字段的public或protected方法

  3. Java 的继承是单继承,但是可以多层继承1。Java不允许多重继承(和C++不同),即

    //错误写法
    public class A{}
    public class B{}
    public class C extends A, B{}

  4. 在继承关系之中,如果要实例化子类对象,会默认先调用父类构造,为父类之中的属性初始化,之后再调用子类构造,为子类之中的属性初始化。在任何的情况下,子类都逃不出父类构造的调用

    • 子类和父类的构造函数均无参数
      
      class A {
      public A() {         // 父类无参构造
              System.out.println("*************************") ;
          }
      }
      class B extends A {
          public B() {         // 子类构造
              //这里会自动补充一句super();
              System.out.println("#########################");
          }
      }
      public class TestDemo {
          public static void main(String args[]) {
              B b = new B() ;   // 实例化子类对象
          }
      }
      /*输出为
      *************************
      #########################
      */
      
    • 父类的构造函数有参数,子类无参数
      
      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 关键字

  • super 表示使用它的类的父类。super 可用于:

    • 调用父类的构造方法
    • 调用父类的方法(在子类需要重写父类时使用
    • 访问父类的数据域

调用父类的构造方法

super();  
super(参数列表);
  • super 语句必须是子类构造方法的第一条语句
  • 父类的构造方法不被子类继承, 不能在子类中使用父类构造方法名来调用父类构造方法,调用父类的构造方法的唯一途径是使用 super 关键字。
  • 如果子类中没显式调用,则编译器自动将 super(); 作为子类构造方法的第一条语句。也就是说如果父类构造器没有参数,则在子类的构造方法中不需要使用 super 关键字调用父类构造方法,系统会自动调用父类的无参构造方法
    //有参数
    public class Animal{
        public String name;
        public int id;
        public Animal(int name, int id){
            this.name = name;
            this.id = id;
        }
    }
    
    public class Dog extends animal{
        public Dog(int name, int id){
            super(name, id);
        }
    }
    
    //无参数
    public class Animal{
        public String name;
        public int id;
        public Animal(){
            System.out.println(name + " : " + id);
        }
    }
    
    public class Dog extends animal{
        public Dog(int name, int id){
            super();  //也可以不写;
        }
    }
    

调用父类的实例方法

  • 如果是继承的方法,是没有必要使用 super 来调用,直接即可调用。
  • 如果子类覆盖或重写了父类的方法,则只有使用 super 才能在子类中调用父类中的被重写的方法。
    super.methodName([parameter list]){
        //重新定义方法
    }

访问父类的数据域

  • 如果是继承的数据,是没有必要使用 super 来调用,直接即可调用。
  • 如果子类覆盖或重写了父类的数据,则只有使用 super 才能在子类中调用父类中的被重写的数据。
    super.variableName

this 关键字

this 关键字表示当前对象(实例),可用于:

  • 调用当前类的构造方法(调用类方法不能用this
  • 限定当前对象的数据域变量
    ### 调用当前类的构造方法
    通过this调用当前类的构造方法时必须是方法的第一条语句。(和调用父类使用的super用法相似)
    • this(); 调用默认构造方法。
    • this(参数); 调用带参构造方法。
    • 使用规则:(参考该博客
      • 假如在一个构造方法中使用了this语句,那么它必须作为构造方法的第一条语句

      • 只能在一个构造方法中使用this语句来调用类的其他构造方法,而不能在实例方法中用this语句来调用类的其他构造方法。

      • 只能用this语句来调用其他构造方法,而不能通过方法名来直接调用构造方法。

        public class animal{
            public int id;
        
            public animal(int id){
                this.id = id;
            }
        
            public animal(){
                this(10);
            }
        
            public static void main(String[] args){
                animal cat = new animal();
            }
        }
        

限定当前对象的数据域变量

  • 一般用于方法内的局部变量与对象的数据域变量同名的情况,将成员变量和局部变量进行区分(和C++相似)
    public Student(String name, int age) {
        //注:可以使用this进行区分成员变量和局部变量
        this.name = name;
        this.age = age;
    }

多态的初步介绍

多态是同一个行为具有多个不同表现形式或形态的能力;是同一个接口,使用不同的实例而执行不同操作。多态的好处是——可以使程序有良好的扩展,并可以对所有类的对象进行通用处理。

  • 多态的必要条件
    • 继承
    • 重写
    • 父类引用指向子类对象:Parent p = new Child();
  • 多态调用方法的流程:当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。

下面我们重点理解一下第三个必要条件—— 父类引用指向子类对象。例如以下程序——

class Animal{
    public void move(){
        System.out.println("Animal move!");
    }
}

class Dog extends Animal{
    public int age;
    public void move(){
        age = 10;
        System.out.println("Dog move!");
    }
    public void bark(){
        System.out.println("Dog bark!");
    }
}

public class Test{
    public static void main(String args[]){
        Animal a = new Animal(); // Animal 对象
        Animal b = new Dog(); // Dog 对象

    a.move();// 执行 Animal 类的方法
    b.move();//执行 Dog 类的方法
    b.bark();//编译错误!!!!!!!
    }
}

最后一行编译错误原因是——

因为此时Animal b = new Dog();满足父类引用指向子类对象的情况,首先检查在父类中是否有该方法。因为父类Animal并没有bark()方法,因此会报错。

如果将Animal b = new Dog();改为Dog b = new Dog();的话,以上程序会被正常编译。


文章作者: Hyggge
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Hyggge !
  目录