目录
1. 接口
- 接口的定义使用interface 。
- 接口无法被实例化,也就是不可以new一个接口的实例。
- 接口不能包含属性(也就是成员变量)。
- 接口只能声明方法,方法不能包含代码实现。
- 类实现接口的时候,必须实现接口中声明的所有方法。
示例:定义了一个 Filter 接口。AuthencationFilter 和 RateLimitFilter 是接口的两个实现类,分别实现了对 RPC 请求鉴权和限流的过滤功能。
// 接口
public interface Filter {
void doFilter(RpcRequest req) throws RpcException;
}
// 接口实现类:鉴权过滤器
public class AuthencationFilter implements Filter {
@Override
public void doFilter(RpcRequest req) throws RpcException {
//...鉴权逻辑..
}
}
// 接口实现类:限流过滤器
public class RateLimitFilter implements Filter {
@Override
public void doFilter(RpcRequest req) throws RpcException {
//...限流逻辑...
}
}
// 过滤器使用Demo
public class Application {
// filters.add(new AuthencationFilter());
// filters.add(new RateLimitFilter());
private List<Filter> filters = new ArrayList<>();
public void handleRpcRequest(RpcRequest req) {
try {
for (Filter filter : filters) {
filter.doFilter(req);
}
} catch(RpcException e) {
// ...处理过滤结果...
}
// ...省略其他处理逻辑...
}
}
2.抽象类
- 抽象类不允许被实例化,只能被继承。也就是说,你不能 new 一个抽象类的对象出来。
- 抽象类可以包含属性和方法。
- 子类继承抽象类,必须实现抽象类中的所有抽象方法。
示例:Logger 是一个记录日志的抽象类,FileLogger 和 MessageQueueLogger 继承 Logger, 分别实现两种不同的日志记录方式:记录日志到文件中和记录日志到消息队列中
// 抽象类
public abstract class Logger {
private String name;
private boolean enabled;
private Level minPermittedLevel;
public Logger(String name, boolean enabled, Level minPermittedLevel) {
this.name = name;
this.enabled = enabled;
this.minPermittedLevel = minPermittedLevel;
}
public void log(Level level, String message) {
boolean loggable = enabled && (minPermittedLevel.intValue() <= level.intValue());
if (!loggable) return;
doLog(level, message);
}
protected abstract void doLog(Level level, String message);
}
// 抽象类的子类:输出日志到文件
public class FileLogger extends Logger {
private Writer fileWriter;
public FileLogger(String name, boolean enabled,
Level minPermittedLevel, String filepath) {
super(name, enabled, minPermittedLevel);
this.fileWriter = new FileWriter(filepath);
}
@Override
public void doLog(Level level, String mesage) {
// 格式化level和message,输出到日志文件
fileWriter.write(...);
}
}
// 抽象类的子类: 输出日志到消息中间件(比如kafka)
public class MessageQueueLogger extends Logger {
private MessageQueueClient msgQueueClient;
public MessageQueueLogger(String name, boolean enabled,
Level minPermittedLevel, MessageQueueClient msgQueueClient) {
super(name, enabled, minPermittedLevel);
this.msgQueueClient = msgQueueClient;
}
@Override
protected void doLog(Level level, String mesage) {
// 格式化level和message,输出到消息中间件
msgQueueClient.send(...);
}
}
3.什么时候用接口和抽象类
- 如果要表示一种 is-a 的关系,并且是为了解决代码复用问题,我们就用抽象类;如果要表示一种 has-a 关系,并且是为了解决抽象而非代码复用问题,那我们就用接口。
- 从类的继承层次上来看,抽象类是一种自下而上的设计思路,先有子类的代码重复,然后再抽象成上层的父类(也就是抽象类)。而接口正好相反,它是一种自上而下的设计思路。我们在编程的时候,一般都是先设计接口,再去考虑具体的实现。
4.静态内部类
- 静态内部类,是类中使用static 修饰的类
- 可以有访问控制符,静态内部类和静态方法,都是类的静态组成部分
示例:使用静态内部类实现单例模式
public class UserSingleton {
/** 私有化构造器 */
private UserSingleton() {
}
/** 对外提供公共的访问方法 */
public static UserSingleton getInstance() {
return UserSingletonHolder.INSTANCE;
}
/** 写一个静态内部类,里面实例化外部类 */
private static class UserSingletonHolder {
private static final UserSingleton INSTANCE = new UserSingleton();
}
}
5.成员内部类:
- 在类中直接定义类
- 不可以包含任务静态的成分,否则会造成内外部初始化问题
- 可以有访问控制符,成员内部类和成员方法,成员变量一样,都是类的组成部分
class Person {
class student { //内部类
}
}
6.局部内部类:
- 在类中的方法中直接定义类
- 不可以包含任何静态的成分,比如静态方法,静态变量,静态内部类,否则会造成内外部类初始化问题
- 不可以有访问控制符,局部内部类和成员方法,成员变量一样,都是类的组成部分
class Person1 {
public Person1(){
class student { //内部类
}
}
}
7.匿名类
- 匿名类是用来创建接口或者抽象类的实例
- 可以出现在任何有代码的地方
class Test{
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
System.out.println("名内部类方式使用多线程");
}
}.start();
}
}