栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈的栈元素。
栈帧存储了方法的局部变量表,操作数栈,动态连接和方法返回地址等信息。每一个方法调用从开始至执行完成,都对应着一个栈帧在虚拟机栈里面入栈到出栈的过程。
一个线程的方法调用链可能会很长,很多方法同时处于执行状态,在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧。所有字节码指令都是围绕当前栈帧进行操作。
局部变量表用于存放方法参数和方法内定义的局部变量。
操作数栈是一个先入后出的栈。当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,执行过程中,各种字节码指令回往操作数栈中写入和提取内容,也就是入栈/出栈操作。
方法返回地址,当一个方法开始执行后,只有两种方式可以退出这个方法。第一种是执行引擎遇到任意一个方法返回的字节码指令(正常返回),另一种是遇到了异常(异常返回)。无论采用哪种退出方式,只要在方法退出后,都要返回方法被调用的位置,这样方法才能继续执行。
静态分派:重载
Human man = new Man();
我们把Human称为变量的静态类型,后面的Man为变量的实际类型。虚拟机在重载时是通过参数的静态类型而不是实际类型作为判断依据,并且静态类型是编译期可知的。因此,Javac编译器会根据参数的静态类型决定使用哪个重载版本。
所有依赖静态类型来定位方法执行版本的分派动作称为静态分配。静态分配的典型是方法重载。
静态分派发生在编译阶段,因此静态分派的动作实际上不是有虚拟机来执行的。编译器选择的重载版本并不是唯一的,而是确定一个更加合适的版本。
动态分派:重写
动态分派和重写有着密切的关联。重写时会根据实际类型来作为判断依据。
Tomcat:正统的类加载器架构
一个主流的或者叫功能健全的Web服务器要解决如下几个问题:
部署在同一个服务器上的两个Web程序使用的Java类库可以实现相互隔离。
部署在同一个服务器上的两个Web应用程序所使用的Java类库可以共享。
服务器需要尽可能的保证自身的安全不受部署的Web应用程序的影响。
所以在部署Web应用时,单独的一个ClassPath就无法满足需求了,所以Web服务器都不约而同的提供了好几个ClassPath路径供用户存放第三方类库,这些路径一般以lib 或 classes 命名。
Tomcat目录结构中,有三组目录,commom,server,shared可以存放java类库,另外可以加上web应用程序自身目录/WEB-INF/,一共四组。
common可以被Tommcat和所有的Web应用程序共同使用。
server目录可以被Tomcat使用,但对于Web应用程序不可见。
shared可以被所有的Web应用程序共同使用,但是对Tomcat自己不可见。
WEB-INF仅仅可以被此Web应用程序使用。
OSGi中,Bundle之间的依赖关系从传统的上层依赖底层变为平级模块之间的依赖,而且类库的可见性能得到非常准确的控制,一个模块里只有被Export过得Package才能由外界访问,其他会被隐藏起来。
OSGi的Bundle类加载器之间只有规则,没有固定的委派关系。所有对于某个Package的类的加载动作都会委派给发布它的Bundle类加载器去完成。
动态代理中的所谓“动态”,是针对使用Java代码实际编写了代理类的“静态”代理而言的,他的优势不在于省去了编写代理类的那一点工作量,而是实现了可以在原始类和接口还未知的时候,就确定代理类的行为,可以灵活的重用于不同的应用场景之中。