Java语言学习笔记---继承与多态

第二章:继承和多态

第一节:继承

1.1:继承的概述

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

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

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

**父类:**也可以叫做基类、超类

**子类:**也可以叫做派生类

继承关系中的特点:

1、子类可以拥有父类的内容

2、子类还可以拥有自己专有的新内容

1.2:继承的格式

在继承的关系中,子类就是一个父类。(子类可以被当做父类看待)

定义父类的格式:

public class 父类名称{
    //...
}

定义子类的格式:

public class 子类名称 extends 父类名称{
    //...
}
1.3:继承中成员变量的访问特点

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

1、直接通过子类对象访问成员变量:等号左边是谁,就优先用谁,没有则向上找

2、间接通过成员方法访问成员变量:该方法属于谁,就优先用谁,没有则向上找

1.4:区分子类方法中重名的三种情况

局部变量: 直接写成员变量名

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

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

1.5:继承中成员方法的访问特点

在父子类的继承关系中,创建子类对象,访问成员方法的规则:

创建的对象是谁,就优先用谁,如果没有就向上找

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

1.6:方法的覆盖重写

**重写概念:**在继承关系中,方法的名称一样,参数列表也一样

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

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

**方法的覆盖重写特点:**创建的是子类对象,则优先用子类方法

注意:

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

@Override,写在方法前面,用来检测是否是有效的方法覆盖重写

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

2、子类方法的返回值必须小于等于父类方法的返回值范围

3、子类方法的权限必须大于等于父类方法的权限修饰符

权限比较:public>protected>(default)>private

 **(default)不是关键字,而是什么都不写**

**设计原则:**对于已经投入使用的类,尽量不要进行修改,推荐定义一个新的类,来重复利用其中共性 内容,并且添加改动新内容

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

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

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

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

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

总结:

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

1.8:关键字super和this的用法
super关键字的用法:

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

public void methodzi(){
    System.out.println(super.num);//父类中的num
}

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

public void methodzi(){
    super.method();//访问父类中的method
}

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

public zi(){
    super();//可以不写
}
this关键字的用法:

super关键字用来访问父类内容,而this关键字用来访问本类内容

this关键字的用法:

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

int num=20;
public void shownum(){
    int num=10;
    System.out.println(num);//局部变量
    System.out.println(this.num);//本类中的成员变量
    System.out.println(super.num);//父类中的成员变量
}

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

public void methodA(){
    System.out.println("AAA");
}
public void methodB(){
    this.methodA();
    System.out.println("BBB");
}

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

注意:A this(…)调用也必须是构造方法的第一个语句,唯一一个

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

public zi(){
    this(123);//本类的无参构造,调用本类的有参构造
}
public zi(int n){
    
}
this和super关键字图解:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m7oCdNHl-1611640295969)(D:/学习/Java/图片/image-20201122105420796.png)]

1.9:Java继承的三个特点

**1、Java语言是单继承的:**一个类的直接父类只能有唯一一个

2、Java语言可以多级继承

3、一个子类的直接父类是唯一的,但是一个父类可以拥有很多个子类

第二节:抽象类

2.1:抽象的概念

如果父类当中的方法不确定如何进行{}方法体实现,那么这就应该是一个抽象方法

2.2:抽象的方法和抽象的类的格式

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

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

public abstract class Animal{
	public abstract void eat();
}
2.3:抽象方法和抽象类的使用

如何使用抽象类和抽象方法:

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

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

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

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

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

2.4:抽象方法和抽象类的注意事项

1、抽象类不能创建对象,只能创建其非抽象子类的对象

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

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

4、抽象类的子类,必须重写抽象父类中所有的抽象方法,除非子类是抽象类

第三节:接口

3.1 接口概念

**接口:**一种公共的规范标准

只要符合规范标准,大家就可以通用

接口是多个类的公共规范,是一种引用数据类型,最重要的内容就是其中的抽象方法

3.2 接口的定义基本格式

定义接口的格式:

public interface 接口名称{
    //接口内容
}

**备注:**换成了关键字interface之后,编译生成的字节码文件依然是.java–>.class

如果是java 7,那么接口中可以包含的内容有:

1、常量

2、抽象方法

如果是java 8,还可以额外包含有:

3、默认方法

4、静态方法

如果是java 9,还可以额外包含有:

5、私有方法

3.3 接口的抽象方法定义

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

格式:

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

注意:

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

2、这两个关键字修饰符,可以选择性的忽略

3、方法的三要素可以随意定义

3.4 接口的使用步骤

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

格式:

public class 实现类名称 implements 接口名称{
    //...
}

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

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

3、创建实现类的对象,进行使用

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

3.5 接口的默认方法

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

格式:

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

备注:接口中的默认方法可以解决接口升级问题

总结:

1、接口的默认方法,可以通过接口实现类对象直接调用

2、接口的默认方法,也可以被接口实现类进行覆盖重写

3.6 接口的静态方法

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

格式:

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

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

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

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

格式:

接口名称.静态方法名(参数);
3.7 接口的私有方法

需求:我们需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题,但是这个公共方法不应该让实现类使用,应该是私有化的

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

私有方法的种类:

1、普通私有方法:解决多个默认方法之间重复代码问题

格式:

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

2、静态私有方法:解决多个静态方法之间重复代码问题

格式:

private static 返回值类型 方法名称(参数列表){
    方法体
}
3.8 接口的常量定义和使用

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

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

格式:

public static final 数据类型 常量名称=数据值;
都能用	 能.出来 不可变	
例:public static final int num=10;//这其实就是一个常量,不可以修改

注意:

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

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

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

3.9 内容小结

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

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

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

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

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

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

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

3、从Java 8开始,接口里允许定义默认方法,格式:

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

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

4、从Java 8开始,接口里允许定义静态方法,格式:

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

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

5、从Java 9开始,接口里允许定义私有方法,格式:

普通私有方法:

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

静态私有方法:

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

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

使用接口的时候,需要注意:

1、接口是没有静态代码块或构建方法的

2、一个类的直接父类是唯一的,但是一个类可以同时实现多个接口

格式:

public class MyInterfaceImp implments MyInterfaceA,MyInterfaceB{
    //覆盖重写所有抽象方法
}

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

4、如果实现类没有覆盖重写所有接口中的所有抽象方法,那么实现类就必须是抽象类

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

6、一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,会优先用父类中的方法

3.10 接口之间的多继承

1、类与类之间是单继承的,直接父类只有一个

2、类与接口之间是多实现的,一个类可以实现多个接口

3、接口与接口之间是多继承的

注意:

1、多个父接口中的抽象方法如果重复,没关系

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

第四节:多态

4.1 概述:

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

extends继承或者implements实现,是多态性的前提

**对象的多态性:**一个对象拥有多种形态

4.2 多态的使用和说明

代码当中体现多态性,其实就是一句话:父类引用指向子类对象

格式:

父类名称 对象名=new 子类名称();
	或者:
接口名称 对象名=new 实现类名称();

访问成员变量的两种方式:

1、直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找

2、间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找

第五节:final关键字

5.1 概述

final:最终不可改变的

常见四种用法:

1、可以用来修饰一个类

2、还以用来修饰一个方法

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

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

5.2 final关键字用来修饰一个类

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

public final class 类名称{
    //...
}

**含义:**当前这个类不能有任何的子类,即不能使用final类作为父类

注意:一个类如果是final类,那么其中所有的成员方法都无法进行覆盖重写

5.3 final关键字用于修饰成员方法

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

格式:

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

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

5.4 final关键字用于修饰局部变量

一旦使用final用来修饰局部变量,那么这个变量就不能进行修改,一次赋值,终生不变

final int num=200;//不可再改变num的值了
final int numb;
numb=100;//正确写法,只要保证只有唯一一次赋值即可

不变:对于基本类型来说,不可改变的是变量当中的数据,对于引用类型来说,不可变的是变量中的地址值,但其中的数据可以改变

final Student stu2=new Student("aa");
stu2=new Student("bb");//错误写法,final的引用类型变量,其中的地址不可改变
5.5final关键字用于修饰成员变量

对于成员变量来说,如果使用final关键字修饰,那么这个变量也照样是不可变的

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

2、对于final的成员变量,要么进行直接赋值,要么进行构造方法赋值(二者选其一)

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

第六节:四种权限修饰符

四种权限修饰符: public>protect>(default)>private

同一个类(我自己) YES YES YES YES

同一个包(我邻居) YES YES YES NO

不同包子类(我儿子) YES YES NO NO

不同包非子类(陌生人) YES NO NO NO

第七节:内部类

7.1 内部类的概念与分类

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

分类:

1、成员内部类

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

7.2 成员内部类
定义格式:
修饰符 class 外部类名称{
    修饰符 class 内部类名称{
        /...
    }
    //...
}

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

如何使用:

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

Body body=new Body();
body.methodBdy();

**2、直接方式:**公式:外部类名称.内部类名称 对象名=new 外部类名称().new 内部类名称();

Body.Heart heart=new Body().new Heart();
heart.beat();
内部类的同名变量访问:

如果出现了重名现象,那么格式是:

外部类名称.this.外部类成员变量名

public class Outer{
    int num=10;
    public class Inner{
        int num=20;
        public void methodInter(){
            int num=30;//内部类方法的局部变量
            System.out.println(num);//局部变量,就近原则
            System.out.println(this.num);//内部类的成员变量
            System.out.println(Outer.this.num);//外部类的成员变量
        }
    }
}
7.4 局部内部类

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

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

定义格式:

修饰符 class 外部类名称{
    修饰符 返回值类型 外部类方法名称(参数列表){
        class 局部内部类名称{
            //...
        }
    }
}

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

1、外部类:public/(default)

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

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

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

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

原因:

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

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

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

4、new出来的对象会在堆内存中持续存在,知道垃圾回收消失

7.5 匿名内部类

如果接口的实现类(或者父类的子类)只需要使用唯一的一次,那么这种情况下就可以省略该类的定义,而改写为使用**【匿名内部类】**

匿名内部类的定义:

格式:

接口名称 对象名=new 接口名称(){
  //覆盖重写所有抽象方法  
};

**对格式进行解析:**new 接口名称(){…}

1、new代表创建对象的动作

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

3、{…}这才是匿名内部类的内容

注意:

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

如果希望多次创建对象,而且类的内容一样,那么必须使用单独定义的实现类

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

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

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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值