重写、抽象类、接口
主要内容
- 方法重载
- 方法重写
- final修饰类和方法
- super关键字
- 抽象类
- static
- 接口
一、 方法重载(Overload)
1 简介
Java是强类型语言,不同的数据都对应不同类型。同一个功能如果针对不同的数据类型需要起多个方法名会导致方法名称过多,难于记忆。为了解决这个问题,Java支持方法重载。
方法重载(overload):允许一个类中出现同名方法,但这些方法的参数列表必须是不同的。
参数列表不同:参数的类型不同。
方法重载给程序员调用方法提供了方便。参数个数相同(顺序不同)
例如:我们一直使用的输出语句println()可以支持String、int等多种参数类型,这就是方法重载。所以我们只需要记住一个System.out.println();是输出就行,不需要考虑输出方法参数是什么类型的。
例如:我们在类中生成的构造方法,有无参构造,有参构造。这些构造方法的参数列表是不相同的。只所以允许出现多个同名方法,就是因为Java的重载。
2 代码示例
只要方法名相同,参数列表不同就是重载,允许同一个类出现同名方法。和返回值以及访问权限修饰符没有关系。
3 方法重载误区一
方法重载是一种提供同名方法支持不同参数的机制。这也是Java中唯一一种允许同一个类中出现同名方法的情况。
重载并没有说:不同返回值是重载。也就是说方法名相同,参数列表相同,但是返回值不同的方法,无法构成重载,编译报错。
4 重载误区二
方法名相同、参数列表相同,访问权限修饰符不同时不构成重载。编译报错。
二、 方法重写(Override)
1 简介
方法重写是以继承为基础的。Java规定子类允许对从父类继承过来的方法进行重新定义。
方法重写让程序的代码更加灵活。
记住:子类有的内容直接调用子类内容,子类没有这个内容才会调用父类的。
方法重写必须满足:
- 子类方法名与父类名称完全相同
- 子类方法参数列表必须与父类参数列表完全相同
- 子类方法返回值必须和父类方法返回值相同或是父类方法返回值的子类
- 子类方法访问权限修饰符必须和父类方法访问权限修饰符相同或比父类访问权限修饰符范围更大。
认定:public > protected>默认的 由于private修饰的方法不能被继承,所以不需要考虑。
小技巧:可以在重写的方法上添加@Override注解,来检查重写的语法是否正确。
提示:@+XXXX 这种以@开头的都是注解。注解可以放在类上、方法上、方法参数前面。但是不同的注解支持的位置是不一样的。
2 代码示例
2.1 定义父类
在Parent中提供了getName();方法,设置返回值给父类的方法
2.2 定义子类
定义子类Child,继承Parent。重写getName()方法,设置返回值为子类的方法
2.3 测试重写
创建子类对象,调用getName()发现储输出:子类的方法。
结论:如果子类重写了父类的方法,会调用子类重写后的方法。
三、 final修饰类和方法时
1 简介
在Java中final修饰的类不允许被继承,final修饰的方法不允许被重写。
在JDK中很多类都是final修饰的。
如:String、八大基本数据类型封装类等。
2 代码示例
2.1 在父类中添加final关键字
注意:并不是说类使用final修饰了,方法必须使用final修饰。也不是说方法使用了final修饰,类必须使用final修饰。只是用一个例子直接演示了,final修饰类和final修饰方法子类继承和子类重写的效果。
2.2 在子类中继承和重写
子类直接编译报错。
鼠标放在Parent上时提示:
鼠标方法重写方法上时提示:
3 特例:私有final方法
当父类中final修饰方法的访问权限修饰符是private时,子类是不会继承这个方法的,所以也就不构成重写条件。这个使用在子类中提供一个和父类相同的方法时是允许的。
3.1 父类代码
3.2 子类代码
4 final修饰引用类型变量时
final修饰的变量称为常量。常量一旦被赋值就不允许被修改。
对于引用数据类型赋值的语法:
给对象赋值。对于内存:开辟了一块空间。
类型 对象名 = new 构造方法();
如果使用final修饰.对象一直指向内存中开辟的空间,不允许重新开辟空间(重新实例化)。
final 类型 对象= new 构造方法();
不能再次:对象 = new 构造方法();
但是可以对对象中属性进行修改值。
允许:对象.属性= 值。
四、 父类和子类出现同名属性(常见面试笔试题)
1 简介
在Java中,继承关系下允许父类和子类出现同名属性。且设置父类同名属性的访问权限修饰符能够被子类继承。这时就需要分为多种情况进行讨论了。
2 情况一
当父类和子类都出现同名属性时,实例化子类对象。会调用子类的属性。
2.1 在父类中定义属性
2.2 在子类中定义同名属性
2.3 调用子类属性
2.4 结论
如果子类有,调用子类属性。如果子类没有,调用父类属性。
3 情况二
如果父类中的方法调用了父类属性的值,而子类没有重写这个方法。实例化子类对象时输出的是父类属性值。
3.1 在父类中定义方法
3.2 子类代码没有变化
3.3 调用方法
3.4 结论
继承表示允许子类使用父类的内容。但是父类的方法操作的是父类的属性。所以最后输出的是父类属性的值。
4 情况三
如果父类中的方法调用了属性的值,而子类重写了这个方法。实例化子类对象时输出的是子类属性值。
4.1 父类中有调用属性的方法
4.2 子类中重写这个方法
4.3 调用方法
4.4 结论
因为子类重写了父类的方法,所以实例化子类后调用的就是子类的方法,子类方法操作的是子类的属性,所以最终输出是子类的属性值。
5 情况四
如果子类继承了父类的属性,且在子类中存在同名属性。可以通过super关键字调用父类的属性。
super关键字代表的是父类对象,所有能够被子类继承的方法或实行都能通过super关键字调用。
5.1 父类代码
为了区分调用的是父类方法还是子类方法,在父类方法返回值前面随意加了一个字符串值。
5.2 子类使用super关键字调用父类属性
注意:此处为了让同学们知道依然调用的是子类重写的方法,所以在返回值中随意添加了一个字符串值。
注释掉的内容是为了告诉同学们,super关键字不仅仅可以调用继承的属性,也可以调用继承的方法。
5.3 调用方法
5.4 结论
无论是否出现同名方法或同名属性,都可以使用super关键字调用父类允许被继承的方法或属性。可以使用this关键字调用子类自己的方法和属性(this可以省略)
五、 static
1 简介
static 中文名称:静态。
可以使用static 修饰全局变量 | 成员变量 | 属性或方法。
按照是否为静态,Java中可以把属性分为:静态属性和非静态属性。或静态成员变量和非静态成员变量。也可以叫做静态属性和实例属性。
按照是否为静态,Java中可以把方法分为:静态方法和非静态方法(又称实例方法)。static修饰的方法不允许被重写。父类和子类定义完全相同的两个方法,这是被允许的,但是这两个方法不满足重写,因为这两个方法都不是实例方法,都不属于对象(可以通过@Override注解进行验证)。
使用static修饰的属性在类被加载时加载到内存中,直到程序执行结束或引用类型赋值为null时才可能被回收。所以尽量少用静态属性。
2 语法
2.1 定义静态属性和静态方法
2.2 调用静态属性和静态方法
3 静态属性和非静态属性加载顺序
3.1 创建类
在类中包含静态属性和非静态属性。
有的属性赋值有的属性没有赋值
3.2 创建测试类
3.3 启动Debug
通过Debug会发现执行执行流程如下:
- 实例化类时会加载类中内容。声明对象时不会触发断点。
- 优先加载类中静态属性。然后才会实例化对象。
- 实例化对象时会把类中所有非静态属性赋默认值
- 加载赋值的非静态属性
- 执行构造方法
4 同类中方法调用静态属性
在Java中规定,在一个类中的静态方法和静态 - 静态方法只能调用静态属性
- 非静态方法可以调用静态属性
5 静态代码块
静态代码块:把多个静态属性进行赋值。因为是代码块,所以可以和方法一样,写逻辑代码(但是一般不写)。
静态代码块内部也可以定义变量,但是变量的有效范围只能是当前代码块,这点和局部变量是一样的。
5.1 语法
static{
}
5.2 代码示例
六、 抽象类
1 引入
既然Java中允许方法重写,一种极限情况就是父类的方法子类必须重写。这点和现实生活是一样。
例如:父类中(设定父类为人类)有一个测试打字速度方法,而子类中(子类可以是男人、女人、小孩、大人、学生、老师等)每个人的打字速度都是不一样的,所以子类需要重写父类的方法。所以:既然在写父类的时候就知道了这个方法需要被子类重写,那不如我们就强制限制子类必须重写这个方法。这种情况就可以使用抽象方法。
2 抽象方法
抽象方法需要使用abstract关键字修饰。因为抽象方法表示需要被子类重写的方法,所以提供方法体也没有意义。所以抽象方法没有方法体( 没有方法的大括号{})
2.1 代码示例
上面代码需要注意的是:
- abstract 需要写在返回值类型前面。允许写在访问权限修饰符前面,但是规范是写在访问权限修饰符后面。
- 由于抽象方法没有方法体,所以方法最后需要有分号
3 抽象类
Java中规定:具有抽象方法的类,必须是抽象类。抽象类不允许被实例化。
但是抽象类允许没有抽象方法。
当子类继承了抽象类后必须重写抽象方法,除非子类也是抽象类。
3.1 代码示例
上面代码注意:
- 抽象类中允许出现普通方法
- abstract修饰类时必须放在class关键字前面。允许abstract放在public前面,但是习惯都是放在public后面。
- 类中有抽象方法后,如果类没有abstract修饰,会报编译错误。
4 抽象类和普通类区别及相同点(常见面试笔试题)
区别:
抽象类不能被实例化。允许存在抽象方法。
普通类能被实例化。不允许存在抽象方法
相同点:
抽象类和普通类都允许存在普通方法。
抽象类虽然不能被实例化,但是允许存在构造方法。
七、 接口
1 简介
接口可以看做是一种极端的抽象类。它不允许有构造方法,不允许被实例化。
接口存在的意义就是制定规范。对于初学者来说,很难感受到接口的魅力,但是我们现在开发都是面向接口编程。即:由接口制定规范,在实现接口,重写方法。在后面我们学习JDBC或集合时,就是JDK提供的非常经典的接口使用场景。
由于Java中继承是单继承的,且会使类的耦合度较高。所以以后我们尽量多使用接口,少使用继承。
2 接口语法
2.1 定义接口
接口关键字interface
在Java SE 8之前接口中只允许有存在公共、静态常量属性(可以有多个)和公共、抽象方法(可以有多个)。
定义完成后,鼠标放在属性或方法前面灰色关键字上,会提示我们是冗余的。
也就是说推荐我们属性不写public static final。由编译器自动加上。方法不写public abstract,编译器自动加上。所以最终写法:
2.2 实现接口
实现接口的关键字是implements。
在Java中一个类可以实现多个接口,每个接口使用逗号分隔。
类实现接口必须重写接口中方法,除非这个类是抽象类。
实现接口的类称为:实现类。
3 接口之间的继承
接口可以继承其他接口。而且接口中继承是允许多继承的。继承后父接口的内容会被子接口完全继承。
注意:
如果父接口中存在同名属性,允许被继承。但是外部必须通过父接口调用指定属性。通过子接口调用会出现编译错误。
如果父接口中存在相同方法,允许被继承。子接口相当于只声明了一个方法。
4 JDK8中关于接口新特性
4.1 新增静态方法
4.2 新增default了关键字
当我们在接口中新增一个方法时,所有的实现类就必须重写这个方法。在JDK中很多类都是基于接口实现的。例如:我们后面学的集合,都是基于接口的。在Java版本更新时,想要在接口中添加方法,所有的实现类就必须重写这个方法。但是并不是所有的类都需要这个方法。所以Java 8开始为了解决这个问题推出了default关键字。(在Java 8 以前,我们会把接口中方法,拆分到多个接口中,类需要用哪些方法,就实现哪个接口)
从Java 8开始接口中的方法允许使用default修饰。default只能用在接口中。使用default修饰的方法,子类可以重写,也可以不重写。
4.2.1 定义含有default的接口
public可以省略,但是default不允许省略。
4.2.2 子类可以不重写default方法
4.2.3 子类也可以重写default方法
因为default关键字只能使用在接口中,所以实现类重写时,不能包含default
5 接口和抽象类的区别(常见面试笔试题)
接口:
- 实现类可以实现多个接口。
- 接口中只能包含public static final属性。
- 接口只能有抽象方法,静态方法,default修饰的方法。
- 接口不允许有构造方法。
- 接口可以多继承
- 不可以创建对象
抽象类: - 子类只能继承一个抽象类。
- 抽象类可以包含任意类型属性。
- 抽象类可以有普通方法,静态方法,抽象方法,但是不能有default修饰的方法。 4. 抽象类可以有构造方法。
- 不可以创建对