一、final关键字
final是最终的意思,可以修饰类,变量,方法
1.final修饰的特点:
- 修饰类:表明该类是最终类,不能被继承
- 修饰方法:表明该方法是最终方法,不能被重写
- 修饰变量:表明该变量是常量,该变量在第一次赋值后,不能再次被赋值
2.final修饰变量应注意:
- 变量是基本类型:基本变量的数据值不能发生修改
- 变量是引用类型:引用类型的地址值不能发生改变,但是对象中封装的数据值是可以修改的
- 修饰局部变量是可以先定义后赋值,修饰成员变量时必须定义时赋值或者在构造方法中赋值
二、抽象类
1.定义格式:
权限修饰符 abstract class 类名{}
2.抽象方法的定义格式:
修饰符 abstract 返回值类型 方法名(参数列表);
注意:
①有抽象方法的类一定是抽象类,而抽象类中可以没有抽象方法。
②抽象类只有被子类继承后,重写抽象方法才有意义。
3.抽象类的特点:
- 抽象类无法创建对象
- 抽象类可以没有抽象方法,但有抽象方法的类一定是抽象类
- 子类继承抽象类:要么重写所有抽象方法,要么子类也定义为抽象类
4.抽象类与普通类的区别
①得到定义抽象方法的能力,但失去创建对象的能力
②除此之外,普通类有的抽象类具备
5.抽象类案例
系统需求:
某加油站推出了2种支付卡,一种是预存10000的金卡,后续加油享受8折优惠。
另一种是预存5000的银卡 ,后续加油享受8.5折优惠。
请分别实现2种卡片进入收银系统后的逻辑,卡片需要包含卡号,余额,支付功能 。
分析:
金卡和银卡有相同的属性,相同的支付功能,但是实际支付算法不同。可以把多个类中的相同属性和方法抽象到父类中,而由于方法的具体实现不同,所以可以在父类中定义成抽象方法,让子类继承后重写。
实现:
创建一个抽象卡类(Card),提供卡号(id),余额(balance),抽象的支付方法(pay)。
创建一张金卡类(GoldenCard):重写支付功能,按照原价的8折计算输出。
创建一张银卡类(SilverCard):重写支付功能,按照原价的8.5折计算输出。
/创建一个抽象卡类(Card),提供卡号(id),余额(balance),抽象的支付方法(pay)。
public abstract class Card {
private String id; //卡号
private double balance; //余额
public Card() {
}
public Card(String id, double balance) {
this.id = id;
this.balance = balance;
}
//抽象的支付方法(pay)。
//double money 加油的金额
public abstract void pay(double money);
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
/金卡
public class GoldenCard extends Card{
public GoldenCard(){}
public GoldenCard(String id, double balance){
super(id,balance);
}
//重写支付功能,按照原价的8折计算输出。
@Override
public void pay(double money) {
System.out.println("支付成功");
System.out.println("原价:"+money);
double pay = money*0.8;
System.out.println("折扣价:"+pay);
double newBalance = getBalance() - pay;
System.out.println("余额:"+newBalance);
//更新余额
setBalance(newBalance);
}
}
//银卡
public class SilverCard extends Card{
public SilverCard() {
}
public SilverCard(String id, double balance) {
super(id, balance);
}
//重写支付功能,按照原价的8.5折计算输出。
@Override
public void pay(double money) {
System.out.println("支付成功");
System.out.println("原价:"+money);
double pay = money*0.85;
System.out.println("折扣价:"+pay);
double newBalance = getBalance() - pay;
System.out.println("余额:"+newBalance);
//更新余额
setBalance(newBalance);
}
}
import java.util.Scanner;
public class test {
public static void main(String[] args) {
GoldenCard g = new GoldenCard("vip001", 10000);
Scanner sc = new Scanner(System.in);
System.out.println("请输入支付金额:");
double money = sc.nextDouble();
g.pay(money);
System.out.println(g.getBalance());
}
}
6.面试题: 抽象方法能否被private, static, final这些关键字修饰?
抽象方法存在的意义被子类继承和重写。
private方法不能被重写,
static方法可以被继承,但是也不能被重写
final方法表示最终方法,不能被重写
private, static, final修饰的方法都不能被重写,所以和抽象方法存在的意义冲突,所以不能和abstract一起使用
三、设计模式
1.设计模式是什么?
- 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
- 使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、重用性。
2.模板方法模式
- 规定一个操作的基本流程,而将某些实现细节定义成抽象方法。
- 子类通过重写抽象方法,并调用从父类继承而来的模板方法即可。
3.模板方法的优点
①规范了不变的流程部分,扩展了可变的细节部分。
②提取公共代码,利于后期维护。
4.模板方法举例:医生看病
引入:
通常来说,医生看病的流程都是固定的:登记,检查病因、开单、抓药。
对传统中医来说,检查病因的方式通常是“望闻问切”了解病况,而西医则是根据化验报告了解病因。
分析:
因为总体的看病流程是相同的,此时可以定义一个方法控制流程,而检查病因的步骤可以定义成抽象方法,由子类实 现。这就是模板方法的体现。
//模板类
public abstract class Doctor {
//规定看病的流程,模板方法
public final void work(){
//医生看病的流程都是固定的:登记,检查病因、开单、抓药。
System.out.println("登记");
checkBody();
System.out.println("开单");
System.out.println("抓药");
}
//细节部分,定义成抽象方法,由子类去重写
public abstract void checkBody();
}
public class ChinaDoctor extends Doctor{
@Override
public void checkBody() {
System.out.println("中医看病,望闻问切检查病因...");
}
}
public class WestDoctor extends Doctor{
@Override
public void checkBody() {
System.out.println("西医通过化验,拍片,根据检查报告发现病因");
}
/* @Override
public void work() {
super.work();
System.out.println("收小费");
}*/
}
/*
目标:掌握模板方法设计模式。
模板方法:
规定一个操作的基本流程,而将某些实现细节定义成抽象方法。
子类通过重写抽象方法,并调用从父类继承而来的模板方法即可。
*/
public class Demo1 {
public static void main(String[] args) {
ChinaDoctor c = new ChinaDoctor();
c.work();
WestDoctor w = new WestDoctor();
w.work();
}
}
四、接口
1.接口的概述
①什么是接口?
- 接口是比抽象类更加彻底的抽象,体现了现实世界中“如果你是这类事物,则必须具备某些行为”的思想。
- Java接口主要是对功能的描述和规范,接口中全都是抽象方法(JDK8之前)。
②接口的重要意义
- 接口多用于约束和统一功能,一个接口体现的是能做什么,而不关心怎么做。
- 接口可以提高程序的扩展性和维护性
2.接口的定义和特点
①接口的定义:
java 使用 interface关键字定义接口
java 使用 interface关键字定义接口
格式:
权限修饰符 interface 接口名{
}
注意:接口的权限修饰符只能是public或者缺省(不写)
②接口的成员特点
- jdk7及之前,接口中只能定义常量和抽象方法不能有其他的成分
- 接口中没有构造方法,所以不能创建对象
- 常量:默认都是public static final修饰的,可以省略不写
- 抽象方法:默认都是public abstract修饰的,可以省略不写
3.接口和类的关系
- 接口是用来被类实现的,实现接口的类被称为实现类
- 一个类可以实现多个接口,实现关键字为Implement
格式 :
权限修饰符 class 类名 implement 接口1,接口2,接口3{
}
注意:一个类实现接口,必须重写接口的所有抽象方法,否则这个类要定义成抽象类
4.接口与接口的关系
-
接口的多继承:
接口和接口是多继承的关系,一个接口可以同时继承多个接口。
格式: 权限修饰符 interface 接口名 extends 接口1, 接口2, 接口3{ }
-
接口多继承的作用
规范合并,整合多个接口为同一个接口,便于子类实现。
5.JDK8开始接口新增方法
从JDK8开始,接口中新增了三种非抽象方法。
① 默认方法
- 方法必须用default修饰,权限默认是public,可以省略不写。
- 需要用接口的实现类对象来调用。
②静态方法
- 方法使用static修饰,权限默认public,可以省略不写。
- 注意:接口的静态方法必须用接口名来调用。
③静态方法
- DK9开始,新增private修饰的私有方法,可以是私有实例方法和私有静态方法。
- 私有方法只能在接口内被其他方法访问。
6.接口使用的注意事项
①子类继承父类并实现接口:
- 当一个类,既继承父类,又实现接口时,父类中的成员方法与接口中的默认方法相同,子类就近选择执行父类的成员方法。
② 类实现多个接口:
- 实现的多个接口有相同的抽象方法时,实现类只需要重写一次。
- 实现的多个接口有相同的默认方法时,实现类需要重写该默认方法。(继承多接口也一样)
- 实现的多个接口有相同的静态方法时,使用不会冲突,因为静态方法通过各自的接口名调用。
7.接口的设计思路
- 如果要一些类对象必须完成某些功能,则可以使用接口定义抽象方法,让类必须实现接口。(规范功能)
- 如果接口大面积更新方法,又不想去修改每一个实现类,可以将更新的方法设计为默认方法。
- 希望默认方法调用的更加简洁,可以考虑设计为static静态方法。
- 默认方法中出现了重复的代码,可以考虑抽取出一个私有方法。
五、面试题
接口和抽象类类的区别?
语法:
1.接口和抽象类都可以定义抽象方法。
2.接口和抽象类都不能创建对象。
3.抽象类可以定义成员变量,构造方法。
4.接口中的变量只能是public static final修饰的常量,接口不能有构造方法。
作用:
1.抽象类可以被子类继承,而且只能单继承。
2.接口可以被子类实现,而且支持多实现;接口也可以被其他接口继承,而且是多继承。
设计思想:
1.抽象类是对子类共同特征的抽取,可以将多个子类中相同的属性和行为抽取到父类中,
某些实现细节定义成抽象方法,子类可以继承和重写,以达到简化代码,复用功能的目的。
2.接口是对功能的统一和约束,实现接口的目的是为了扩展类的功能。
理论上,一个类实现的接口越多,该类具备的方法就越多。