heap与stack的区别
堆:
1、heap 2、空间是手动申请和释放 3、和队列一样,先入先出 4、虚拟机中最大的一块内存区域,所有线程共享 5、存放的是对象实例和数组 6、又称GC堆,垃圾收集器管理的主要区域 7、可以处于物理上不连续的内存区域中,只要逻辑上连续
栈:
1、stack 2、空间是OS自动的申请和释放 3、后入先出 4、Java虚拟机栈是线程私有的,生命周期与线程相同,其描述的是方法执行的内存模型;方法执行时创建栈帧,用于存储局部变量表、动态链接、出口信息等;方法的执行,对应着栈帧在虚拟机栈中的出栈和入栈 5、是一块连续的内存的区域局部变量表
局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。在Java程序被编译成Class文件时,就在方法的Code属性的max_locals数据项中确定了该方法所需要分配的。
其所需内存空间在编译期就已经确定并分配,在方法运行期间,不会改变局部变量表的大小。什么是基于注解的切面实现
在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
切面(Aspect):用于定义多个增强处理的类
增强处理(advice):AOP框架在特定的切入点执行的逻辑,Spring中的增强处理有before、after、around
切点(Pointcut):可以插入增强处理的连接点
步骤:
a、开启aop注解方式,默认为false
<aop:aspectj-autoproxy>
b、定义切面、增强处理、切入点
@Component //加入到IoC容器
@Aspect //指定当前类为切面类
public class Aop {
//指定切入点表达式,拦截那些方法,即为那些类生成代理对象
//@Pointcut("execution(* com.aop.User.save(..))") ..代表所有参数
//@Pointcut("execution(* com.aop.User.*())") 指定所有的方法
//@Pointcut("execution(* com.aop.User.save())") 指定save方法
@Pointcut("execution(* com.aop.User.*(..))")
public void pointCut(){
}
@Before("pointCut()")
public void begin(){
System.out.println("开启事务");
}
@After("pointCut()")
public void close(){
System.out.println("关闭事务");
}
}
什么是 对象/关系 映射集成模块
对象关系映射(Object Relational Mapping,简称ORM),详细一点,是 面向对象编程中的 对象(Object)和关系数据库的 关(Relation) 的一个映射(Mapping)
是通过使用描述对象和数据库之间映射的元数据,将面向对象语言程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。
常用地orm框架如hibernate和mybatis什么是 Java 的反射机制
概念:反射是一种计算机处理方式,他可以在运行时根据指定的类名获得类的信息,包括方法和属性等
优点:
1、反射提高了程序的灵活性和扩展性。
2、降低耦合性,提高自适应能力。
3、它允许程序动态创建和控制任何类的对象,无需提前硬编码目标类。
缺点:
1、性能问题:反射的开销十分大。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
2、使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。
- 什么是 ACID
Atomic原子性: 事务是一个原子操作单元,其对数据的修改,要么全部执行,要么全部不执行。
Consistent一致性: 在事务开始和完成时,数据都必须保持一致的状态,这意味着所有相关的数据规则都必须应用于数据的修改,以保证数据的完整性;事务结束时,所有的内部数据结构(B树索引、双向链表)也必须是完整的
Isolated隔离性: 数据库提供一定的隔离机制,保证事务在不受外部并发操作的影响下的‘独立的’环境中执行,这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。
Durable持久性: 一旦一个事务被提交,它对数据的修改是永久性的,不会因为和其他操作冲突而取消这个事务。很多人认为这意味着事务是持久在磁盘上,但是规范没有特别定义这点。
事物的隔离级别
五种问题:
1、脏读(Dirty Read):A事务读取B事务尚未提交的数据并在此基础上操作,而B事务执行回滚,那么A读取到的数据就是脏数据。
2、不可重复读(Unrepeatable Read):事务A重新读取前面读取过的数据,发现该数据已经被另一个已提交的事务B修改过了。
3、幻读(Phantom Read):事务A重新执行一个查询,返回一系列符合查询条件的行,发现其中插入了被事务B提交的行。
4、第1类丢失更新:事务A撤销时,把已经提交的事务B的更新数据覆盖了。
5、第2类丢失更新:事务A覆盖事务B已经提交的数据,造成事务B所做的操作丢失。BS与CS的联系与区别
1、C/S是Client/Server的缩写。服务器通常采用高性能的PC、工作站或小型机,并采用大型数据库系统,客户端需要安装专用的客户端软件。
2、B/S是Brower/Server的缩写,客户机上只要安装一个浏览器。在这种结构下,用户界面完全通过浏览器实现,一部分事务逻辑在前端实现,但是主要事务逻辑在服务器端实现。浏览器通过Web Server 同数据库进行数据交互。-
- cookie和session都是用来跟踪浏览器用户身份的会话方式
- cookie数据存放在客户的浏览器上,session数据放在服务器上
- 两个都可以用来存私密的东西,同样也都有有效期的说法,区别是session过期与否取决于服务期的设定,cookie过期与否可以在cookie生成的时候设置进去
- cookie不是很安全,可以分析本地的COOKIE并进行COOKIE欺骗,故考虑到安全应当使用session
- session会在一定时间内保存在服务器上。当访问增多,会比较占用服务器的性能,考虑到服务器性能方面,应当使用COOKIE
- 单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K。故建议将登陆信息等重要信息存放为SESSION;其他信息如果需要保留,可以放在COOKIE中
-
- java.util包下面的所有的集合类都是快速失败的,而java.util.concurrent包下面的所有的类都是安全失败的
- 快速失败的迭代器会抛出ConcurrentModificationException异常,而安全失败的迭代器永远不会抛出这样的异常
- fail-fast原理是通过判断modCount 不等于 expectedModCount,集合的增删改查等操作都会引起modCount 的改变
- Iterator的安全失败是基于对底层集合做拷贝,因此,它不受源集合上修改的影响
- fail-safe机制有两个问题:1、需要复制集合,产生大量的无效对象,开销大 2、无法保证读取的数据是目前原始数据结构中的数据
HTTP中Get与Post的区别
- GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&相连;POST把提交的数据则放置在是HTTP包的包体中
- GET方式提交的数据最多只能是1024字节,理论上POST没有限制
- Get是向服务器发索取数据的一种请求,而Post是向服务器提交数据的一种请求
Interface 与 abstract 类的区别
- abstract 不能与private、static、final或native并列修饰同一个方法
IoC 优点和缺点
- IoC是什么,即反转控制,或许说为依赖注入更为合适。他将对象创建和对象之间的依赖关系的管理交给容器。
- 优点:实现组件之间的解耦,提高程序的灵活性和可维护性
- 缺点:使用反射来创建对象,所以在效率上会有些损耗
-
IO是面向流的,NIO是面向缓冲区的
- Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方
- NIO则能前后移动流中的数据,因为是面向缓冲区的
IO流是阻塞的,NIO流是不阻塞的
- Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了
- Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。NIO可让您只使用一个(或几个)单线程管理多个通道(网络连接或文件),但付出的代价是解析数据可能会比从一个阻塞流中读取数据更复杂。
- 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。
- 选择器
- Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。
死锁产生的条件
什么是竞态条件?
- 如果程序的执行结果和对资源的访问顺序有关,就称存在竞态条件。导致竟态条件发生的代码称作临界区。下例中add()方法就是一个临界区,它会产生竞态条件。在临界区中使用适当的同步就可以避免竞态条件。
public class Counter {
protected long count = 0;
public void add(long value){
this.count = this.count + value;
}
}
JRE、JDK、JVM 及 JIT 之间有什么不同
- JVM:java虚拟机,它抽象化了硬件设备,很好的实现了每个平台的规范,是Java平台独立性的保证。
- JRE:java运行时环境, JRE是JVM的一个超集。JVM对于一个平台或者操作系统是明确的,而JRE是一个一般的概念,他代表了完整的运行时环境
- JDK:java开发工具箱,java开发工具箱指的是编写一个java应用所需要的所有jar文件和可执行文件
- JIT:即时编译器,即时编译器是种特殊的编译器,它通过有效的把字节码变成机器码来提高JVM的效率
MVC 的各个部分都有那些技术来实现?如何实现?
- MVC 是 Model-View-Controller 的简写。 Model 代表的是应用的业务逻辑( 通过
JavaBean, EJB 组件实现), View 是应用的表示面( 由 JSP 页面产生), Controller 是提供
应用的处理过程控制( 一般是一个 Servlet), 通过这种设计模型把应用逻辑, 处理过程和显
示逻辑分成不同的组件实现。 这些组件可以进行交互和重用
- MVC 是 Model-View-Controller 的简写。 Model 代表的是应用的业务逻辑( 通过
-
- RPC远程过程调用协议,通过网络从远程计算机上请求调用某种服务;RMI:远程方法调用,能够让在客户端Java虚拟机上的对象像调用本地对象一样调用服务端java 虚拟机中的对象上的方法。
方法调用方式不同:
- RMI中是通过在客户端的Stub对象作为远程接口进行远程方法的调用。每个远程方法都具有方法签名。如果一个方法在服务器上执行,但是没有相匹配的签名被添加到这个远程接口(stub)上,那么这个新方法就不能被RMI客户方所调用。
- RPC中是通过网络服务协议向远程主机发送请求,请求包含了一个参数集和一个文本值,通常形成“classname.methodname(参数集)”的形式。RPC远程主机就去搜索与之相匹配的类和方法,找到后就执行方法并把结果编码,通过网络协议发回
适用语言范围不同:RMI只用于Java;RPC是网络服务协议,与操作系统和语言无关。
- 调用结果的返回形式不同: Java是面向对象的,所以RMI的调用结果可以是对象类型或者基本数据类型
WebService
- WebService是一种跨编程语言和跨操作系统平台的远程调用技术,服务端和客户端可以使用不同的操作系统,也可是不同的语言
- SOAP:简单对象访问协议(Simple Object Access Protocol),是Web Service中交换数据的一种协议规范。
- WSDL:Web服务描述语言(Web Service Description Language),它描述了Web服务的公共接口。这是一个基于XML的关于如何与Web服务通讯和使用的服务描述;也就是描述与目录中列出的Web服务进行交互时需要绑定的协议和信息格式。通常采用抽象语言描述该服务支持的操作和信息,使用的时候再将实际的网络协议和信息格式绑定给该服务。
- UDDI:统一描述、发现和集成(Universal Description, Discovery and Integration),它是一个基于XML的跨平台的描述规范,可以使世界范围内的企业在互联网上发布自己所提供的服务。简单的说,UDDI是访问各种WSDL的一个门面(可以参考设计模式中的门面模式)。
- WebService是一种跨编程语言和跨操作系统平台的远程调用技术,服务端和客户端可以使用不同的操作系统,也可是不同的语言
WEB容器主要有哪些功能? 并请列出一些常见的WEB容器名字。
- ①web容器是一种服务程序,就是为应用服务器组(如jsp,servlet等)提供一个运行环境,使JSP、servlet直接跟容器中的环境变量接口交互,不必关注其他系统问题。主要有web服务器来实现。
- ②tomcat、WebLogic,WebSphere等
Servlet的生命周期及每个阶段使用的方法
- ①实例化阶段:服务器对Servlet进行实例化,调用Servlet的构造方法
- ②初始化阶段:服务器调用Servlet的init方法进行初始化(只在第一次请求时调用)。
- ③请求处理阶段:服务器调用Servlet的service方法,然后根据请求方式调用相应的doXXX方法。
- ④服务终止阶段:服务器调用Servlet的destroy方法销毁Servlet实例
什么是懒加载
- “懒加载模式”又叫“懒汉模式”是指当第一次使用到这个属性时才给这个属性对应的成员变量进行初始化,如果程序还没运行到这个地方就不进行相应的创建和初始化有利于节省资源提高性能。与之对应的还用一种模式叫做“饿汉模式”就是程序一启动就初始化相应的成员变量,不管当时有没有用到先创建并初始化了再说,所以这种模式相对来说不需要程序员考虑那么详细,会耗费一点资源。
尾递归
- 如果一个函数中
所有递归形式的调用都出现在函数的末尾
,我们称这个递归函数是尾递归的。当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式的一部分时,这个递归调用就是尾递归。尾递归函数的特点是在回归过程中不用做任何操作,直白的讲就是进入下一个递归函数不再需要上一个函数的环境了,得出结果以后直接返回
- 与普通递归相比,由于尾递归的调用处于方法的最后,因此方法之前所积累下的各种状态对于递归调用结果已经没有任何意义,因此完全可以把本次方法中留在堆栈中的数据完全清除,把空间让给最后的递归调用。这样的优化便使得递归不会在调用堆栈上产生堆积,意味着即时是“无限”递归也不会让堆栈溢出。这便是尾递归的优势。
- 如果一个函数中
控制反转(Inversion of Control)与依赖注入(Dependency Injection)
- Ioc不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。–松耦合和扩展
- DI,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。–提升组件重用性
继承类的初始化顺序
1、父类静态代码块和静态属性 > 子类静态代码块和静态属性 > 父类非静态代码块和属性 > 父类构造函数 > 子类非静态代码块和属性 > 子类构造函数
2、对于静态块和静态属性或者非静态块和属性,初始化顺序决定于它们在代码中的顺序。
3、静态代码块和属性只执行一次,非静态代码块每次调用构造函数都会执行一次
4、上面流程并不是绝对的,不可生搬硬套
- java中 float k=1.0 为什么错?
1.0默认是double类型,Java是强类型语言,double类型的内存空间比float大,所以不会自动将double类型转成float 要使用float类型只能这样:
float ff = 1.0f; 数据后必须加上一个f以表示是float类型的
- short s1=1;s1=s1+1;和short s1=1;s1+=1;有什么区别
s1=s1+1; //这是一个短整型和一个整型运算,然后运算结果s1被强行自动升级为整形,而最初s1是声明为短整型的,显然矛盾,肯定会报错。
s1+= 1; //这种写法,强制把1转换成short类型了,当然不会报错了。
正确的写法是:short s1=1;s1=(short)(s1+1); 或者 short s1=1;s1+=1;
java中的内存泄漏
- 定义:某个对象或者变量不再被使用,但是由于被其他对象应用,从而不能被回收
- 两种引发类型
- 1、长生命周期的对象持有短生命周期的对象的应用,导致短生命周期的对象不能被回收
- 2、外部类方法返回内部类的实例,当外部类不再被使用时,由于内部类持有外部类的应用,从而导致外部类无法被回收
HashMap和Hashtable区别
- 相同点:内部都是使用hash表存储数据
- 不同点:
- HashMap非线程安全,Hashtable线程安全
- HashMap键值都可为NULL,Hashtable键值都不能为NULL
- HashMap继承AbstractMap,Hashtable继承Dictory
- HashMap使用iterator迭代,Hashtable使用Enumeration的elements迭代
- HashMap初始容量16,扩容为2的整数倍,Hashtable初始容量为11,扩容为2N+1
- -
静态块等加载顺序
- 1、静态块,静态属性->非静态块,属性->构造器
- 2、对于静态块和静态属性或者非静态块和属性,初始化顺序决定于它们在代码中的顺序。
- 3、上面三部分。父类的优先于子类
- 4、如果类中有属性的类型为类本身,注意静态属性在初始化时会忽略其后面还未初始化的其他静态属性
父类的静态代码块和静态属性 》 子类的静态代码块和静态属性 》 父类的非静态代码块和非静态属性、构造器 》 子类的非静态代码块和非静态属性、构造器
public class StaticTest {
public static int k = 0;
public static StaticTest t1 = new StaticTest("t1");
public static int i = print("i");
public static int n = 99;
public int j = print("j");
{
print("构造块");
}
static{
print("静态块");
}
public StaticTest(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
++i;
}
public static int print(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++i;
return ++n;
}
public static void main(String[] args) {
}
}
结果:注意初始化t1的时候,后面的i、n并没有初始化
1:j i=0 n=0
2:构造块 i=1 n=1
3:t1 i=2 n=2
4:静态块 i=10 n=99
- IOC 容器初始化的基本步骤
(1).初始化的入口在容器实现中的 refresh()调用来完成。
(2).对 bean 定义载入 IOC 容器使用的方法是 loadBeanDefinition,
其中的大致过程如下:
通过 ResourceLoader 来完成资源文件位置的定位, DefaultResourceLoader是默认的实现, 同时上下文本身就给出了 ResourceLoader 的实现, 可以从类路径, 文件系统,URL 等方式来定为资源位置。 如果是 XmlBeanFactory 作为 IOC 容器, 那么需要为它指定 bean 定义的资源,也 就 是 说 bean 定 义 文 件 时 通 过 抽 象 成 Resource 来 被 IOC 容 器 处 理 的 。
容 器 通 过BeanDefinitionReader 来 完 成 定 义 信 息 的 解 析 和 Bean 信 息 的 注 册 , 往 往 使 用 的 XmlBeanDefinitionReader 来 解 析 bean 的 xml 定 义 文 件 - 实 际 的 处 理 过 程 是 委 托 给BeanDefinitionParserDelegate 来完成的, 从而得到 bean 的定义信息, 这些信息在 Spring 中使用BeanDefinition 对 象 来 表 示 - 这 个 名 字 可 以 让 我 们 想 到
loadBeanDefinition,RegisterBeanDefinition 这些相关方法-他们都是为处理 BeanDefinitin 服务 的。
容 器 解 析 得 到 BeanDefinition 以 后 , 需 要 把 它 在 IOC 容 器 中 注 册 , 这 由 IOC 实 现BeanDefinitionRegistry 接口来实现。 注册过程就是在 IOC 容器内部维护的一个 HashMap 来保存得到的 BeanDefinition 的过程。 这个 HashMap 是 IOC 容器持有 Bean 信息的场所, 以后对 Bean 的操作都是围绕这个 HashMap 来实现的。
- 依赖注入的时机
当 Spring IOC 容器完成了 Bean 定义资源的定位、 载入和解析注册以后, IOC 容器中已经管理类 Bean
定义的相关数据, 但是此时 IOC 容器还没有对所管理的 Bean 进行依赖注入, 依赖注入在以下两种情况
发生:
(1).用户第一次通过 getBean 方法向 IOC 容索要 Bean 时, IOC 容器触发依赖注入。
(2).当用户在 Bean 定义资源中为元素配置了 lazy-init 属性,即让容器在解析注册 Bean 定义
时进行预实例化, 触发依赖注入
- SpringMVC初始化和请求处理原理
1、在容器初始化时会建立所有 url 和 Controller 的对应关系(HandlerMapping),保存到 Map<url,Controller>中.Tomcat 启动时会通知 Spring 初始化容器(加载 Bean 的定义信息和初始化所有单例 Bean),然后SpringMVC 会遍历容器中的 Bean,获取每一个 Controller 中的所有方法访问的 url,然后将 url 和Controller 保存到一个 Map 中;
2、请求到达DispatchServlet后,会调用service方法-> doDispatch方法,会根据 Request 快速定位到 Controller,因为最终处理 Request 的是Controller 中的方法,Map 中只保留了 url 和 Controller 中的对应关系,所以要根据 Request 的 url 进一步确认Controller 中 的 Method, 这 一 步 工 作 的 原 理 就 是 拼 接 Controller 的 url(Controller 上
@RequestMapping 的值)和方法的 url(Method 上@RequestMapping 的值),与 request 的 url 进行匹配,找到匹配的那个方法;
3、确定处理请求的 Method后,接下来的任务就是参数绑定(HandlerAdapter),把 Request中参数绑定到方法的形式参数上,执行方法处理请求,之后返回一个ModeAndView对象
4、ModeAndView对象最终会交给一个ViewResolver类解析,得到View(xml、json、html等),然后返回给前端
web.xml中定义有ContextLoaderListener监听器,该监听器在会容器启动的时候调用初始化webApplicationContext的方法,而DispatchServlet类的父类(FrameworkServlet)实现了ApplicationContextAware,会在webApplicationContext初始化完成后,将webApplicationContext注入到servlet容器中。
DispatchServlet初始化最终都会在FrameworkServlet的onRefresh方法,其调用位置有两个地方
1、HttpServletBean的init(),最终实现在FrameworkServlet的initServletBean()方法
2、FrameworkServlet的内部类ContextRefreshListener的onApplicationEvent方法
- 父子类初始化问题
通过子类引用父类中定义的静态变量只会触发父类初始化而不会触发子类初始化
通过数组定义来引用类,不会触发此类的初始化
常量会在编译阶段存入调用者的常量池,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类初始化