继承

继承

概述

  • 继承的概念

    • 继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法
  • 实现继承的格式

    • 格式:class 子类 extends 父类
      • 举例:class Dog extends Animal
  • 继承带来的好处

    • 继承可以让类与类之间产生关系,子父类关系,产生子父类后,子类则可以使用父类中非私有的成员。
package testClass;

//一个子类可以拥有父类的属性和方法,称为继承
//java不允许多继承,但允许多层继承,不过为了结构的清晰,建议最多继承三层。
public class Student  extends Person{

    //Person类public的属性,Student对象都可以使用
    //Private属性不可以继承
    public void study(){
    //创建子类的对象时会先调用父类的无参构造器,然后再调用子类的构造器
    //可以在子类的构造方法中加上super(),明确要先调用父类的构造器。
        super();//如果想要使用父类的有参构造,就加上参数。也可以用super关键字调用父类的其他属性和方法
        //如果父类有无参构造,super()可以省略。但是如果父类没有无参构造,必须明确使用super()调用父类有参构造。
        super.talk();
        System.out.println(this.name+"在学习。");
    }

}

下面是测试类:

public class Application {
    public static void main(String[] args) {

        //类是抽象的,需要实例化创建对象
        Student jack = new Student();
        jack.name = "Jack";
        jack.age = 15;
        jack.study();
    }
}

继承的好处和缺点

  • 继承好处
    • 提高了代码的复用性(多个类相同的成员可以放到同一个类中)
    • 提高了代码的维护性(如果方法的代码需要修改,修改一处即可)
  • 继承弊端
    • 继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性
  • 继承的应用场景:
    • 使用继承,需要考虑类与类之间是否存在is..a的关系,不能盲目使用继承
      • is..a的关系:谁是谁的一种,例如:老师和学生是人的一种,那人就是父类,学生和老师就是子类

继承中构造方法的访问特点

注意:子类中所有的构造方法默认都会访问父类中无参的构造方法

子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化,原因在于,每一个子类构造方法的第一条语句默认都是:super()

问题:如果父类中没有无参构造方法,只有带参构造方法,该怎么办呢?

1. 通过使用super关键字去显示的调用父类的带参构造方法
2. 在父类中自己提供一个无参构造方法

推荐方案:

​ 自己给出无参构造方法

继承中成员的访问特点

如果子类定义了和父类完全相同的属性名称时,称为属性的覆盖。当父类子类和方法中都有同名的变量时,优先调用方法中的变量,如果想要使用父类的变量就使用super关键字,想使用子类的变量就使用this关键字。同名方法的调用方式类似。

不过属性的覆盖在实际开发中没有意义。在任何开发中,属性都将使用private封装,一旦封装后属性的覆盖是没有意义的。因为父类定义的私有属性子类根本就看不见,更不会相互影响了。

public class Fu{
String info = "Hello";
}

public class Zi extends Fu{
int info = 30;
public void print(){
int info = 20;
System.out.println(info);//使用方法中的info属性
System.out.println(super.info);//使用父类的info属性
System.out.println(this.info);//使用子类的info属性
}
//测试类
public class Demo{
public static void main(String[] args){
	Zi z = new Zi();
	z.print();
	}
}

this&super

  • this&super关键字:
    • this:代表本类对象的引用
    • super:代表父类存储空间的标识(可以理解为父类对象引用)
  • this和super的使用分别
    • 成员变量:
      • this.成员变量 - 访问本类成员变量
      • super.成员变量 - 访问父类成员变量
    • 成员方法:
      • this.成员方法 - 访问本类成员方法
      • super.成员方法 - 访问父类成员方法
  • 构造方法:
    • this(…) - 访问本类构造方法
    • super(…) - 访问父类构造方法

方法的重写

当子类定义了和父类的方法名称、返回值类型、参数类型和个数完全相同的方法时,就称为方法的重写。如果子类覆写了父类的方法,而且实例化了子类对象,那么调用的一定是子类的方法。
方法重写注意事项:

  1. 在覆写的过程中,必须注意到权限问题:被子类覆写的方法不能拥有比父类更严格的访问控制权限。即如果父类的方法是public,那么子类覆写的方法也必须是public;如果父类的方法是default,子类覆写方法是可以是default或public。
  2. 私有方法不能被重写(父类私有成员子类是不能继承的)
class Fu{
    public void fun(){
     	System.out.println("父类的fun()方法"); 
    }
}
class Zi{
    void fun(){//错误!父类方法权限是public,子类不能是default。
        System.out.println("子类的fun()方法"); 
    }
}

方法重写和多态的关系

ps:方法重写要求子类的方法声明和父类完全一样,哪怕方法的参数是多态都不行。

public class Test {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);

        Collection collection = new ArrayList();
        collection.add("hello");
        collection.add("world");
        collection.add("java");

        Father father = new Son();
        father.show(collection);//Son的方法1
        father.show(list);//Son的方法1
    }
}

class Father{
    public void show(Collection c){
        System.out.println("Father的方法");
        for (Object o : c) {
            System.out.println(o);
        }
    }

}
class Son extends Father{

    @Override
    public void show(Collection c){
        System.out.println("Son的方法1");
        for (Object o : c) {
            System.out.println(o);
        }
    }

    //下面的方法不是重写,因为参数不能是继承关系。所以这个方法是子类的特有方法,通过父类引用是无法调用此方法的。
    public void show(List list){
        System.out.println("Son的方法2");
        for (Object o : list) {
            System.out.println(o);
        }
    }
}

阻止继承:使用final

一个类如果不想被子类继承,可以使用final修饰。
字段也可以声明为final,不过如果将一个类声明为final,只有其中的方法自动地变为final,而不包括字段。
如果一个类没有被继承,JVM就不需要使用动态绑定,可以通过内联机制优化处理,比如把c.getName()方法替换成c.name。

posted @ 2021-08-27 17:51  黄了的韭菜  阅读(34)  评论(0编辑  收藏  举报