2020-09-21
- 模式定义:将一个类的接口转换为客户程序希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作。
- 适用环境:希望复用一些现存的类,但是接口又与复用环境要求不一致的情况。在遗留代码复用、类库迁移等方面非常有用。
- 实现结构:对象适配器和类适配器(采用多继承实现,一般不推荐使用)。
案例
#
//老接口
interface OldTarget{
public int bar();
public void foo(int data);
}
//一个实现了老接口的类
class OldClass implements OldTarget{
public int bar(){
//...
}
public void foo(int data){
//...
}
}
//新接口
interface NewTarget{
public void process();
}
//对象适配器
class Adapter implements NewTarget{
private OldTarget oldTarget;
public Adapter(OldTarget oldTarget){this.oldTarget=oldTarget;}
public void process(){
int tmp=bar;
foo(tmp);
}
}
public static void main(String[] args){
OldTarget ot=new OldClass();
//通过该适配器就将一个旧的接口转换成了一个新的接口
NewTarget nt=new Adapter(ot);
nt.process();
}
2020-07-21
类加载的过程
#
- 加载
- 通过一个类的全限定名来获取定义此类的二进制字节流。
- 将这个字节流所代表的静态存储结构转化为方法去的运行时数据结构。
- 在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
- 验证
- 确保Class文件的字节流对象中包含的信息符合当前虚拟机的要求,并且不会危虚拟机自身的安全。
- 准备
- 准备阶段是正式为类变量分配内存并设置类变量初始值(零值)的阶段,这些类变量使用的内存都将在方法区进行分配。
- 如果类变量同时也被final修饰了,那它就是一个常量,准备阶段就会被初始化为代码中指定的值。
- 解析
- 将常量池内的符号引用替换为直接引用的过程。
- 符号引用:以一组符号来描述所引用的目标,符号可以是任何形式的字面量,只要使用时能无歧义地定位到目标即可。
- 直接引用:可以是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。
- 初始化
- 初始化时执行类构造器clinit的方法的过程。
- clinit方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块static{}中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的。
- 定义在静态语句块之后的类变量,在该静态语句块中可以赋值,但不能访问。
class Main{
static{
i=0; //正常编译通过
System.out.println(i); //这句编译器会提示非法向前引用
}
static int i=1;
}
类加载器
#
- 启动类加载器Bootstrap ClassLoader
- 用来加载Java的核心类库(JAVA_HOME\lib目录或者被-Xbootclasspath参数所指定的路径中)。
- 没有父类加载器
- 加载扩展类和应用程序类加载器,并指定为它们的父类加载器。
- 扩展类加载器Extension ClassLoader
- 派生于ClassLoader,父类为Bootstrap。
- 从java.ext.dirs系统变量所指定的路径中加载所有类库。
- 应用程序类加载器Application ClassLoader
- 派生于ClassLoader,父类为扩展类加载器。
- 负责加载classspath下的类库。
- 程序中的默认类加载器。
双亲委派机制
#
- 如果一个类收到类加载请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成。
- 如果父类还有父类,则进一步向上委托,请求最终到达顶层的启动类加载器中。
- 如果父类可以完成加载,就成功返回。否则,子类加载器才会尝试自己去加载。