目前流行的开发技术、常见的面试问题以及问题的答案都已经写的特别清楚了,今天我在以前的基础上,再基于我的的经验继续精选一些面试题给你们阅读参考。java
1,Java的反射程序员
Java 反射机制是在运行状态中,对于任意一个类,都可以得到这个类的全部属性和方法,对于任意一个对象都可以调用它的任意一个属性和方法。这种在运行时动态的获取信息以及动态调用对象的方法的功能称为Java 的反射机制。反射也就是动态加载对象,并对对象进行剖析。Class 类与java.lang.reflect 类库一块儿对反射的概念进行了支持,该类库包含了Field,Method,Constructor类(每一个类都实现了Member 接口)。web
反射的做用:面试
1),在运行时判断任意一个对象所属的类redis
2),在运行时构造任意一个类的对象spring
3),在运行时判断任意一个类所具备的成员变量和方法数据库
4),在运行时调用任意一个对象的方法编程
优势:能够动态的建立对象和编译,最大限度发挥了java的灵活性。设计模式
缺点:对性能有影响。使用反射基本上一种解释操做,告诉JVM咱们要作什么而且知足咱们的要求,这类操做老是慢于直接执行java代码。缓存
如何使用java的反射?
a. 经过一个全限类名建立一个对象
1) Class.forName("全限类名");
2) 类名.class; 获取Class<?> clazz 对象
3) 对象.getClass();
b. 获取构造器对象,经过构造器new出一个对象
1) Clazz.getConstructor([String.class]);
2) Con.newInstance([参数]);
c. 经过class对象建立一个实例对象(就至关与new类名()无参构造器)
1) Clazz.newInstance();
d. 经过class对象得到一个属性对象
1) Field c=clazz.getFields(); 得到某个类的全部的公共(public)的字段,包括父类中的字段。
2) Field c=clazz.getDeclaredFields(); 得到某个类的全部声明的字段,即包括public、private和proteced,可是不包括父类的申明字段。
e、经过class对象得到一个方法对象
1)Clazz.getMethod("方法名",class…..parameaType);(只能获取公共的)
2)Clazz.getDeclareMethod("方法名"); (获取任意修饰方法,不能执行私有)
M.setAccessible(true);(让私有的方法能够执行)
f. 让方法执行
Method.invoke(obj实例对象,obj可变参数);
2,Spring的源码分析及实现
Spring是一个开源的、轻量级的Java 开发框架。Spring使用的是基本的JavaBean来完成之前只可能由EJB完成的事情。然而,Spring的用途不只仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用均可以从Spring中受益。Spring的核心是控制反转(IOC)和面向切面(AOP)。
Spring Bean的建立是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者管理对象间的依赖关系提供了不少便利和基础服务,在Spring中有许多的IOC容器的实现供用户选择和使用,其相互关系以下:
BeanFactory做为最顶层的一个接口类,它定义了IOC容器的基本功能规范,BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。IOC容器接口BeanFactory:
public interface BeanFactory {
在BeanFactory里只对IOC容器的基本行为做了定义,根本不关心你的bean是如何定义怎样加载的。正如咱们只关心工厂里获得什么的产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心。
而要知道工厂如何产生对象,就须要看具体的IOC容器实现,spring提供了许多IOC容器的实现。如XmlBeanFactory,ClasspathXmlApplicationContext等。其中XmlBeanFactory就是针对最基本的ioc容器的实现,这个IOC容器能够读取XML文件定义的BeanDefinition(XML文件中对bean的描述),若是说XmlBeanFactory是容器中的屌丝,ApplicationContext应该算容器中的高富帅了。
ApplicationContext是Spring提供的一个高级的IoC容器,它除了可以提供IoC容器的基本功能外,还为用户提供了如下的附加服务。从ApplicationContext接口的实现,咱们看出其特色:
1, 支持信息源,能够实现国际化。(实现MessageSource接口);
2, 访问资源。(实现ResourcePatternResolver接口,这个后面要讲);
3, 支持应用事件。(实现ApplicationEventPublisher接口);
AOP即面向切面编程。能够说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来创建一种对象层次结构,用于模拟公共行为的一个集合。AOP技术利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减小系统的重复代码,下降模块之间的耦合度,并有利于将来的可操做性和可维护性。
AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特色是,他们常常发生在核心关注点的多处,而各处基本类似,好比权限认证、日志、事物。AOP的做用在于分离系统中的各类关注点,将核心关注点和横切关注点分离开来。
Spring对AOP的支持
Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。所以,AOP代理能够直接使用容器中的其它bean实例做为目标,这种关系可由IOC容器的依赖注入提供。Spring建立代理的规则为:
1)、默认使用Java动态代理来建立AOP代理,这样就能够为任何接口实例建立代理了;
2)、当须要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB;
AOP编程实际上是很简单的事情,纵观AOP编程,程序员只须要参与三个部分:
1)、定义普通业务组件 2)、定义切入点,一个切入点可能横切多个业务组件 3)、定义加强处理,加强处理就是AOP框架为普通业务组件织入的处理动做
因此进行AOP编程的关键就是定义切入点和定义加强处理,一旦定义了合适的切入点和加强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=加强处理+被代理对象的方法。
下面给出一个Spring AOP的.xml文件模板,名字叫作aop.xml,以后的内容都在aop.xml上进行扩展:
<?xml version="1.0" encoding="UTF-8"?>
3,****动态代理****(cglib 与 JDK)
JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,经过修改其字节码生成子类来处理。
一、若是目标对象实现了接口,默认状况下会采用JDK的动态代理实现AOP;
二、若是目标对象实现了接口,能够强制使用CGLIB实现AOP;
三、若是目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换;
如何强制使用CGLIB实现AOP?
1) 添加CGLIB库,SPRING_HOME/cglib/*.jar
2)在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>
JDK动态代理和CGLIB字节码生成的区别?
1) JDK动态代理只能对实现了接口的类生成代理,而不能针对类;2) CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,由于是继承,因此该类或方法最好不要声明成final;
4,分布式锁的实现方案
分布式锁通常有三种实现方式:
1. 数据库锁;
2. 基于Redis的分布式锁;
3. 基于ZooKeeper的分布式锁。
基于数据库锁实现
方案1:
CREATE TABLE `methodLock` (
当咱们想要锁住某个方法时,执行如下SQL:
insert into methodLock(method_name,desc) values (`method_name`,`desc`);
:想要释放锁的话,须要执行如下Sql:
delete from methodLock where method_name ='method_name';
方案2:
CREATE TABLE `method_lock` (
获取锁:
select id, method_name, state,version from method_lock where state=1 and method_name='methodName';
占有锁:
update t_resoure set state=2, version=2, update_time=now() where method_name='methodName' and state=1 and version=2;
缺点:
一、这把锁强依赖数据库的可用性,数据库是一个单点,一旦数据库挂掉,会致使业务系统不可用。 二、这把锁没有失效时间,一旦解锁操做失败,就会致使锁记录一直在数据库中,其余线程没法再得到到锁。 三、这把锁只能是非阻塞的,由于数据的insert操做,一旦插入失败就会直接报错。没有得到锁的线程并不会进入排队队列,要想再次得到锁就要再次触发得到锁操做。 四、这把锁是非重入的,同一个线程在没有释放锁以前没法再次得到该锁。由于数据中数据已经存在了。
解决方案:
一、数据库是单点?搞两个数据库,数据以前双向同步。一旦挂掉快速切换到备库上。 二、没有失效时间?只要作一个定时任务,每隔必定时间把数据库中的超时数据清理一遍。 三、非阻塞的?搞一个while循环,直到insert成功再返回成功。 四、非重入的?在数据库表中加个字段,记录当前得到锁的机器的主机信息和线程信息,那么下次再获取锁的时候先查询数据库,若是当前机器的主机信息和线程信息在数据库能够查到的话,直接把锁分配给他就能够了。
实现方案:
try{
缺点:
在这种场景(主从结构)中存在明显的竞态:
客户端A从master获取到锁,
在master将锁同步到slave以前,master宕掉了。
slave节点被晋级为master节点,
客户端B取得了同一个资源被客户端A已经获取到的另一个锁。安全失效!
基于zookeeper实现
方案:能够直接使用zookeeper第三方库Curator客户端,这个客户端中封装了一个可重入的锁服务。
Curator提供的InterProcessMutex是分布式锁的实现。acquire方法用户获取锁,release方法用于释放锁。
缺点:
性能上可能并无缓存服务那么高。由于每次在建立锁和释放锁的过程当中,都要动态建立、销毁瞬时节点来实现锁功能。ZK中建立和删除节点只能经过Leader服务器来执行,而后将数据同不到全部的Follower机器上。
三种方案的比较
上面几种方式,哪一种方式都没法作到完美。就像CAP同样,在复杂性、可靠性、性能等方面没法同时知足,因此,根据不一样的应用场景选择最适合本身的才是王道。
从理解的难易程度角度(从低到高):数据库 > 缓存 > Zookeeper
从实现的复杂性角度(从低到高):Zookeeper >= 缓存 > 数据库
从性能角度(从高到低):缓存 > Zookeeper >= 数据库
从可靠性角度(从高到低):Zookeeper > 缓存 > 数据库
5,Java设计模式部分搞笑解读
一、工厂模式,
搞笑解读:—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不一样,但无论你带MM去麦当劳或肯德基,只管向服务员说“来四个鸡翅”就好了。麦当劳和肯德基就是生产鸡翅的Factory。
工厂模式:客户类和工厂类分开。消费者任什么时候候须要某种产品,只需向工厂请求便可。消费者无须修改就能够接纳新产品。缺点是当产品修改时,工厂类也要作相应的修改。如:如何建立及如何向客户端提供。
2,单例模式
搞笑解读:俺有6个漂亮的老婆,她们的老公都是我,我就是咱们家里的老公Sigleton,她们只要说道“老公”,都是指的同一我的,那就是我(白日好梦)。
单例模式确保某一个类只有一个实例,并且自行实例化并向整个系统提供这个实例单例模式。单例模式只应在有真正的“单一实例”的需求时才可以使用。
3,适配器模式
搞笑解读:在一次聚会碰到了一个很漂亮的乌克兰MM,可不会说乌克兰语,她也不会说普通话,只好求助于会乌克兰语的朋友,他做为咱们之间的Adapter,让咱们能够相互交谈了(也不知道他会不会耍我)。
适配器模式:把一个类的接口变换成客户端所期待的另外一种接口,从而使本来因接口缘由不匹配而没法一块儿工做的两个类可以一块儿工做。适配类能够根据参数返还一个合适的实例给客户端。
4,代理模式
搞笑解读:跟MM在网上聊天,一开头老是“hi,你好”,“你从哪儿来呀?”“你多大了?”“身高多少呀?”这些话,真烦人,写个程序作为个人Proxy吧,凡是接收到这些话都设置好了自动的回答,接收到其余的话时再通知我回答,酷吧。
代理模式:代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。代理就是一我的或一个机构表明另外一我的或者一个机构采起行动。某些 状况下,客户不想或者不可以直接引用一个对象,代理对象能够在客户和目标对象直接起到中介的做用。客户端分辨不出代理主题对象与真实主题对象。代理模式可 以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不可以建立被代理对象,被代理对象必须有系统的其余角色代为建立并传入。