1.理解继承的优缺点 2.了解继承的使用场景 3.掌握super和this的使用 4.理解方法重载和重写的区别 5.了解抽象类的 使用场景 6.了解final关键字的特点

1. 继承

1.1 继承的实现(掌握)

  • 继承的概念

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

    • 继承通过extends实现
    • 格式:class 子类 extends 父类 { }
      • 举例:class Dog extends Animal { }
  • 继承带来的好处

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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中类支持多层继承
  • 多层继承示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    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. 子类局部范围找
  2. 子类成员范围找
  3. 父类成员范围找
  • 示例代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Fu {
    int num = 10;
    }
    class Zi {
    int num = 20;
    public void show(){
    int num = 30;
    System.out.println(num);
    }
    }
    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 继承中成员方法的访问特点(掌握)就近原则

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

  1. 子类成员范围找
  2. 父类成员范围找

2.4 方法重写(掌握)

  • 1、方法重写概念

    • 子类出现了和父类中一模一样的方法声明(方法名一样,参数列表也必须一样)
  • 2、方法重写的应用场景

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

重载和重写的区别:

重载 :同一个类中 方法名相同 参数不同

​ 目的:使用相同的方法名处理不同 的业务

重写: 父子类关系,方法声明全部相同 (@Override)

​ 目的 :执行与父类不同的业务

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

  • 方法重写的注意事项
  1. 私有方法不能被重写(父类私有成员子类是不能继承的)
  2. 子类方法访问权限不能更低(public > 默认 > 私有)
  3. 静态方法不能被重写,如果子类也有相同的方法,并不是重写的父类的方法
  4. @Override注解用来检测当前的方法,是否是重写的方法,起到【校验】的作用
  • 示例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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.6 权限修饰符 (理解)

02_权限修饰符

public 所有人都可以

private 只有自己可以

protected 只有自己或自己的子(只认父子关系)

默认 只有同一个包下的可以(只认包不管父子)

public protected 默认(啥也不写) private

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

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

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

盘点jdk帮我们省略的东西
new int[]{};//静态初始化数组时 , jdk帮我们省略了new int[]

​ this. 在同一个类种调用类的成员方法 (静态方法 省略 类名.)

​ super(); 在所有的构造方法中第一行都默认省略了一个super()

​ 类型转换 : 自动类型转换省略了 (数据类型)

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

1
2
3
4
1. 通过使用super关键字去显示的调用父类的带参构造方法
2. 子类通过this去调用本类的其他构造方法,本类其他构造方法再通过super去手动调用父类的带参的构造方法

注意: this(…)super(…) 必须放在构造方法的第一行有效语句,并且二者不能共存

注意: 构造方法的目的:创建对象

3.抽象类

3.1抽象类的概述(理解)

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

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

1
2
3
4
5
6
 抽象方法:一个方法如果没有方法体 ,称这个方法为抽象方法    在方法的声明上加abstract 没有{}

抽象类: 有抽象方法的类就叫抽象类 类的声明位置上有 abstract

抽象方法 最终一定会被明确方法体

3.2抽象类的特点(记忆)

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

    1
    2
    3
    4
    5
    //抽象类的定义
    public abstract class 类名 {}

    //抽象方法的定义
    public abstract void eat();
  • 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类

  • 抽象类不能实例化(只能创建子类对象)

  • 抽象类可以有构造方法

  • 抽象类的子类

    ​ 要么重写抽象类中的所有抽象方法

    ​ 要么是抽象类

    最终的类一定是 非抽象 , 并且一定是把抽象类中的抽象方法声明了的

3.3模板设计模式

  • 设计模式

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

    java 23中常用的设计模式

  • 模板设计模式

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

  • 模板设计模式的优势

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

  • 示例代码

    模板类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    /*
    作文模板类
    */
    public abstract class CompositionTemplate {

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

    body();

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

    }

    public abstract void body();
    }

    实现类A

    1
    2
    3
    4
    5
    6
    7
    8
    public class Tom extends CompositionTemplate {

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

    实现类B

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Tony extends CompositionTemplate {
    @Override
    public void body() {

    }

    /*public void write(){

    }*/
    }

    测试类

    1
    2
    3
    4
    5
    6
    public class Test {
    public static void main(String[] args) {
    Tom t = new Tom();
    t.write();
    }
    }

3.4final(应用) (最终)

  • fianl关键字的作用

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

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

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

    • final修饰变量:表明该变量是一个常量,不能再次赋值

    • 被final修饰的成员变量 一定要在创建构造方法前对其进行初始化

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

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

      • 举例

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

4.代码块

4.1代码块概述 (理解)

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

4.2代码块分类 (理解)

  • 局部代码块

    • 位置: 方法中定义

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

    • 示例代码

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

      // System.out.println(a);
      }
      }
  • 构造代码块

    • 位置: 类中方法外定义

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

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

    • 示例代码

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      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关键字修饰,随着类的加载而加载,并且只执行一次

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

    • 示例代码

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      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类的带...........参数构造方法");
      }
      }

5.难点总结

  • 子类继承父类 实例化子类时 会先初始化父类构造方法 代码块优先于构造方法 静态代码块优先于代码块 (静态优先于非静态),静态方法随着类加载而加载 并且只执行一次 用于对数据进行初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class A extends B{
static {
sout("1"); //2.再初始化本类的静态代码块 静态随着类的加载而加载 并且只执行一次
}
{
sout("2"); //5.再初始化子类的代码块
}
public A(){

sout("3");//6.再初始化子类的构造方法

}
}
class B {
static {
sout("4"); //1.先初始化父类的静态代码块 静态随着类的加载而加载 并且只执行一次
}
{
sout("5"); //3.再初始化父类的代码块
}
public B(){
sout("6"); //4.再初始化父类的构造方法
}
}
psvm{

A a= new A();
sout()
}

  • 子类继承父类后 子类所有的构造方法 默认会有super(); 并且在构造的第一行 如果父类没有空构造方法 子类必须手动给父类进行初始化 例如 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A {
public A(int a){
//已知 已经定义了有参构造 系统默认空参构造就会被收回
}
}


public class B extends A {
public B(){
this(20);//此处也会有默认的super() 也会出错 有两种解决办法 一种是调用本类有参构造,就会执行super(20)对父类进行初始化 或者 super(20);
}
public B(int a){
super(20);//这儿默认super()调用父类的空参构造就会出错 所以只能手动赋值 调用父类的有参构造进行初始化
}
}
  • **静态方法不能被重写,如果子类也有相同的方法,并不是重写的父类的方法 **

  • 被final修饰的成员变量 一定要在构造方法创建时 进行初始化

6.概述总结

继承概念

概念:让类与类之间产生父子关系
写法: 子类 extends 父类,之后子类就具有了父类非private 的优缺点:
优点:提高了代码复用性,提高了维护效率
缺点:继承关系会让类与类之间的耦合性提高了
特点:类与类之间 只能是单继承关系 , 不可以多继承, 只能继承一个父类,可以 多层继承

方法:最后一定要明确自己要干啥

高内聚,低耦合

对扩展开放 , 对修改关闭:

成员的访问

成员变量: 就近原则: 先局部后成员 再父类

成员方法:就近原则 先成员后父类

构造方法:所有的构造方法里的第一行都是super (),

子类对象在创建前 会 先执行父类的构造方法

super关键字

含义: 父类地址的引用

this与super 对比

this 本类的 变量或方法

super 父类的变量或方法

this 和 super都可以调用构造方法 this(); super(); 不能同时使用

方法的重写:

子类不想执行父类的方法内容 , 有独特的功能

写法: 与父类的声明 严格一致 ,权限不能比父类小

重载与重写区别

重写:父子类关系中,不同的执行方式

重载: 同一个类种 ,自己 不同功能

抽象 类

概念: 现有抽象方法 : 方法 不明确方法体,有抽象方法的类 就是抽象类

写法:abstract 修饰方法 与类

特点: 不能创建对象 , 只能使用子类对象 调方法

抽象类可以没有抽象方法

有抽象方法的类必须是抽象类

抽象类中抽象方法 最终一定会被声明清楚

final关键字:

修饰类 ,方法, 变量

类: 不能被继承

方法: 不能被重写

变量: 不能被修改

7.Xmid思维导图

Xmid思维导图:: 点击查看