java经典面试题

1.数组与链表的优缺点和区别:(后面引入map)

数组:是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素。但是如果要在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中。同样的道理,如果想删除一个元素,同样需要移动大量元素去填掉被移动的元素。如果应用需要快速访问数据,很少插入和删除元素,就应该用数组。
链表:中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起,每个结点包括两个部分:一个是存储 数据元素 的 数据域,另一个是存储下一个结点地址的 指针。 
如果要访问链表中一个元素,需要从第一个元素开始,一直找到需要的元素位置。但是增加和删除一个元素对于链表数据结构就非常简单了,只要修改元素中的指针就可以了。如果应用需要经常插入和删除元素你就需要用链表。

数组从栈中分配空间, 对于程序员方便快速,但自由度小。
链表从堆中分配空间, 自由度大但申请管理比较麻烦。

2.&和&&区别


与,短路与):一样的地方就是二者执行最后的结果是一样的,但是执行的过程有区别,
对于&:无论&左边是否为false,他都会继续检验右边的boolean值。
对于&&:只要检测到左边Boolean值为false时,就会直接判断结果,不会在检验右边的值(因为"与"有一个false最后结果就是false了)
所以&&的执行效率更高,所以一般都是使用&&.
|与||之间也是同样的道理,|:无论左边是否为ture,都会检验右边 ,||:则不会。||  的执行效率会更高
&和 | 做位运算符,做二进制位之间的与运算:
比如 6&3=110&011=010=2或6|3=110|011=111=7

3.HashMap的存储结构及原理:


存储
这里HashMap用了一个算法。
map.put(key,value) //存储key
int hash=key.hashCode(); //获取key的hashCode,这个值是一个固定的int值
int index=hash%Entry[].length;//获取数组下标:key的hash值对Entry数组长度进行取余
Entry[index]=value;
注意:如果两个key通过hash%Entry[].length得到的index相同,会不会覆盖?(hash冲突)
是不会的。Entry类有一个next属性,作用是指向下一个Entry。打个比方, 第一个键值对A进来,通过计算其key的hash得到的
index=0,记做:Entry[0] = A。一会后又进来一个键值对B,通过计算其index也等于0,现在怎么办?HashMap会这样做:B.next =
A,Entry[0] = B,如果又进来C,index也等于0,那么C.next = B,Entry[0] = C;这样我们发现index=0的地方其实存取了A,B,C三个键值对,他
们通过next这个属性链接在一起。所以疑问不用担心。解决hash冲突的方法有很多,HashMap底层是通过链表来解决hash冲突的。
HashMap其实就是一个Entry数组,Entry对象中包含了键和值,其中next也是一个Entry对象,它就是用来处理hash冲突的,形成一个链表。


4.hashcode和equals区别


hashCode是为了提高在散列结构存储中查找的效率,在线性表中没有作用。
equals和hashCode需要同时覆盖。
若两个对象equals返回true,则hashCode有必要也返回相同的int数。
若两个对象equals返回false,则hashCode不一定返回不同的int数,但为不相等的对象生成不同hashCode值可以提高哈希表的性能。
若两个对象hashCode返回相同int数,则equals不一定返回true。
若两个对象hashCode返回不同int数,则equals一定返回false。
同一对象在执行期间若已经存储在集合中,则不能修改影响hashCode值的相关信息,否则会导致内存泄露问题。


5spring中IOC和AOP原理分析


IOC容器:就是具有依赖注入功能的容器,是可以创建对象的容器,IOC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。通常new一个实例,控制权由程序员控制,而"控制反转"是指new实例工作不由程序员来做而是交给Spring容器来做。。在Spring中BeanFactory是IOC容器的实际代表者。
IOC,就是DAO接口的实现不再是业务逻辑层调用工厂类去获取,而是通过容器(比如spring)来自动的为我们的业务层设置DAO的实现类。这样整个过程就反过来,以前是我们业务层主动去获取DAO,而现在是DAO主动被设置到业务逻辑层中来了,这也就是反转控制的由来。通过IOC,我们就可以在不修改任何代码的情况下,无缝的实现数据库的换库迁移,当然前提还是必须得写一个实现特定数据库的DAO。我们把DAO普遍到更多的情况下,那么IOC就为我们带来更大的方便性,比如一个接口的多个实现,我们只需要配置一下就ok了,而不需要再一个个的写工厂来来获取了。这就是IOC为我们带来的模块的松耦合和应用的便利性。说白了其实就是由我们平常的new转成了使用反射来获取类的实例。
AOP就是纵向的编程,如业务1和业务2都需要一个共同的操作,与其往每个业务中都添加同样的代码,不如写一遍代码,让两个业务共同使用这段代码。在日常有订单管理、商品管理、资金管理、库存管理等业务,都会需要到类似日志记录、事务控制、权限控制、性能统计、异常处理及事务处理等。AOP把所有共有代码全部抽取出来,放置到某个地方集中管理,然后在具体运行时,再由容器动态织入这些共有代码。

6.aop的动态代理:


jdk代理:1、因为利用JDKProxy生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有。
2、生成的代理类的所有的方法都拦截了目标类的所有的方法。而拦截器中invoke方法的内容正好就是代理类的各个方法的组成体。
3、利用JDKProxy方式必须有接口的存在。
4、invoke方法中的三个参数可以访问目标类的被调用方法的API、被调用方法的参数、被调用方法的返回类型。
CGlib代码
1、CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
2、用CGlib生成代理类是目标类的子类。
3、用CGlib生成 代理类不需要接口
4、用CGLib生成的代理类重写了父类的各个方法。
5、拦截器中的intercept方法内容正好就是代理类中的方法体
CGLIB和JDK动态代理区别:
JDK:目标类和代理类实现了共同的接口
拦截器必须实现InvocationHandler接口,而这个接口中invoke方法体的内容就是代理对象方法体的内容
CGLIB:目标类 是代理类的父类
拦截器必须实现MethodInterceptor接口,而接口中的intercept方法就是代理类的方法体,使用字节码增强机制创建代理对象的.

7.垃圾收集器和内存分配策略。


一、判断对象生存的算法
java并未使用引用计数法判断一个对象是否存活。
而真正的方法是:可达性分析算法。
可达性分析算法:
通过一系列称为"GC Roots"的对象为起始点,从这些节点开始向下搜索,走过的路径为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。
这个GC Roots包含下面几种:
1.虚拟机栈中引用的对象。
2.方法区中类静态属性引用的对象。
3.方法区中常量引用的对象。
4.本地方法中JNI(一般说的是NAtive方法)引用的对象。
但是不管事计数法和可达性分析法,都会与引用相关。所以分成了四种引用
1.强引用   类似Object obj=new Object()引用,垃圾回收器永远不会回收掉被引用的对象。
2.软引用   描述一些还有用但并非必须的对象。
3.若引用   也是用来描述非必须对象,强度比软引用更弱一些。
4.虚引用   会在被回收的时候收到一个系统通知。

生存还是死亡?
即使是可达性算法不可达的对象,也不是"非死不可"的,需要经过两次标记,一是是否要执行finaliza()方法.如果需要执行则标记,会进入F-Queue队列中。并由线程去执行它。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值