第九章、继承与多态_黑马Java第57期个人学习笔记_个人笔记

继承与多态

 

第一节、继承

一、继承的概念、格式、特点

(一)继承的概念:

1、继承是多态的前提,如果没有继承,就没有多态。

2、继承解决的主要问题是:共性抽取。

3、面向对象的三大特征:封装性、继承性、多态性。

(二)继承的格式

父类的格式:(即普通类)

public class 父类名称 {

    // ...

}

子类的格式:

public class 子类名称 extends 父类名称 {

    // ...

}

(三)继承的三个特点(单继承、多层继承、相对继承)

1、Java只支持单继承,不支持多继承。

2、Java支持多层继承(继承体系)。

3、子类和父类是一种相对的概念。

 

二、继承中的变量

(一)成员变量的访问(直接、间接)

在父子类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式:

 

1、直接通过子类对象访问成员变量:

    等号【左边】是谁,就优先用谁,没有则向上找。

2、间接通过成员方法访问成员变量:

    该方法【属于】谁,就优先用谁,没有则向上找。

 

(二)子类方法中重名的三种变量区分(局部、本成、父成)

1、局部变量:     直接写局员变量名

2、本类的成员变量:      this.成员变量名

3、父类的成员变量:      super.成员变量名

 

三、继承中的方法

(一)成员方法-覆盖重写

1、访问:在父子类的继承关系当中,创建子类对象,访问成员方法的规则:创建的对象是谁,就优先用谁,如果没有则向上找。

注意事项:

无论是成员方法还是成员变量,如果没有都是向上找父类,绝对不会向下找子类的。

重写(Override):方法的名称一样,参数列表【也一样】。覆盖、覆写。

重载(Overload):方法的名称一样,参数列表【不一样】。

2、重写(Override)

概念:重写要求两同两小一大原则: 方法名相同,参数类型相同,子类返回类型小于等于父类方法返回类型, 子类抛出异常小于等于父类方法抛出异常, 子类访问权限大于等于父类方法访问权限。

(1)必须保证父子类之间方法的名称相同,参数列表也相同。

@Override:写在方法前面,用来检测是不是有效的正确覆盖重写。

这个注解就算不写,只要满足要求,也是正确的方法覆盖重写。

(2)子类方法的返回值类型必须【小于等于】父类方法的返回值类型。

小扩展提示:java.lang.Object类是所有类的公共最高父类(祖宗类),java.lang.String就是Object的子类。

(3)子类方法的抛出异常【小于等于】父类方法的抛出异常

(4)子类方法的权限必须【大于等于】父类方法的权限修饰符。

小扩展提示:public > protected > (default) > private

备注:(default)不是关键字default,而是什么都不写,留空。

 

 

(二)构造方法的访问

1、继承关系中,父子类构造方法的访问特点:

(1) 子类构造方法当中有一个默认隐含的“super()”调用,所以一定是先调用的父类构造,后执行的子类构造。

(2)子类构造可以通过super关键字来调用父类重载构造。

(3)super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造。

(4)子类必须调用父类构造方法,不写则赠送super();写了则用写的指定的super调用,super只能有一个,还必须是第一个。

(5)父类的构造方法是不被子类继承的,只能从子类的构造方法中用super关键字调用。

 

四、super与this关键字

(一)super三用法

1、在子类的成员方法中,访问父类的成员变量。

2、在子类的成员方法中,访问父类的成员方法。

3、在子类的构造方法中,访问父类的构造方法。

 

(二)this三用法

1、在本类的成员方法中,访问本类的成员变量。

2、在本类的成员方法中,访问本类的另一个成员方法。

3、在本类的构造方法中,访问本类的另一个构造方法。

在第3种用法当中要注意:

A. this(  )调用也必须是构造方法的第一个语句,唯一一个。

B. super和this两种构造调用,不能同时使用。

 

(三)super与this的内存图解

 

五、继承综合案例:发红包

(一)案例分析

(二)案例实现

第二节、抽象类

一、抽象的概念、格式

(一)概念

1、父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明还有意义,而方法主体则没有存在的意义了。我们把没有方法主体的方法称为抽象方法。Java语法规定,包含抽象方法的类就是抽象类。

2、被abstract修饰的内容都是暂未被实现的,比如类、方法。

属性之所以不能被abstract修饰,是因为属性不存在"尚未被实现"的状态。

比如你可能会联想到int age; 或是String name; 但可惜的是,在申明变量时,int会默认给age赋予初始值0,String会默认给name赋予初始值""。因此属性达不到"尚未被实现的状态",从而不能被abstract修饰。

(二)抽象方法和抽象类的格式

抽象方法:就是加上abstract关键字,然后去掉大括号,直接分号结束。

抽象类:抽象方法所在的类,必须是抽象类才行。在class之前写上abstract即可。

二、抽象的使用、注意事项

(一)如何使用抽象类和抽象方法:

1、不能直接创建new抽象类对象。

2、必须用一个子类来继承抽象父类。

3、子类必须覆盖重写抽象父类当中所有的抽象方法。

覆盖重写(实现):子类去掉抽象方法的abstract关键字,然后补上方法体大括号。

4、创建子类对象进行使用。

 

(二)抽象方法和抽象类的注意事项

1、抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。

理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。

2、抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。

理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。 

3、抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。

4、抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。

理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。

第三节、接口

 

一、接口的概念、格式、特点

 

(一)接口的概念

1、接口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么 接口的内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法 (JDK 9)。 接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并 不是类,而是另外一种【引用数据类型】。

2、接口的使用,它不能创建对象,但是可以被实现( implements ,类似于被继承)。一个实现接口的类(可以看做是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象类。

3、接口是一种特殊的抽象类。

 

(二)接口的格式

public interface 接口名称 {

    // 接口内容

}

 

(三)接口的特点

1、内容特点:

抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法 (JDK 9)

在Java9+版本中,接口的内容可以有:

(1)成员变量其实是常量,格式:

[public] [static] [final] 数据类型 常量名称=数据值;

注意:常量必须进行赋值,而且一旦赋值不能改变。常量名称完全大写,用下划线进行分隔。

 

(2)接口中最重要的就是抽象方法,格式:

[public] [abstract] 返回值类型 方法名称(参数列表);

注意:实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类。

 

(3)从Java8开始,接口里允许定义默认方法,格式:

[public] default 返回值类型 方法名称(参数列表){方法体}

注意:默认方法也可以被覆盖重写

 

(4)从Java8开始,接口里允许定义静态方法,格式:

[public] static 返回值类型 方法名称(参数列表){方法体}

注意:应该通过接口名称进行调用,不能通过实现类对象调用接口静态方法

 

(5)从Java9开始,接口里允许定义私有方法,格式:

普通私有方法:private 返回值类型 方法名称(参数列表){方法体}

静态私有方法:private static 返回值类型 方法名称(参数列表){方法体}

注意:private的方法只有接口自己才能调用,不能被实现类或别人使用。

 

2、实现特点(多实现)

(1)类与类之间是单继承的。直接父类只有一个。

(2)类与接口之间是多实现的。一个类可以实现多个接口。

(3)接口与接口之间是多继承的。

 

注意事项:

①多个父接口当中的抽象方法如果重复,没关系,不冲突因为抽象方法没有方法体。

②多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写,【而且带着default关键字】。

 

二、接口的常量

(一)格式

public static final 数据类型 常量名称 = 数据值;

备注:一旦使用final关键字进行修饰,说明不可改变。

(二)特点

接口当中也可以定义“成员变量”,但是必须使用public static final三个关键字进行修饰。

从效果上看,这其实就是接口的【常量】。

注意事项:

1、接口当中的常量,可以省略public static final,注意:不写也照样是这样。

2、接口当中的常量,必须进行赋值;不能不赋值。

3、接口中常量的名称,使用完全大写的字母,用下划线进行分隔。(推荐命名规则)

 

三、接口的四类方法(抽、默、静、私)

(一)抽象方法abstract

1、接口抽象方法定义

在任何版本的Java中,接口都能定义抽象方法。

格式:

public abstract 返回值类型 方法名称(参数列表);

 

注意事项:

(1)接口当中的抽象方法,修饰符必须是两个固定的关键字:【public abstract】

(2)这两个关键字修饰符,可以选择性地省略。

(3)方法的三要素(返回值类型,方法名称,参数列表),可以随意定义。

 

2、接口抽象方法使用

接口使用步骤:

(1)接口不能直接使用,必须有一个“实现类”来“实现”该接口。

格式:

public class 实现类名称 implements 接口名称 {

    // ...

}

(2)接口的实现类必须覆盖重写(实现)接口中所有的抽象方法。

实现:去掉abstract关键字,加上方法体大括号。

(3)创建实现类的对象,进行使用。

 

注意事项:

如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己就必须是抽象类。

 

(二)默认方法default (接口升级)

1、接口默认方法定义

从Java 8开始,接口里允许定义默认方法。

格式:

public default 返回值类型 方法名称(参数列表) {

    方法体

}

备注:接口当中的默认方法,可以解决【接口升级】的问题。

 

2、接口默认方法使用

(1)接口的默认方法,可以通过接口【实现类对象】,直接【调用】。

(2)接口的默认方法,也可以被接口【实现类】进行覆盖【重写】。

 

(三)静态方法static

1、接口静态方法定义

从Java 8开始,接口当中允许定义静态方法。

格式:

public static 返回值类型 方法名称(参数列表) {

    方法体

}

提示:就是将abstract或者default换成static即可,带上方法体。

 

2、接口静态方法使用

通过接口名称,直接调用其中的静态方法。

注意事项:不能通过接口实现类的对象来调用接口当中的静态方法。

格式:

接口名称.静态方法名(参数);

 

(四)私有方法private /  private static

1、接囗私有方法定义

从Java 9开始,接口当中允许定义私有方法:

(1)普通私有方法,解决多个【默认方法】之间【重复代码】问题

格式:

private 返回值类型 方法名称(参数列表) {

    方法体

}

(2)静态私有方法,解决多个【静态方法】之间【重复代码】问题

格式:

private static 返回值类型 方法名称(参数列表) {

    方法体

}

 

四、继承父类并实现多个接口

(一)接口是没有静态代码块或者构造方法的。

(二)一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。

格式:

public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {

    // 覆盖重写所有抽象方法

}

(三)如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。

(四)如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个【抽象类】。

 

(五)如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。

(六)一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用【父类】当中的方法。

 

 

第四节、多态

一、多态的概念、格式、特点

(一)多态的概念

1、多态: 是指同一行为,具有多个不同表现形式。父类引用指向子类对象,引用变量所调用的方法总是表现出子类方法的行为特征。

2、多态的前提【重点】

(1)继承或者实现【二选一】 

(2)方法的重写【意义体现:不重写,无意义】 

(3)父类引用指向子类对象【格式体现】

 

(二)多态的格式

代码当中体现多态性,其实就是一句话:父类引用指向子类对象。(一只猫被看做成一只动物)

格式:

父类名称 对象名 = new 子类名称();

或者:

接口名称 对象名 = new 实现类名称();

 

 

(三)多态中的特点

1、成员变量(编译运行全看父类)

成员变量不能覆盖重写

成员变量不具备多态性,通过引用变量来访问其包含的实例变量,系统总是试图访问它编译时类型所定义的成员变量,而不是运行时类型所定义的成员变量。

 

什么是编译时类型和运行时类型?

Java中的许多对象(一般都是具有父子类关系的父类对象)在运行时都会出现两种类型:编译时类型和运行时类型,例如:Person person = new Student();这行代码将会生成一个person变量,该变量的编译时类型是Person,运行时类型是Student。

Java的引用变量有两个类型,一个是编译时类型,一个是运行时类型,编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,会出现所谓的多态。因为子类其实是一种特殊的父类,因此java允许把一个子类对象直接赋值给一个父类引用变量,无须任何类型转换,或者被称为向上转型,由系统自动完成。

 

有一些父类,他允许被继承,但是他本身有一些属于自己的函数,这些函数也允许覆盖,但是函数中有一些自己必须要执行的步骤,如果不执行就会导致类错误,所以我们在覆盖这些函数的时候,必须调用super.xxx。让父函数正常执行,才能执行我们覆盖后添加的内容。

2、成员方法(编译看父类,运行看子类)

在多态的代码当中,成员方法的访问规则是:

    看new的是谁,就优先用谁,没有则向上找。

 

口诀:编译看左边,运行看右边。

 

对比一下:

成员变量:编译看左边,运行还看左边。***

成员方法:编译看左边,运行看右边。

3、多态的好处

 

二、多态的转型(向上、向下)

(一)对象的向上转型

向上转型一定是安全的,没有问题的,正确的。但是也有一个弊端:

对象一旦向上转型为父类,那么就无法调用子类原本特有的内容。

解决方案:用对象的向下转型【还原】。

 

 

(二)对象的向下转型

 

三、用instanceof关键字进行父子类判断

如何才能知道一个父类引用的对象,本来是什么子类?

格式:

对象 instanceof 类名称

这将会得到一个boolean值结果,也就是判断前面的对象能不能当做后面类型的实例。

 

四、多态案例笔记本USB

(一)笔记本USB接口案例分析

 

 

(二)笔记本USB接口案例实现

 

 

第五节、fina关键字

一、fina关键字概念

(一)final关键字概念

学习了继承后,我们知道,子类可以在父类的基础上改写父类内容,比如,方法重写。那么我们能不能随意的继承 API中提供的类,改写其内容呢?显然这是不合适的。为了避免这种随意改写的情况,Java提供了 final 关键字, 用于修饰不可改变内容。

final: 不可改变。可以用于修饰类、方法和变量。 

类:被修饰的类,不能被继承。 

方法:被修饰的方法,不能被重写。 

变量:被修饰的变量,不能被重新赋值

 

(二)常见四种用法:

1. 可以用来修饰一个类

2. 可以用来修饰一个方法

3. 还可以用来修饰一个局部变量

4. 还可以用来修饰一个成员变量

 

二、final的4种用法(类、局变、成变、成方)

(一)final修饰类

当final关键字用来修饰一个类的时候,格式:

public final class 类名称 {

    // ...

}

含义:当前这个类不能有任何的子类。(太监类)

注意:一个类如果是final的,那么其中所有的成员方法都无法进行覆盖重写(因为没儿子。)

 

 

(二)final修饰局部变量

 

(三)final修饰成员变量

1、由于成员变量具有默认值,所以用了final之后必须手动赋值,不会再给默认值了。

2、对于final的成员变量,要么使用直接赋值,要么通过构造方法赋值。二者选其一。

3、必须保证类当中所有重载的构造方法,都最终会对final的成员变量进行赋值。

 

(四)final修饰成员方法

当final关键字用来修饰一个方法的时候,这个方法就是最终方法,也就是不能被覆盖重写。

格式:

修饰符 final 返回值类型 方法名称(参数列表) {

    // 方法体

}

 

注意事项:

对于类、方法来说,abstract关键字和final关键字不能同时使用,因为矛盾。

 

第六节、权限修饰符

编写代码时,如果没有特殊的考虑,建议这样使用权限:

成员变量使用 private ,隐藏细节。 

构造方法使用 public ,方便创建对象。 

成员方法使用 public ,方便调用方法。

 

 

 

第七节、内部类

一、内部类的概念

(一)内部类的概念

如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一个类。

例如:身体和心脏的关系。又如:汽车和发动机的关系。

(二)分类:

1、成员内部类

2、局部内部类(包含匿名内部类)

 

二、成员内部类

(一)成员内部类的格式

修饰符 class 外部类名称 {

    修饰符 class 内部类名称 {

        // ...

    }

    // ...

}

注意:内用外,随意访问;外用内,需要内部类对象。

 

(二)成员内部类的访问特点

1. 间接方式:在外部类的方法当中,使用内部类;然后main只是调用外部类的方法。

2. 直接方式,

类名称 对象名 = new 类名称();

【 外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称(); 】

 

(三)成员内部类的同名变量访问

如果出现了重名现象,那么格式是:外部类名称.this.外部类成员变量名

 

 

三、局部内部类

(一)局部内部类的格式

如果一个类是定义在一个方法内部的,那么这就是一个局部内部类。

“局部”:只有当前所属的方法才能使用它,出了这个方法外面就不能用了。

定义格式:

修饰符 class 外部类名称 {

    修饰符 返回值类型 外部类方法名称(参数列表) {

        class 局部内部类名称 {

            // ...

        }

    }

}

类的权限修饰符:

public > protected > (default) > private

定义一个类的时候,权限修饰符规则:

1、外部类:public / (default)

2、成员内部类:public / protected / (default) / private

3、局部内部类:什么都不能写

 

(二)局部内部类的final问题

局部内部类,如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效final的】。

 

备注:从Java 8+开始,只要局部变量事实不变,那么final关键字可以省略。

 

原因:

1、new出来的对象在堆内存当中。

2、局部变量是跟着方法走的,在栈内存当中。

3、方法运行结束之后,立刻出栈,局部变量就会立刻消失。

4、但是new出来的对象会在堆当中持续存在,直到垃圾回收消失。

 

 

(三)局部内部类重点:【匿名内部类】

1、匿名内部类的格式

如果接口的实现类(或者是父类的子类)只需要使用唯一的一次,

那么这种情况下就可以省略掉该类的定义,而改为使用【匿名内部类】。

匿名内部类的定义格式:

接口名称 对象名 = new 接口名称() {

    // 覆盖重写所有抽象方法

    .....

};

2、匿名内部类的注意事项

对格式“new 接口名称() {...}”进行解析:

(1)new代表创建对象的动作

(2)接口名称就是匿名内部类需要实现哪个接口

(3) {...}这才是匿名内部类的内容

 

另外还要注意几点问题:

(1)匿名内部类,在【创建对象】的时候,只能使用唯一一次。

如果希望多次创建对象,而且类的内容一样的话,那么就需要使用单独定义的实现类了。

(2)匿名对象,在【调用方法】的时候,只能调用唯一一次。

如果希望同一个对象,调用多次方法,那么必须给对象起个名字。

(3)匿名内部类是省略了【实现类/子类名称】,但是匿名对象是省略了【对象名称】

强调:匿名内部类和匿名对象不是一回事!!!

 

 

第八节、引用类型用法总结

 

一、calss作为成员变量类型

 

二、interface作为成员变量、方法参数、返回值类型

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值