抽象类
1. 抽象类的特点
- 关键字:abstract
- 抽象类不能实例化
- 抽象类有构造器
- 抽象类只能单继承
- 抽象方法只有方法的声明,没有方法体。
2. 抽象类的匿名子类
/**
* 抽象类
*/
public abstract class Person {
public Person(){
talk();
}
public abstract void talk();
}
/**
* 匿名子类对象
*/
public class DemoTest01 {
public static void getInstance(Person p){
System.out.println(p);
}
public static void main(String[] args) {
//方式一:
Person p=new Person(){
@Override
public void talk(){
System.out.println("this is Overwrite talk method");
}
};
//方式二:
getInstance(new Person(){
@Override
public void talk(){
System.out.println("this is Overwrite talk method");
}
});
}
}
3. 抽象类的应用:模板方法设计模式-TemplateMethod
案例1:计算某段代码执行,需要花费的时间
/**
* 模板抽象类
*/
public abstract class TemplateTest {
public void spendTime(){
long startTime = System.currentTimeMillis();
code();//不确定的部分。易变的部分。
long endTime=System.currentTimeMillis();
System.out.println("花费的时间是:" + (endTime-startTime));
}
/**
* 需要子类重写的方法
*/
public abstract void code();
}
public class SubTemplate extends TemplateTest {
@Override
public void code() {
//1000以内的质数
for (int i = 2; i < 1000; i++) {
boolean isFlag=true;
for (int k = 2; k < Math.sqrt(i); k++) {
if(i%k==0){
isFlag=false;
break;
}
}
if(isFlag){
System.out.println(i+" 是一个质数");
}
}
}
}
//测试
public static void main(String[] args) {
TemplateTest t1 = new Subtemplate();
t1.spendTime();
}
案例2:银行办理不同的业务
public class TemplateMethodTest {
public static void main(String[] args) {
BankTemplateMethod btm = new DrawMoney();
btm.process();
BankTemplateMethod btm2 = new ManageMoney();
btm2.process();
}
}
/**
* 模板抽象类
*/
abstract class BankTemplateMethod {
// 具体方法
public void takeNumber() {
System.out.println("取号排队");
}
public abstract void transact(); // 办理具体的业务。钩子方法
public void evaluate() {
System.out.println("反馈评分");
}
// 模板方法,把基本操作组合到一起,子类一般不能重写
public final void process() {
this.takeNumber();
this.transact();// 回调方法。像个钩子,具体执行时,挂哪个子类,就执行哪个子类的实现代码
this.evaluate();
}
}
class DrawMoney extends BankTemplateMethod {
public void transact() {
System.out.println("我要取款!!!");
}
}
class ManageMoney extends BankTemplateMethod {
public void transact() {
System.out.println("我要理财!我这里有2000万美金!!");
}
}
接口
1. 接口的特点
- 关键字:interface
- 接口中没有构造器
- 接口可以继承多个接口。
- 类可以实现多个接口。
- 接口中的变量都是全局常量。
- 接口中的方法,都是public修饰的。
- 接口是一种规范。
2. 接口中的成员
- 全局常量 public static final
- 抽象方法 public abstract
- 静态方法 public static
- 默认方法 public default
- 私有方法-Java9新特性
[1] 全局常量
public static final 数据类型 大写变量名;
[2] 抽象方法
public abstract 返回值类型 方法名( );
[3] 静态方法
public static 返回值类型 方法名( );
接口中的静态方法,只能通过接口调用。类似工具类。
[4] 默认方法
public default 返回值类型 方法名( );
-
接口中的默认方法,可以通过实现类的对象来调用
-
实现类可以重写接口的默认方法,调用的是重写后的方法
-
如果接口和父类存在同名同参数的默认方法,默认调用的是父类中的方法
-
如果实现了多个接口,多个接口中存在同名同参数的默认方法,并且父类中没有此同名同参数的默认方法,实现类必须重写该方法。
-
调用父类中的方法: super.方法名( );
调用子类自己重写的方法: this.方法名( );
调用接口中的默认方法:接口名称.super.默认方法名( );
[5] 私有方法 - Java9新特性
将接口中重复的代码封装起来,只提供接口内部使用。
3. 解决接口冲突问题
子类实现了多个接口,并且多个接口中存在同名同参数的默认方法,父类中又没有此同名同参数的方法,子类如果没有重写此方法,编译会报错。引发接口冲突问题。
4. 接口的应用
代理模式 - Proxy
静态代理
针对某一个接口,提供的代理类。
案例1:访问网络
/**
* 网络接口
*/
public interface NetWork {
/**
* 浏览网页
*/
public abstract void browse();
}
/**
* 被代理类
*/
public class Server implements NetWork {
@Override
public void browse() {
System.out.println("服务器正在浏览");
}
}
/**
* 代理类
*/
public class ProxyServer implements NetWork {
private NetWork netWork;
public ProxyServer(NetWork netWork) {
this.netWork = netWork;
}
/**
* 连接网络校验
*/
private void check(){
System.out.println("连接网络之前的校验操作");
}
@Override
public void browse() {
check();
netWork.browse();
}
}
//测试
public static void main(String[] args) {
NetWork netWork=new ProxyServer(new Server());
netWork.browse();
}
动态代理
JDK自带的动态代理。使用反射技术。
在代码执行过程中,动态生成代理类的对象。
工厂方法模式 - Factory
- 创建者与调用者的分离
- 用来生产同一等级结构中的固定产品。(支持增加任意产品)
案例1:生产汽车
汽车接口 和 实现的汽车接口的类
/**
* 汽车种类的接口
*/
public interface Car {
void run();
}
public class AuDi implements Car {
@Override
public void run() {
System.out.println("奥迪正在跑...");
}
}
public class BYD implements Car {
@Override
public void run() {
System.out.println("比亚迪正在跑...");
}
}
汽车工厂的接口 和 实现汽车工厂的类
/**
* 生产汽车的接口
*/
public interface ProductCarFactory {
Car getCar();
}
public class AuDiFactory implements ProductCarFactory {
@Override
public Car getCar() {
return new AuDi();
}
}
public class BYDFactory implements ProductCarFactory {
@Override
public Car getCar() {
return new BYD();
}
}
测试
public static void main(String[] args) {
//从工厂中获取汽车的对象
Car AuDi = new AuDiFactory().getCar();
Car BYD = new BYDFactory().getCar();
AuDi.run();
BYD.run();
}
5. 接口的练习
/**
* 比较大小的接口
*/
public interface CompareObject {
/**
* @param o
* @return
* 若返回值是 0 , 代表相等;
* 若为正数,代表当前对象大;
* 负数代表当前对象小
*/
public int compareTo(Object o);
}
/**
* 圆的类
*/
public class Circle {
private Double radius;
public Circle() {
}
public Circle(Double radius) {
this.radius = radius;
}
//get and set method...
}
/**
* 继承圆,并实现比较大小接口的方法
*/
public class ComparableCircle extends Circle implements CompareObject {
public ComparableCircle(Double radius) {
super(radius);
}
@Override
public int compareTo(Object o) {
if(this==o){
return 0;
}
if(o==null || !(o instanceof Circle)){
throw new RuntimeException("传入的数据类型不匹配。不是一个圆!");
}
Circle c=(Circle)o;
return Double.compare(this.getRadius(),c.getRadius());
}
}
//测试
public static void main(String[] args) {
ComparableCircle c1 = new ComparableCircle(3.6);
ComparableCircle c2 = new ComparableCircle(3.6);
int result=c1.compareTo(c2);
if(result>0){
System.out.println("c1面积大");
}else if(result==0){
System.out.println("面积相等");
}else{
System.out.println("c2面积大");
}
}
6. 抽象类和接口的异同
相同点:
- 抽象类和接口都不能实例化
- 都可以定义抽象方法
不同点:
- 抽象类只能单继承,接口可以继承多个接口
- 抽象类有构造器,子类创建对象时,会调用父类中的构造器。接口没有构造器
- 抽象类是一种模板,接口是一种规范