主页

适配器模式

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-09-21
设计模式

  1. 依赖倒置原则(DIP)

    • 高层模块(稳定)不应该依赖与低层模块(变化),二者都应该依赖与抽象。

    • 抽象(稳定)不应该依赖于实现细节(变化),实现细节应该依赖于抽象(稳定)。

  2. 开放封闭原则(OCP)

    • 对扩展开放,对更改封闭。
    • 类模块应该是可扩展的,但是不可以修改。
  3. 单一职责原则(SRP)

    • 一个类应该仅有一个引起他变化的原因。
    • 变化的方向隐含着类的责任。
  4. liskov替换原则(LSP)

    • 子类必须能够替换他们的基类(IS-A)。
    • 继承表达类型抽象。
  5. 接口隔离原则(ISP)

    • 不应该强迫客户程序依赖他们不用的方法。
    • 接口应该小而完备。
  6. 优先使用对象组成,而不是类继承(组合/聚合复用原则)

    • 类继承通常为“白箱复用”,对象组合通常为“黑箱复用”。
    • 继承某种程度上破坏了封装性,子类父类耦合度高。
    • 而对象组合则只要求对象具有良好定义的外部接口,耦合的相对较低。
  7. 迪米特法则

    • 一个对象应该对其他对象保持最少的了解。

方法区

2020-08-29
java

  • 各个线程共享的内存区域
  • 存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等

运行时常量池 #

  • 运行时常量池是方法区的一部分
  • Class文件中有一项是常量池表,这部分在类加载后存放到方法区的运行时常量池中

java堆

2020-08-29
java

  • java堆是被所有线程共享的一块内存区域
  • 几乎所有的对象实例及数组都在堆上分配

jvm栈

2020-08-29
java

  • jvm栈是线程私有的
  • 每个方法被执行的时候,java都会同步创建一个栈帧,用来存放局部变量表、操作数栈、动态连接、方法出口等信息
  • 每一个方法被调用直至完毕的过程,就是一个栈帧在虚拟机中从入栈到出栈的过程
  • 局部变量表存放了编译期间可知的各种java基本数据类型、对象引用和returnAddress(指向了一条字节码指令的地址)
    • 这些数据类型在局部变量表中存储空间以局部变量槽(slot)表示,64位的long和double会占用两个槽,其余的数据类型只占用一个。
    • 局部变量表所需的内存空间在编译期间完成分配。

collection和map

2020-07-29
java

Collection #

Map #

HashMap #

  • DEFAULT_INITIAL_CAPACITY = 1 << 4:默认初始容量为16,该容量必须为2的倍数
  • DEFAULT_LOAD_FACTOR = 0.75f:默认的加载因子,可以大于1
  • MAXIMUM_CAPACITY = 1 <<30:最大容量
  • TREEIFY_THRESHOLD = 8:由链表转换成树的阈值
  • UNTREEIFY_THRESHOLD = 6:由树转换成链表的阈值
  • MIN_TREEIFY_CAPACITY = 64

类加载机制

2020-07-21
java

类加载的过程 #

  • 加载
    • 通过一个类的全限定名来获取定义此类的二进制字节流。
    • 将这个字节流所代表的静态存储结构转化为方法去的运行时数据结构。
    • 在内存中生成一个代表这个类的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下的类库。
    • 程序中的默认类加载器。

双亲委派机制 #

  • 如果一个类收到类加载请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成。
  • 如果父类还有父类,则进一步向上委托,请求最终到达顶层的启动类加载器中。
  • 如果父类可以完成加载,就成功返回。否则,子类加载器才会尝试自己去加载。