1.说一下Java类集
类集是Java实现的数据结构应用,如果只是使用,那么类集的操作非常简单,因为类集的核心接口有List,Set,Map,Iterator,Enumeration;
List子接口:是可以根据索引号取得内容,而在list集合里最容易问到的问题:
ArrayList:基于数组结构实现,需要一段连续的存储空间,通过索引搜索数据的速度较快,但插入和删除数据的速度较慢,扩容方式为创建一个新数组,将原来老数组的元素copy到新数组中,新数组为原来老数组容量的的1.5倍。
**LinkedList**:基于链表数据结构实现,不需要连续的存储空间,插入和删除数据的速度很快,但搜索数据的速度很慢(通过指针遍历搜索)
Set子接口:排序子类
HashSet:重复的判断依靠的是hashcode()和equals的关系;
TreeSet:是有序的,依靠的是Comparable排序
LinkedHashSet:继承了HashSet的特点,但是属于有序(怎加顺序为保存顺序)
Map接口
HashMap:基于哈希表实现,每一个元素是一个key-value对(key和value都允许为null,key为null的键值对永远都放在以table[0]为头结点的链表中),其内部通过单链表解决冲突问题,初始容量默认为16(2的次方数),容量不足(超过了阀值)时,同样会自动增长(默认加载因子为0.75),通过resize操作进行两倍扩容; HashMap是非线程安全的,只是用于单线程环境下;实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆,遍历方式为Iterator。
HashTable:同样是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,默认初始容量为11,容量不足(超过了阀值默认0.75)时,同样会自动增长(扩容方式为原来的两倍加1)遍历方式为Iterator与Enumeration;HashTable也是JDK1.0引入的类,是线程安全的,能用于多线程环境中,同样实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆。
ConcurrentHashMap:使用锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。解决了HashTable访问效率底下的问题,ConcurrentHashMap由Segment数组结构和HashEntry数组结构组成。Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。一个ConcurrentHashMap里包含一个Segment数组,Segment的结构和HashMap类似,是一种数组和链表结构, 一个Segment里包含一个HashEntry数组,每个HashEntry是一个链表结构的元素, 每个Segment守护者一个HashEntry数组里的元素,当对HashEntry数组的数据进行修改时,必须首先获得它对应的Segment锁;扩容的时候首先会创建一个两倍于原容量的数组,然后将原数组里的元素进行再hash后插入到新的数组里。为了高效ConcurrentHashMap不会对整个容器进行扩容,而只对某个segment进行扩容。
2.Spring的工作原理,控制反转是怎么实现的?自己写过滤器过滤编码怎么实现?
**IOC(Inversion of control)**:控制反转,控制权由对象本身转向容器,由容器根据配置文件去创建实例并创建各个实例之间的依赖关系,IOC在整个框架中负责创建对象,管理对象(通过依赖注入DI:依赖注入,IOC的另一种表现方式,组件以一种预先定义好的方式来接受容器注入的资源。装配对象,配置对象,并且管理这些对象的整个生命周期),IOC或依赖注入把应用的代码量讲到最低,它使应用容易测试,单元测试不再需要单例和JNDI查找机制。最小的代价和最小的侵入性使松散耦合得以实现。IOC容器支持加载服务时的饿汉式初始化和懒加载。动态注入让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射,反射其实就是在运行时动态的去创建、调用对象,Spring就是在运行时,根据xml里面的Spring的配置文件来动态的创建对象,和调用对象里的方法。
AOP:AOP是Spring框架面向切面的编程思想,AOP采用一种称为“横切”的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。
Struts1.x、SpringMVC、JSP+Servlet:都可以以直接通过过滤器完成;
Struts2.x:必须通过拦截器完成;
实现:考虑到可扩展性的配置,所以在配置文件里面设置编码,在程序运行的时候动态取得设置的编码进行操作。但是需要设置两个操作:请求编码、回应编码。
3.动态代理是怎么实现的?
直接使用Invocation Handler接口进行实现,同时利用Proxy类设置动态请求对象(JDK反射机制)
使用CGLIB来避免对于“代理设计模式需要使用接口实现”的限制
代理对象的使用场合:一般由于客户端不想直接访问实际对象,或者访问实际的对象存在技术上的障碍,因而通过代理对象作为桥梁,来完成间接访问。
4.事务的控制
MySQL数据库如果想要使用事物,必须使用“type=innodb”这个数据引擎
MyISAM:MyISAM是MySQL的ISAM扩展格式和缺省的数据库引擎。除了提供ISAM里所没有的索引和字段管理的大量功能,MyISAM还使用一种表格锁定的机制,来优化多个并发的读写操作,其代价是你需要经常运行OPTIMIZE TABLE命令,来恢复被更新机制所浪费的空间。
InnoDB:InnoDB数据库引擎都是造就MySQL灵活性的技术的直接产品,这项技术就是MYSQL+API。在使用MYSQL的时候,你所面对的每一个挑战几乎都源于ISAM和MyISAM数据库引擎不支持事务处理(transaction process)也不支持外来键。尽管要比ISAM和 MyISAM引擎慢很多,但是InnoDB包括了对事务处理和外来键的支持,这两点都是前两个引擎所没有的。
区别:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。MyISAM类型的表强调的是性能,其执行速度比InnoDB类型要快,但是不提供事务支持,而InooDB提供事物支持以及外部键等高级数据库功能
事物的核心控制:commit、rollback
在Spring里面,利用AspectJ可以设置AOP的切面,而后进行声明式事务控制
5.脏读、幻读、不可重复读
脏读:脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。
幻读:是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新的数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好像发生了幻觉一样。
不可重复读:是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,第一个事务两次读到的数据可能是不一样的,这样就发生了在一个事务内两次读到的事务是不一样的,因此成为不可重复读。
6.事务的传播属性
在Transaction Definition接口中定义了七个事务传播行为
- PROPAGATION REQUIRED:如果存在一个事务,则支持当前事务,如果没有事务则开启一个新的事务;
- PROPAGATION SUPPORTS:如果存在一个事务,支持当前事务,如果没有事务则非事务的执行,但是对于事务同步的事务管理器,PROPAGATION SUPPORTS与不使用事务有少许不同;
- PROPAGATION MANDATORY:如果已经存在一个事务,支持当前事务,如果没有一个活动的事务,则抛出异常;
- PROPAGATION REQUIRES NEW:总是开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起;
- PROPAGATION_NOT_SUPPORTED:总是非事务地执行,并挂起任何存在的事务;
- PROPAGATION_NEVER:总是非事务地执行,如果存在一个活动事务,则抛出异常;
- PROPAGATION NESTED:如果一个活动的事务存在,则运行在一个嵌套的事务中,如果没有活动事务,则按Transaction Definition.PROPAGATION_REQUIRED属性执行。
7.购物车是怎么是实现的?
Cookie:在网站中,http请求是无状态的,也就是说即使第一次和服务器两届后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。cookie的出现就是为了解决这个问题,第一次登陆后服务器返回一些数据(cookie)给浏览器,然后浏览器保存在本地,当该用户发送第二次请求的时候,就会自动地把上次请求存储的cookie数据自动的携带给服务器,服务器通过浏览器携带的数据就能判断当前用户是那个了。cookie存储的数据量有限,不同的浏览器有不同的存储大小,但一般不超过4kb,因此使用cookie只能存储一些小量的数据,例如session_id。
Session:session和cookie的作用有点类似,都是为了存储用户相关的信息,不同的是,cookie是存储在本地浏览器上的,而session存储在服务器上,存储在服务器的数据会更加安全,不容易被窃取(因此经常会存储一些关键数据如密码),但存储在服务器上也有一定的弊端,就是会占用服务器的资源。
数据库:Ajax处理操作,处理购物车的应用,考虑到用户如果多的情况,并且访问量频繁,要单独设计一个购物车的子系统模块。
8.有没有使用过定时任务?
Java本身提供有定时任务:Time Task、Timer;Timer是一种定时器工具,用来在一个后台线程计划执行指定任务,而TimerTask则是一个抽象类,它的子类代表一个可以被Timer计划的任务;但是此类操作对于定时很难完成,它只能够做频率,但是这个频率不准,所以在定时开发之中会用到quartz组件,而且spring里面也提供有自己的定时实现,这个实现的好处就是可以在准确的时间上进行触发。
9.Java虚拟机内存
Java虚拟机内存区域:
程序计数器:线程私有,一块较小的内存空间,当前线程执行字节码的行号指示器,线程运行、切换、恢复是记录执行的字节码指令地址位置
Java虚拟机栈:线程私有,生命周期和线程相同。描述的是Java方法执行的内存模型
- 每个方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。从调用到执行完成的过程对应一个栈帧在虚拟机栈中入栈到出栈的过程。
- 局部变量表存放了编译器可知的8种基本数据类型、对象引用和returnAddress类型(指向了一条字节码指令的地址),所需内存大小编译期确定。最小存储单位是slot,第一个存放的是this对象引用,其后是方法参数变量、方法局部变量。
- 该区域规定了2种异常: StackOverflowError 请求栈深度大于虚拟机允许的深度 OutOfMemeryError
虚拟机栈动态扩展时无法申请到足够内存。
本地方法栈:线程私有,和虚拟机栈类似,为Native方法服务,HotSpot虚拟机已将该栈和虚拟机栈合并。
Java堆:
- 线程共享,虚拟机启动时创建,唯一目的就是存放对象实例,存放几乎所有对象实例以及数组,GC堆。
- 线程私有缓冲区内存从Java堆中划分
- 物理上是不连续的内存空间,逻辑上连续
方法区:
- 线程共享,存储已被虚拟机加载的类信息(版本、字段、方法、接口)、常量、静态变量、即时编译器编译后的代码等数据(多个类实例共享数据,如静态变量、类hashCode、指向锁记录的指针,线程ID、对象分代年龄)
- HotSpot将方法区作为Java堆的一部分,当做永久代(Permanent Generation)
- HotSpot JDK1.7已将永久代的字符串常量池(hashMap表)移到堆内存中。
运行时常量池:
- 方法区的一部分,存放编译器生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中。
- 字面量包括:1.文本字符串 2.八种基本类型的值 3.被声明为final的常量等;
- 符号引用包括:1.类和方法的全限定名 2.字段的名称和描述符 3.方法的名称和
10.说一下缓存
缓存主要目的的提高查询的效率,常见的两种缓存组件:EhCache(用于数据库)、OSCache(用于页面),除了这样的操作之外,还有缓存的数据库:redis、memcached,其中redis可以将数据保存到磁盘上,并且支持的数据类型要多于memcached。这种redis的数据库每秒并发的访问量可以达到15W次。
11.统计所有重名用户
还是需要考虑数据量问题,如果数据量大,考虑使用位图索引,如果数据量小就直接分组统计即可。
位图索引:位图索引指的是位图索引(bitmap index)技术,是一类特殊的数据库索引技术,其索引使用bit数组(或称bitmap、bit set、bit string、bit vector)进行存储与计算操作。
12.描述一下什么是RPC?(有关分布式)
RPC是一个远程过程调用,实际上Webservice就是RPC的一种实现机制,RPC属于最原始的概念。全称是Remote Procedure Call是一种进程间通信方式,它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即无论是调用本地接口/服务的还是远程的接口/服务,本质上编写的调用代码基本相同。比如两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数或者方法,由与不在一个内存空间,不能直接调用,这时候需要通过就可以应用RPC框架的实现来解决。
13.Spring的自动注入注解有哪些?
@Component 泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注(把普通pojo实例化到spring容器中,相当于配置文件中的
@repository 用于标注数据访问组件,即DAO组件(实现到dao访问)
@service 服务,用于标注业务层组件(注入dao)
@controller 控制器,用于标注控制层组件(注入服务)
14.Java垃圾回收机制
垃圾收集GC(Garbage Collection)是Java语言的核心技术之一,在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,这一切都交给了JVM来处理,针对GC我们这篇文章提出了以下几个问题,GC中判定为垃圾的标准,标记垃圾的算法以及回收垃圾的算法。
什么样的对象才是垃圾,这个问题其实很简单,对于Java对象来讲,如果说这个对象没有被其他对象所引用该对象就是无用的,此对象就被称为垃圾,其占用的内存也就要被销毁,那么自然而然就引出了我们的第二个问题,判断对象为垃圾算法都有哪些?
Java中标记垃圾的算法主要有两种,引用计数法和可达性分析算法,我们首先来介绍引用计数法。
引用计数算法:引用计数算法就是给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加1;当引用失效,计数器就减1;任何时候计数器为0的对象就是不可能在被使用的,可以当作垃圾收集。这种方法实现起来很简单而且优缺点很明显(执行效率高,程序执行受影响较小,但是无法检测出循环引用的情况,导致内存泄漏)
可达性分析算法:这个算法的基本思想就是通过一系列的称为“GC Roots”(虚拟机栈中的引用对对象,方法区中的常量引用对象,方法去中的类静态属性引用对象…)的对象作为起点,从这些结点开始向下搜索,节点所走过的路径就是引用链,当一个对象到GC Roots没有任何引用链相连的话,则证明此对象是不可用的。
那我们又如何将垃圾回收呢?在Java中存在着四种垃圾回收算法,标记清除算法,复制算法,标记整理算法以及分代回收算法
标记清楚算法:该算法分为“标记”和“清除”连个阶段:标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的的对象所占用的空间,他是最基础的收集算法,效率很高,但是在标记清除后会产生大量的不连续碎片空间。
复制算法:为了解决效率问题,有出现了复制算法。它可以将内存分为大小相同的两块,每次使用其中的一块。当第一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。简单来说就是该对象分为对象面以及空闲面,对象在对象面上创建,对象面上存活的对象会被复制到空闲面,接下来就可以清除对象面的内存。但是也有一个问题,就是只能利用一般的空间,只适用于存活率低的场景。
标记整理算法:为了解决复制算法的缺陷,充分利用内存空间,提出了标记整理算法。该算法标记阶段和标记清除一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。
分代收集算法:当前虚拟机的垃圾收集都采用分代收集算法,这种算法就是根据具体的情况选择具体的垃圾回收算法。一般将 java 堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。比如在新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择“标记-清除”或“标记-整理”算法进行垃圾收集。
15.TCP/IP协议族
数据链路层:
以太网协议、
ppp:点对点协议
loopback环回接口
网络层
ip协议:IP则承载要发送的消息,IP协议是TCP/IP协议的核心,所有的TCP,UDP,IMCP,IGCP的数据都以IP数据格式传输,ip是不可靠协议
ARP:地址解析协议,使用IP地址换MAC地址的一种协议
RARP:逆地址协议解析协议
ICMP:当传送IP数据包发生错误--比如主机不可达,路由不可达等等,ICMP协议将会把错误信息封包,然后传送回给主机。给主机一个处理错误的机会,这 也就是为什么说建立在IP层以上的协议是可能做到安全的原因。ICMP数据包由8bit的错误类型和8bit的代码和16bit的校验和组成。而前 16bit就组成了ICMP所要传递的信息。书上的图6-3清楚的给出了错误类型和代码的组合代表的意思。
传输层
TCP:当一台计算机想要与另一台计算机通讯时,两台计算机之间的通信需要畅通且可靠,这样才能保证正确收发数据。例如,当你想查看网页或查看电子邮件时,希望完整且按顺序查看网页,而不丢失任何内容。当你下载文件时,希望获得的是完整的文件,而不仅仅是文件的一部分,因为如果数据丢失或乱序,都不是你希望得到的结果,于是就用到了TCP。TCP协议全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议,由 IETF 的RFC 793定义。TCP 是面向连接的、可靠的流协议(三次握手,四次挥手)。
UDP:UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。