面向对象4---继承

一.继承的概述及特点

  1. 继承的概述:将多个类的共性内容,抽取到一个独立的类中, 独立的类和这多个类就产生了一种继承关系.
    这多个类称为子类,独立的类称为父类

  2. extends关键字:表示继承

    格式:class Zi extends Fu{

      }

  3. 继承的特点:

    • 在java中只支持单继承,不支持多继承
      别的语言可以支持多继承:class Zi extends Fu,Mu{ }
    • 在java中支持多层继承
/*
 * 多层继承
 * */
//爷爷类
class GrandFather{
    public void show1(){
        System.out.println("grandfather");
    }
}

//父亲类继承爷爷类
class Father extends GrandFather{
    public void show2(){
        System.out.println("father");
    }
}

//儿子类继承父亲类
class Son extends Father{
    public void show3(){
        System.out.println("son");
    }
}
public class Demo1 {
    public static void main(String[] args){
        //创建一个儿子类的对象
        Son s = new Son();

        //多层继承,父亲类继承爷爷类,儿子类继承父亲类.因此儿子类可以调用父亲类的方法
        s.show1();

        s.show2();
        s.show3();
    } 
}

这里写图片描述


二.继承的好处及注意事项

  1. 继承的好处:

    • 提高代码的复用性
    • 提高代码维护性
    • 让类与类产生一种关系,是多态的前提
  2. 继承的注意事项:

    • 子类不能继承父类私有的成员(成员方法/成员变量)
    • 子类不能继承父类的构造方法,但可以间接的通过super关键字去访问父类的构造方法

三.继承中成员变量的关系

  1. 类的成员:成员变量,成员方法,构造方法
  2. 子类和父类,同名不同名的成员变量:
    • 不同名的成员变量:分别输出即可
    • 同名的成员变量:
        先在子类成员方法的局部位置查找,有这个变量就输出
        若在子类成员方法的局部位置找不到,就在子类的成员位置查找,有就输出
        若在子类的成员位置找不到,就在父类的成员位置查找,有就输出
        若在子类的成员位置找不到,就没有这个变量,报错
      总结:查找顺序:子类局部位置 —>子类成员位置 —>父类成员位置
//父类
class Fu{
    //父类成员位置
    int num = 10;
}

//子类
class Zi extends Fu{
    //子类的成员位置
    int num = 20;
    public void show(){
        //子类成员方法中的局部位置
        int num = 30;
        System.out.println(num);
    }

}
//测试类
public class Demo2 {
    public static void main(String[] args){
        Zi z = new Zi();
        z.show();
    }
}

这里写图片描述


四.super关键字

  1. super关键字:存储父类空间的一个标识,即父类的引用或者父类的对象
  2. this关键字和super 的区别以及他们的应用场景
    • 区别:
        this关键字:当前类的对象
        super关键字:父类的引用
    • 应用场景:
      访问成员变量:this.成员变量 — super.成员变量
      访问构造方法:this(..) — super(..)
      访问成员方法:this.成员方法() — super.成员方法()

五.继承中构造方法的关系

  1. 构造方法之间的关系:
    • 子类的(有参/无参)构造方法默认的访问父类中的无参构造方法
    • 子类中的构造方法的第一句话被隐藏:super();
  2. 为什么子类的构造方法会默认的访问父类的无参构造?
    因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化
/*
 * 子类中所有的构造方法默认都会访问父类中空参数的构造方法
 * */
class Fu3{

    public Fu3(){
        System.out.println("这是父类的无参构造方法");
    }

    public Fu3(String name){
        System.out.println("这是父类的有参构造方法");
    }
}

class Zi3 extends Fu3{
    public Zi3(){
        System.out.println("子类的无参构造方法");
    }

    public Zi3(String name){
        System.out.println("子类的有参构造方法");
    }

}

//测试类
public class Demo3{
    public static void main(String[] args) {
        //创建子类的对象
        Zi3 z  = new Zi3() ;
        System.out.println("---------------");
        Zi3 z1 = new Zi3("tom") ;       
    }
}

这里写图片描述
子父类初始化问题:先让父类进行初始化,然后子类进行初始化.
对象初始化问题:默认初始化 —>显示初始化 —>构造方法初始化
看程序写结果:

class X {
    Y b = new Y();
    X() {
        System.out.print("X");
    }
}

class Y {
    Y() {
        System.out.print("Y");
    }
}

//测试类
public class Z extends X{
    Y y = new Y();
    Z() {
        System.out.print("Z");
    }
    public static void main(String[] args) {
        new Z();                
    }
输出:YXYZ

分析:
在main方法中,new Z()对Z类进行初始化之前,先对Z的父类X进行数据初始化,在X类中先输出Y,再输出X.然后在对Z进行初始化,输出Y,Z
3. 子类中的构造方法会默认的访问父类中的无参构造方法,那么如果父类中没有无参构造方法,会出现什么问题?如何解决?
问题:报错
解决:在父类中给出无参构造方法
  使用super关键字去显访问父类中的带参构造
  使用在子类构造方法中使用this关键字,间接的使用父类中的代参构造


六.方法重写

  1. 方法重写:子类出现了和父类一模一样的方法声明
  2. 方法重写的应用:当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
//手机类
class Phone{
    public void Call(){
        System.out.println("打电话");
    }
}

//新的手机类,延续了手机类打电话的功能,又有特有的发短信的功能
class NewPhone extends Phone{
    public void Call(){
        System.out.println("打电话");
    }
    public void Message(){
        System.out.println("发短信");
    }
}
public class Demo1 {
    public static void main(String[] args){
        NewPhone n =new NewPhone();
        n.Call();
        n.Message();
    }
}

这里写图片描述
3. 方法重写和方法重载的区别:
a.方法重载(overload):在同一个类中,方法名相同,参数列表不同(参数个数/参数类型),与返回值没有关系
b.方法重写(override):子类的方法和父类的一模一样,返回值也一样


七.final关键字

  1. final关键字:最终,可以修饰类,成员变量,成员方法
  2. final的用法:
    • 修饰类:类不可被继承
    • 修饰方法:方法不可被重写
    • 修饰变量:变量变为常量(自定义常量),只可被赋值一次
//父类
class Father{
    public int num = 100;

    //只可赋值一次
    public final int num2 = 200 ; 
    public void method(){

        //局部变量和成员变量名称一致,就近原则
        int num = 20 ;
        int num2 = 50 ;
        System.out.println("show Father....");
        System.out.println(num2);
    }

    final public void function(){
        System.out.println("function");
    }
}
//子类
class Son extends Father{
    public void show()  {
        System.out.println("show Son...");
    }

    //报错,该类在父类中被final修饰,不可重写
//  public void function(){
//      System.out.println("function");
//  }
}   
public class Demo1 {
    public static void main(String[] args) {
        Son s = new Son() ;

        //报错,此时num2不能在更改,已经是常量
//      s.num2 = 100;
        System.out.println(s.num2);
        s.function();
        s.method();
    }
}

这里写图片描述
3. 关于final修饰变量(基本数据类型/引用类型)的问题:
a.final修饰基本数据类型:基本数据类型的值不改变,变量此时是常量
b.final修饰引用类型:引用类型的地址值不发生改变,对象中堆内存的值可以改变

class Number{
    int num1 = 10;
}
public class Demo2 {
    public static void main(String[] args){
        int x = 20;
        x = 30;
        System.out.println(x);

        //final修饰基本数据类型
        final int y = 40;

        //报错,final修饰基本数据类型,此时变量为常量,不可再赋值
//      y = 50;

        //final修饰引用类型
        final Number n = new Number();

        //final修饰引用类型变量,引用类型变量的值可以改变
        n.num1 = 100;
        n.num1 = 200;

        System.out.println(n.num1);

        //报错,属于新建了一个对象,在堆内存中开辟了一个新空间
//      n = new Number();   
    }
}

这里写图片描述
3. final初始化时机问题:
a.final去修饰变量,这个变量是常量,只能赋值一次
b.被final修饰变量:在调用构造方法之前,被final修饰的变量去使用它

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值