JVM规范
如果try语句中有return,返回的是try语句块中的变量值,详细执行过程如下;
如果有返回值,就把返回值保存在局部变量中,打上断点,继续执行其它语句块
执行jsr指令,跳到finally语句块当中
执行完finally语句中的程序后,回到之前断点处,返回保存在局部变量表里的值
总的来说finally必定执行,不过finally中的变量操作不会影响try中被保存为局部变量的返回值,除非finally中也有return指令,这样一来忽略try中的return语句
JVM内存
一个java源程序首先会被编译成字节码文件,每个java程序都运行在自己的jvm上,然后告知jvm程序的运行入口,再被jvm通过字节码解释器加载运行。jvm每遇到一个线程会分配一个计数器、虚拟机栈、本地方法栈,这三者都是线程私有的,其周期与线程相同,线程结束时回收内存。
函数每次被调用时,在内存中都有自己的活动记录(activation record),称为栈空间(stack). Java 的方法在调用时在 JVM 栈中为其分配一个栈帧(Java栈空间的一个片段),可以称之为方法栈. 原则上,所有对象都在堆空间(Heap)中分配。
方法区
线程共享,存放所加载的类的信息、类中的静态变量、final常量、field信息、方法信息,该区域全局共享。
堆
线程共享
程序计数器
线程私有
虚拟机栈
线程私有
本地方法栈
线程私有
参考文献
jvm中一个字节以下的整形数据会在jvm启动时候加载进内存。
java是自动管理内存的,通常情况下程序运行到稳定状态,内存大小也达到一个稳定的值,但是内存泄漏导致Gc不能回收泄露的垃圾,内存不断变大,最终超出内存界限,抛出OutOfMemoryExpection
类的加载顺序
- 父类静态代码块(包括静态初始化块,静态属性,但不包括静态方法)
- 子类静态代码块(包括静态初始化块,静态属性,但不包括静态方法 )
- 父类非静态代码块( 包括非静态初始化块,非静态属性 )
- 父类构造函数
- 子类非静态代码块 ( 包括非静态初始化块,非静态属性 )
- 子类构造函数
初始化
立即初始化的情况
- 使用new关键字实例化对象的时候、读取或设置一个类的静态字段的时候,已经调用一个类的静态方法的时候。
- 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有初始化,则需要先触发其初始化。
- 当初始化一个类的时候,如果发现其父类没有被初始化就会先初始化它的父类。
- 当虚拟机启动的时候,用户需要指定一个要执行的主类(就是包含main()方法的那个类),虚拟机会先初始化这个类;
- 使用动态语言支持的时候
不会初始化的情况 - 子类引用父类的静态字段不会导致子类初始化
- 通过数值定义来引用类的初始化时候
- 常量在编译阶段会进行常量优化,将常量存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。
jdbc
JDBC提供了Statement、PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedStatement 用于执行参数化查询,而 CallableStatement则是用于存储过程。
对于PreparedStatement来说,数据库可以使用已经编译过及定义好的执行计划,由于 PreparedStatement 对象已预
编译过,所以其执行速度要快于 Statement 对象”
PreparedStatement可以阻止常见的SQL注入式攻击
Statement
普通的不带参数的SQL,批量更新、删除,每次执行时数据库都需要对sql进行编译。
PreparedStatement
可变参数的SQL,编译一次,执行多次。预编译的安全性好,有效防止Sql注入问题
CallableStatement
继承自PreparedStatement,支持调用存储过程,提供对输出、输出参数的支持
spring事务传播特性:
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:
propagation_requierd(需要):如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
propagation_supports(支持):支持当前事务,如果没有当前事务,就以非事务方法执行。
propagation_mandatory(强制):使用当前事务,如果没有当前事务,就抛出异常。
propagation_required_new(需要新建):新建事务,如果当前存在事务,把当前事务挂起。
propagation_not_supported(不支持):以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
propagation_never(绝不):以非事务方式执行操作,如果当前事务存在则抛出异常。
propagation_nested(嵌套):如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作
原文链接
Servlet与CGI
CGI
cgi(公共网关接口)是HTTP服务器与你或其它机器上的程序进行交互的工具,运行在网络服务器上,cgi程序常用来处理来自表单的输入信息,并在服务器产生相应的处理,cgi使得网页具有交互功能。
cgi处理过程
通过网络把用户请求发送到服务器
服务器接收请求并将请求交给cgi处理
cgi把处理结果返回给服务器
服务器把结果返回给用户
Servlet
服务器端的java运用程序,可以生成动态web页面,担当客户请求与服务器相应的中间层。
工作过程
客户端发送请求给服务器,服务器启动并调用servlet,servlet根据客户端请求生成响应内容并传给服务器。
两者比较
servlet效率更高、容易使用;传统CGI每个请求都要启动一个重量级的操作系统线程,Servlet中每个请求由一个轻量级的线程处理,通过多线程方式运行service方法,一个实例服务于多个请求。传统cgi对同一个cgi程序的并发请求处理方式是在内存当中重复装载n次cgi程序代码;而对于servlet,处理请求的是n个线程,所以只需要一份servlet类代码。
Servlet 生命周期
Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:
容器通过类加载器使用servlet类对应的文件加载servlet
调用servlet构造函数创建servlet对象
Servlet 初始化后调用 init () 方法。
Servlet 调用 service() 方法来处理客户端的请求。
Servlet 销毁前调用 destroy() 方法。
最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。
Struts工作原理
MVC为Model-View-Controller的缩写,是一种常用的设计模式。MVC减弱了业务逻辑接口和数据接口之间的耦合,以及让视图层更富于变化。
Struts是MVC的一种实现,它将Servlet和JSP标记用作实现的一部分。
Controller
有一个XML文件Struts-config.xml,与之相关联的是Controller,在Struts中,承担MVC中Controller角色的是ActionServlet。ActionServlet是一个通用的控制组件。提供了处理所有发送到 Struts的HTTP请求的入口点。它截取和分发这些请求到相应的Action的子类。另外控制组件也负责用相应的请求参数填充Action、From(通常称之为FromBean),并传给Action类(通常称之为ActionBean)。动作类实现核心商业逻辑,它可以访问JavaBean或调用EJB。最后Action类把控制权传给后续的JSP文件,后者生成视图。所有这些控制逻辑利用Struts-config.xml文件来配置。
视图:主要由JSP生成页面完成视图,Struts提供丰富的JSP 标签库: Html,Bean,Logic,Template等,这有利于分开表现逻辑和程序逻辑。
模 型:模型以一个或多个java bean的形式存在。这些bean分为三类:Action Form、Action、JavaBean or EJB。Action Form通常称之为FormBean,封装了来自于Client的用户请求信息,如表单信息。Action通常称之为ActionBean,获取从 ActionSevlet传来的FormBean,取出FormBean中的相关信息,并做出相关的处理,一般是调用Java Bean或EJB等。
流程:在Struts中,用户的请求一般以.do作为请求服务名,所有的.do请求均被指向 ActionSevlet,ActionSevlet根据Struts-config.xml中的配置信息,将用户请求封装成一个指定名称的 FormBean,并将此FormBean传至指定名称的ActionBean,由ActionBean完成相应的业务操作,如文件操作,数据库操作等。 每一个*.do均有对应的FormBean名称和ActionBean名称,这些在Struts-config.xml中配置。
核心:Struts的核心是ActionSevlet,ActionSevlet的核心是Struts-config.xml。
Struts 1与 Struts 2
Action类
Struts1要求Action类继承一个抽象类,Struts1使用抽象类编程而不是接口
Struts2可以实现Action接口也可以不实现,Struts2提供一个ActionSuport基类去实现常用接口。Action接口不是必须的,任何有execute的标识的
POJO都有可能成为struts2的Action的对象
线程模式
Struts1的Action是单例模式并且是线程安全的,仅有Action一个实例来处理所有请求。单策略模式限制了Struts1 Action能做的事。比且在开发时要
注意Action资源必须是线程安全比且是同步的。
Struts2的Action对象为每个请求产生一个实例,因此没有线程安全问题。
Servlet依赖
Struts1 Action依赖与Servlet API,因为当一个Action被调用时HttpServletRequest和HttpServletResponse被传递给execute方法。
Struts2 Action不依赖与容器,允许Action脱离容器被单独测试。如果需要,struts2依然可以访问初始的request和response。但是,其他的元素减
少或者消除了直接访问HttpServletRequest和HttpServletResponse的必要性。
可测性
测试Struts1 Action的一个主要问题是execute方法暴漏了Servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)
struts2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。
捕获输入
struts1使用ActionForm对象捕获输入。所有ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的基类不或输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有沉余的JavaBean)。
Struts2直接使用Acrtion属性作为输入属性,消除了对第二个输入对象的请求。输入属性可能是有自己(子)属性的Rich对象类型。Action属性能过通过web页面上的Taglibs访问。struts2也支持ActionForm模式。Richard对象类型,包括业务对象,能够用作输入/输出对象。这种ModelDriven特性简化了Taglib对POJO输入对象的引用。
表达式语言
Struts1整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很脆弱。
Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--“object graph Notation Language”(OGNL)
绑定值到页面(view)
Struts1使用标准JSP机制吧对象绑定到页面中来访问。
struts2使用ValueStack技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重同页面(view)
类型转换
Struts1 ActionForm属性通常都是String类型。struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的
struts2 使用OGNL进行类型转换,提供基本和常用对象的转换器。
效验
Struts1支持在ActionForm的validate方法中手动效验,或者通过Commons Validator的扩展来效验。同一个类可以有不同的效验内容,但不能效验子对象。
Struts2支持通过validate方法和XWork效验框架进行效验。XWork效验框架使用为属性类类型定义的效验和内容效验,来支持Chain效验子属性。
Action执行的控制
Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。
struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不能的生命周期。堆栈能够根据需要和不同的Action一起使用。
forword 与redirect
forward
请求转发,属于服务器行为,本质上是同一个请求,地址栏不变。
redirect
请求重定向,属于客户端行为,本质上是两次请求,地址栏改变。
加载驱动程序的方法
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver");
jdbc使用详细案例
java多线程
java的多线程是抢占机制(不是分时机制),即是说多个线程处于可运行状态,但也只有一个线程在运行。
sleep()与wait()的区别
sleep()
线程类Thread的方法,不释放对象锁,作用是暂停线程,但监控状态仍然保持,结束后自动恢复
wait()
Object类的方法,对象调用时线程放弃对象锁,进入等待此对象的等待锁定持,只有针对此对象发出notify或notifyAll方法后本线程才进入对象锁定池准备获取对象锁进入运行状态(此时处于就绪状态)
异常
运行时异常
都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
非运行时异常 (编译异常)
是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
JSP
静、动态include
静态的include:是jsp的指令来实现的,<% @ include file="xx.html"%> 特点是 共享request请求域,先包含再编译,不检查包含页面的变化,静态include的结果是把其它jsp引入到当前jsp。
动态的include:是jsp动作来实现的,<jsp:include page="xx.jsp" flush="true"/> 这个是不共享request请求域,先编译在包含,是要检查包含页面的变化的,动态include的结构是两者独立,输出时才合并。
AWT与Swing
AWT:基于本地方法的C/C++程序,运行速度快,通过调用操作系统的native方法实现,AWT所提供的图形功能是各种通用型操作系统所提供的图形功能的交集,以此实现“一次编译,到处运行”的概念。
Swing:纯java所写,基于AWT的Java程序,运行速度较慢,对AWT的功能进行了大幅度扩充,且Swing在所有平台表现一致。
在实际运用中使用AWT还是Swing取决于应用程序所部署的平台类型,例如
- 对于一个嵌入式应用,目标平台的硬件资源往往非常有限,而应用程序的运行速度又是项目中至关重要的因素。在这种矛盾的情况下,简单而高效的AWT当然成了嵌入式Java的第一选择。
- 在普通的基于PC或者是工作站的标准Java应用中,硬件资源对应用程序所造成的限制往往不是项目中的关键因素。所以在标准版的Java中则提倡使用Swing, 也就是通过牺牲速度来实现应用程序的功能。
Spring特性
参考文章
Spring的核心特性控制反转和面向切面编程。
IOC控制反转(别名:DI依赖注入)
概念
获得依赖对象的过程反转了,由主动转为了被动,由自身管理转为IOC容器运行期间动态的将依赖关系注入到对象中。
面向对象的编程使得大型项目当中,对象的耦合程度非常高,牵一发而动全身。
而控制反转的理念既是把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部透明,降低了解决问题的复杂度,可以灵活的重用、扩展。
IOC理论的观点大致为:借助于”第三方“实现具有依赖关系的对象之间的解耦。
IOC容器便是引入的第三方。控制反转指的是将依赖具体实现的控制权由主动转为被动。引入IOC容器之前,每当对象A需要具体体现与B的依赖关系的时候都需要自行创建、使用对象B,控制权在A自己手上。引入IOC容器之后,容器会在每当对象A需要依赖B的时候自动将容器中创建好的对象B注入到对象A中。
IOC原理的实现
利用反射特性进行编程,根据给出类名动态的生成对象。其它细节还有:IOC把以前在工厂方法中写死的对象生成代码,改变为由配置文件来定义,把工厂和对象生成独立开来,提高了灵活性和可维护性。
AOP面向切面编程
面向对象编程OOP的补充和完善,OOP通过封装、继承、多态很好的建立了纵向的对象层次结构;AOP将那些与业务无关却被业务模块共同调用散布在各处的逻辑封装起来(命名为Aspect),减少系统的重复代码,是OOP横向上的补充。
AOP原理实现
具体操作便是将共同的逻辑、方法通过Spring注入到接口调用的某个地方。
Spring中AOP代理由IOC容器负责管理、生成,其依赖也由IOC容器负责管理,关于AOP,程序员只需要定义普通业务组件、定义切入点、定义增强处理(AOP框架为普通业务组织注入的处理动作)
Java内存模型
java 内存模型规定了所有的变量都存储在主内存中,但是每个线程会有自己的工作内存,线程的工作内存保存了该线程中使用了的变量(从主内存中拷贝的),线程对变量的操作都必须在工作内存中进行,不同线程之间无法直接访问对方工作内存中的变量,线程间变量值从传递都要经过主内存完成
什么是原子性
一个操作是不可中断的,要么全部执行成功要么全部执行失败,比如银行转账
什么是可见性
当多个线程访问同一变量时,一个线程修改了这个变量的值,其他线程就能够立即看到修改的值
什么是有序性
程序执行的顺序按照代码的先后顺序执行
int a = 0;
int b = 2;
像这2句代码第一句会比第二局先执行,但是jvm在真正执行时不一定是第一句在第二句之前,这里涉及一个概念叫做指令重排,处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。比如上面的代码谁先执行对最终的程序结果并没有影响,那么就有可能在执行过程中,语句2先执行而语句1后执行。
在指令重排时会考虑指令之间的数据依赖性,比如2依赖了1的数值,那么处理器会保证1在2之前执行。
但是在多线程的情况下,指令重排就会有影响了。
volatile到底做了什么
- 禁止了指令重排
- 保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量值,这个新值对其他线程是立即可见的
- 不保证原子性(线程不安全)
其它
在一个含有基本数据类型的比较语句中,比较的时候比较的是数值。