继承和抽象类

目录

1. 继承

1.1 继承的实现(掌握) 

1.2 继承的好处和弊端(理解)

1.3. Java中继承的特点(掌握)

2. 继承中的成员访问特点

2.1 继承中变量的访问特点(掌握)

2.2 super(掌握)

2.3 继承中构造方法的访问特点(理解)

2.4 继承中成员方法的访问特点(掌握)

2.5 super内存图(理解)

2.6 方法重写(掌握)

2.7 方法重写的注意事项(掌握)

2.8 权限修饰符 (理解)

3.抽象类

3.1抽象类的概述(理解)

3.2抽象类的特点(记忆)

3.3抽象类的案例(应用)

3.4模板设计模式

3.5final(应用)

4.代码块

4.1代码块概述 (理解)

4.2代码块分类 (理解)


1. 继承

1.1 继承的实现(掌握) 

  • 继承的概念

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

  • 实现继承的格式

    • 继承通过extends实现

    • 格式:class 子类 extends 父类 { }

      • 举例:class Dog extends Animal { }

  • 继承带来的好处

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

  • 示例代码

     public class Fu {
         public void show() {
             System.out.println("show方法被调用");
         }
     }
     public class Zi extends Fu {
         public void method() {
             System.out.println("method方法被调用");
         }
     }
     public class Demo {
         public static void main(String[] args) {
             //创建对象,调用方法
             Fu f = new Fu();
             f.show();
     ​
             Zi z = new Zi();
             z.method();
             z.show();
         }
     }

1.2 继承的好处和弊端(理解)

  • 继承好处

    • 提高了代码的复用性(多个类相同的成员可以放到同一个类中)

    • 提高了代码的维护性(如果方法的代码需要修改,修改一处即可)

    • 多态的前提

  • 继承弊端

    • 继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性

  • 继承的应用场景:

    • 使用继承,需要考虑类与类之间是否存在is..a的关系,不能盲目使用继承

      • is..a的关系:谁是谁的一种,例如:老师和学生是人的一种,那人就是父类,学生和老师就是子类

1.3. Java中继承的特点(掌握)

  • Java中继承的特点

    1. Java中类只支持单继承,不支持多继承

      • 错误范例:class A extends B, C { }

    2. Java中类支持多层继承

  • 多层继承示例代码:

    public class Granddad {
    
        public void drink() {
            System.out.println("爷爷爱喝酒");
        }
    
    }
    
    public class Father extends Granddad {
    
        public void smoke() {
            System.out.println("爸爸爱抽烟");
        }
    
    }
    
    public class Mother {
    
        public void dance() {
            System.out.println("妈妈爱跳舞");
        }
    
    }
    public class Son extends Father {
    	// 此时,Son类中就同时拥有drink方法以及smoke方法
    }

2. 继承中的成员访问特点

2.1 继承中变量的访问特点(掌握)

在子类方法中访问一个变量,采用的是就近原则。(1->4寻找)

  1. 子类局部范围找

  2. 子类成员范围找

  3. 父类成员范围找

  4. 如果都没有就报错(不考虑父亲的父亲的情况下)

  • 示例代码

    class Fu {
        int num = 10;
    }
    class Zi {
        int num = 20;
        public void show(){
            int num = 30;
            System.out.println(num);        //30
         // System.out.println(this.num);   //20
         // System.out.println(super.num);  //10
        }
    }
    public class Demo1 {
        public static void main(String[] args) {
            Zi z = new Zi();
            z.show();	// 输出show方法中的局部变量30
        }
    }

2.2 super(掌握)

  • this&super关键字:

    • this:代表本类对象的引用

    • super:代表父类存储空间的标识(可以理解为父类对象引用)

  • this和super的使用分别

    • 成员变量:

      • this.成员变量 - 访问本类成员变量

      • super.成员变量 - 访问父类成员变量

    • 成员方法:

      • this.成员方法 - 访问本类成员方法

      • super.成员方法 - 访问父类成员方法

  • 构造方法:

    • this(…) - 访问本类构造方法

    • super(…) - 访问父类构造方法

2.3 继承中构造方法的访问特点(理解)

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

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

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

  1.  通过使用super关键字去显示的调用父类的带参构造方法                                                                   
  2. 子类通过this去调用本类的其他构造方法,本类其他构造方法再通过super去手动调用父类的带参的构造方法                                                                                                                                     
  3. 注意: this(…)super(…) 必须放在构造方法的第一行有效语句,并且二者不能共存

2.4 继承中成员方法的访问特点(掌握)

通过子类对象访问一个方法

  1. 子类成员范围找

  2. 父类成员范围找

  3. 如果都没有就报错(不考虑父亲的父亲的情况下)

2.5 super内存图(理解)

  • 对象在堆内存中,会单独存在一块super区域,用来存放父类的数据

  • 子类可以继承到父类的私有内容,但不能直接使用

2.6 方法重写(掌握)

  • 1、方法重写概念

    • 子类出现了和父类中一模一样的方法声明(方法名一样,参数列表也必须一样,返回类型也要相同)                                                                                                                           (方法重载:在同一个类中方法名相同,参数列表不同,与返回类型无关)

  • 2、方法重写的应用场景

    • 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容

  • 3、Override注解

    • 用来检测当前的方法,是否是重写的方法,起到【校验】的作用

2.7 方法重写的注意事项(掌握)

  • 方法重写的注意事项

  1. 私有方法不能被重写(父类私有成员子类是不能继承的)

  2. 子类方法访问权限不能更低(public > 默认 > 私有)

  3. 静态方法不能被重写,如果子类也有相同的方法,并不是重写的父类的方法

  • 示例代码

public class Fu {
     private void show() {
         System.out.println("Fu中show()方法被调用");
     }
 ​
     void method() {
         System.out.println("Fu中method()方法被调用");
     }
 }
 ​
 public class Zi extends Fu {
 ​
     /* 编译【出错】,子类不能重写父类私有的方法*/
     @Override
     private void show() {
         System.out.println("Zi中show()方法被调用");
     }
    
     /* 编译【出错】,子类重写父类方法的时候,访问权限需要大于等于父类 */
     @Override
     private void method() {
         System.out.println("Zi中method()方法被调用");
     }
 ​
     /* 编译【通过】,子类重写父类方法的时候,访问权限需要大于等于父类 */
     @Override
     public void method() {
         System.out.println("Zi中method()方法被调用");
     }
 }

2.8 权限修饰符 (理解)

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

1.子类中所以的构造方法默认都会访问父类中无参的构造方法

  • 原因:子类在初始化的时候,有可能会使用到父类的数据,如果父类没有完成初始化,子类将无法使用父类的数据,所以子类初始化之前,一定要先完成父类初始化
  • 如何实现先初始化父类:每一个子类构造方法的第一条语句默认都是: super()
  • 注意 : 如果我们编写的类 , 没有手动指定父类 , 系统也会自动继承 Object(Java 继承体系中的最顶层父类 )

2.父类中没有空参构造方法,只有带参构造方法:

  1. 子类通过 super, 手动调用父类的带参的构造方法,例:super(age)
  2. 子类通过 this 去调用本类的其他构造方法 , 本类其他构造方法再通过 super 去手动调用父类的带参的构造方法
  • 注意: this(...) super(...) 必须放在构造方法的第一行有效语句 , 并且二者不能共存
     

4.抽象类

4.1抽象类的概述(理解)

当我们在做子类共性功能抽取时,有些方法在父类中并没有具体的体现(只有一个方法体,没有内容),这个时候就需要抽象类了!

在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类!

4.2抽象类的特点(记忆)

  • 抽象类和抽象方法必须使用 abstract 关键字修饰

    //抽象类的定义
    public abstract class 类名 {}
    
    //抽象方法的定义
    public abstract 返回值类型 方法名(参数列表);
  • 抽象类中不一定要有抽象方法,有抽象方法的类一定是抽象类

  • 抽象类不能实例化(因为实例化出来后,就可以调用抽象类里面的抽象方法,但那没有意义)

  • 抽象类有构造方法(因为子类中隐藏着super()方法)

  • 抽象类的子类                                                                                                                                要么重写抽象类中的所有抽象方法                                                                                              要么是抽象类(没啥用)

4.3抽象类的案例(应用)

  • 案例需求

    定义猫类(Cat)和狗类(Dog)

    猫类成员方法:eat(猫吃鱼)drink(喝水…)

    狗类成员方法:eat(狗吃肉)drink(喝水…)

  • 实现步骤

    1. 猫类和狗类中存在共性内容,应向上抽取出一个动物类(Animal)

    2. 父类Animal中,无法将 eat 方法具体实现描述清楚,所以定义为抽象方法

    3. 抽象方法需要存活在抽象类中,将Animal定义为抽象类

    4. 让 Cat 和 Dog 分别继承 Animal,重写eat方法

    5. 测试类中创建 Cat 和 Dog 对象,调用方法测试

  • 代码实现

    • 动物类

    public abstract class Animal {
        public void drink(){
            System.out.println("喝水");
        }
    
        public Animal(){
    
        }
    
        public abstract void eat();
    }
    //猫类
    
    public class Cat extends Animal {
        @Override
        public void eat() {
            System.out.println("猫吃鱼");
        }
    }
    //狗类
    
    public class Dog extends Animal {
        @Override
        public void eat() {
            System.out.println("狗吃肉");
        }
    }
    //测试类
    
    public static void main(String[] args) {
            Dog d = new Dog();
            d.eat();
            d.drink();
    
            Cat c = new Cat();
            c.drink();
            c.eat();
    
            //Animal a = new Animal();
            //a.eat();
        }

4.4模板设计模式

  • 设计模式

    设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。 使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。

  • 模板设计模式

    把抽象类整体就可以看做成一个模板,模板中不能决定的东西定义成抽象方法 让使用模板的类(继承抽象类的类)去重写抽象方法实现需求

  • 模板设计模式的优势

    模板已经定义了通用结构,使用者只需要关心自己需要实现的功能即可

  • 示例代码

  模板类

/*
    作文模板类
 */
public abstract class CompositionTemplate {

    public final void write(){
        System.out.println("<<我的爸爸>>");

        body();

        System.out.println("啊~ 这就是我的爸爸");

    }

    public abstract void body();
}

 实现类A

public class Tom extends CompositionTemplate {

    @Override
    public void body() {
        System.out.println("那是一个秋天, 风儿那么缠绵,记忆中, " +
                "那天爸爸骑车接我放学回家,我的脚卡在了自行车链当中, 爸爸蹬不动,他就站起来蹬...");
    }
}

 实现类B

public class Tony extends CompositionTemplate {
    @Override
    public void body() {

    }

    /*public void write(){

    }*/
}

 测试类

public class Test {
    public static void main(String[] args) {
        Tom t = new Tom();
        t.write();
    }
}

4.5final(应用)

  • fianl关键字的作用

    • final代表最终的意思,可以修饰成员方法,成员变量,类

  • final修饰类、方法、变量的效果

    • fianl修饰类:该类不能被继承(不能有子类,但是可以有父类)

    • final修饰方法:该方法不能被重写

    • final修饰变量:表明该变量是一个常量,不能再次赋值(常量命名规范:一个单词大写,若为多个单词,所有字母大写,但中间用_分隔)

      • 变量是基本类型,不能改变的是值

      • 变量是引用类型,不能改变的是地址值,但地址里面的内容是可以改变的

      • 举例

        public static void main(String[] args){
            final Student s = new Student(23);
          	s = new Student(24);  // 错误
         	s.setAge(24);  // 正确
        }

5.代码块

5.1代码块概述 (理解)

在Java中,使用 { } 括起来的代码被称为代码块

5.2代码块分类 (理解)

  • 局部代码块

    • 位置: 方法中定义

    • 作用: 限定变量的生命周期,及早释放,提高内存利用率

    • 示例代码

      public class Test {
          /*
              局部代码块
                  位置:方法中定义
                  作用:限定变量的生命周期,及早释放,提高内存利用率
           */
          public static void main(String[] args) {
              {
                  int a = 10;
                  System.out.println(a);
              }
      
             // System.out.println(a);
          }
      }

  • 构造代码块

    • 位置: 类中方法外定义

    • 特点: 每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行

    • 作用: 将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性

    • 示例代码

      public class Test {
          /*
              构造代码块:
                  位置:类中方法外定义
                  特点:每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行
                  作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
           */
          public static void main(String[] args) {
              Student stu1 = new Student();
              Student stu2 = new Student(10);
          }
      }
      
      class Student {
      
          {
              System.out.println("好好学习");
          }
      
          public Student(){
              System.out.println("空参数构造方法");
          }
      
          public Student(int a){
              System.out.println("带参数构造方法...........");
          }
      }

  • 静态代码块

    • 位置: 类中方法外定义

    • 特点: 需要通过static关键字修饰,随着类的加载而加载,并且只执行一次

    • 作用: 在类加载的时候做一些数据初始化的操作

    • 示例代码

      public class Test {
          /*
              静态代码块:
                  位置:类中方法外定义
                  特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
                  作用:在类加载的时候做一些数据初始化的操作
           */
          public static void main(String[] args) {
              Person p1 = new Person();
              Person p2 = new Person(10);
          }
      }
      
      class Person {
          static {
              System.out.println("我是静态代码块, 我执行了");
          }
      
          public Person(){
              System.out.println("我是Person类的空参数构造方法");
          }
      
          public Person(int a){
              System.out.println("我是Person类的带...........参数构造方法");
          }
      }

  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值