一些面试题整理(java)

来源:互联网 发布:万方经济统计数据库 编辑:程序博客网 时间:2024/06/05 20:27

1、Array、ArrayList、LinkedList的区别
存储内容:Array可以包含基本数据类型和对象类型,Arraylist和LinkedList只能包含对象类型
Array和LinkedList在存储数据的时候必须是一种数据类型,但是ArrayList可以是多种
空间大小:Array的大小是固定的,不可扩容,ArrayList的空间是动态增长的,当空间不够时,它会创建一个空间比原空间大一倍的(新数组新容量=(旧容量*3)/2+1,也就是说每一次容量大概会增长50%),然后将所有元素复制到新数组中,接着抛弃旧数组。而且,每次添加新的元素的时候都会检查内部数组的空间是否足够(如果我们知道一个ArrayList将会有多少个元素,我们可以通过构造方法来指定容量。我们还可以通过trimToSize方法在ArrayList分配完毕之后去掉浪费掉的空间)。对于linkedlist,每增加一个节点,就是增加一个Entry的开销。
方法:Arraylist和Linkedlist中封装了很多Array中没有的方法,如addAll、removeAll、iterator()等
使用场景:如果想要保存一些在整个程序运行期间都会存在而且不变的数据,我们可以将它们放进一个全局数组里,但是如果我们只是想要以数组的形式保存数据,查找操作多余增删操作的话,那么,我们就选择ArrayList。如果增删操作多余查询操作的话,就选择LinkedList。
线程安全:ArrayList和LinkedList都是非线程安全的,在多线程中,工具类Collections中的synchronizedList方法将其转换成线程安全的容器后再使用。

2、Voliter
一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:
可见性:保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的。
有序性:禁止进行指令重排序。
但是voliter无法保证对变量的任何操作都是原子性
具体可参考http://www.importnew.com/18126.html

3、创建对象的方式
1、new关键字,调用构造函数
2、使用lang包下Class类的newInstance调用无参构造器,如 Student s = Student.class.newInstance();或者Student s = (Student)Class.forName("根路径.Student").newInstance();实际是调用了Construct类下的newInstance方法
3、使用java.lang.relect.Constructor类的newInstance调用无参或者有参构造器,如Construct<Student> cons = Student.class.getInstance();Student stu = cons.newInstance();
4、使用clone()方法,该方法不会调用任何构造函数,但是需要类实现Cloneable接口并实现clone方法。Student stu2 = (Stdent)stu.clone();这是原型模式的应用
5、使用反序列化,不会调用任何构造方法。当我们序列化或反序列化一个对象, jvm会创建一个单独的对象。类需要实现Serializable接口。ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));Student stu = (Student)in.readObject();

4、JSP九大内置对象及四大作用域
request、response、pageContext、out、exception、application、session、config、page
page:变量只在当前页面有效
session:变量在当前会话有效,即打开浏览器到关闭浏览器之间有效
request:变量在请求过程有效,即从发起http请求到服务器接收请求之间有效
application:变量在整个应用有效,即从应用发布到结束应用之间有效,且此作用域的变量用户之间可以共享,用户甲修改了变量,用户乙是可见的
具体可参考http://blog.csdn.net/zhangzeyuaaa/article/details/44560921

5、自己实现spring的ioc
利用工厂模式+反射
1、创建javabean类,解析xml文件,填充bean属性
2、创建bean工厂,利用反射来初始化bean对象并将对象注入ioc容器(hashmap)
具体可参考http://blog.csdn.net/u010837612/article/details/50686573

6、aop的实现
1、经典的基于代理的aop:自己定义接口和实现类,然后定义切面类实现MethodBeforeAdvice, AfterReturningAdvice接口,然后在spring的配置文件bean中定义被代理者,切入点,通知内容,然后将切入点与通知关联,设置代理(可以将xml中设置代理的bean改成<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>简化配置。)
2、使用aspectj注解驱动的切面:在实现类中使用@Aspectj注解和@pointcut、@before()、@after()等注解,然后在配置文件中加入<aop:aspectj-autoproxy />并定义通知和被代理者
3、纯粹的POJO切面:定义接口和实现类,切面类,在配置文件中定义被代理类,然后用aop标签来定义其他内容。
具体可参考http://blog.csdn.net/zhangliangzi/article/details/52334964

7、SpringMVC请求处理的流程,用到哪些设计模式
1、前端控制器收到用户请求后委托给其他解析器进行处理
2、handlerMaping会把请求映射为handlerExecutionChain对象(包括一个handler处理器(页面控制器)和多个handlerInterceptor(拦截器)),用到策略模式,可以轻易添加其他映射
3、handlerAdapter会把处理器包装成支持多种类型的适配器,用到适配器模式,可以容易适配其他处理器
4、handleAdapter适配得到的真正的处理器调用业务对象进行业务处理,并返回一个ModelAndView对象
5、viewResolver将逻辑视图名解析为具体的view,用到策略模式,可以轻易添加其他的视图技术
6、view会根据Model进行渲染,此处的model是一个map类型,因此更容易支持其他视图技术
7、前端控制器将响应返回给用户
具体可参http://blog.csdn.net/mishifangxiangdefeng/article/details/52763546

8、jvm内存模式
java程序在运行时将内存划分为4个空间
1、堆内存:所有线程共享,存放new出来的对象
2、程序计数器:每个线程私有,指向下一条指令
3、方法区:所有线程共享,存放被虚拟机加载的类信息,常量,静态常量等
4、栈:线程私有,栈又分为虚拟机栈和本地方法栈。虚拟机栈描述的是执行方法的内存模型,每个方法被调用时都会创建一个栈帧,保存局部变量表,操作栈,动态链接,方法出口等信息。每一个方法被调用到执行结束对应着一个帧从入栈到出栈的过程。
java中每一个线程都有一个工作内存,工作内存与主存独立,保存的是主存中线程要应用到的值的拷贝。当数据从主存复制到工作内存对值进行更新时,单线程是没有问题的,对于多线程,要使用volatile使其他线程可以知道变量值的改变。
具体可参考http://blog.csdn.net/bluetjs/article/details/52874852

9、垃圾回收算法
java中判断引用是否可被回收的方法:可达性分析法(GC Root)。
常见垃圾收集算法:

  • 标记-清除算法:容易产生内存碎片
  • 复制算法:将内存划分为两块,一块内存用完之后,会将该块内存中存活的对象复制到另一块,然后清理该块内存。这样不会产生内存碎片,但是可用内存空间变为原来的一半
  • 标记整理算法:将对象标记之后,将存活对象移动到内存的一端,所有存活对象移完后清理端外面的空间。这样解决了内存碎片和内存利用率的问题。
  • 分代收集算法:根据对象存活周期将内存分为新生代和老年代,新生代采用复制算法,老年代采用标记整理算法。一般将新生代又分为一块较大的Eden和两个较小的Survivor,新生代每次使用Eden和其中一个Survivor,每次进行垃圾回收的时候,会将Eden和Survivor中的存活对象复制到另一个Survivor,然后清除Eden和Survivor。

主要的垃圾收集器:

  • Serial:串行收集器。在进行垃圾回收时其他线程要暂停
  • Parrllel:并行收集器。在进行垃圾回收时其他线程要暂停,但是暂停时间变短
  • CMS:并发收集器。
    初始标记:暂停其他线程
    并发标记:不会暂停其他线程
    重新标记:暂停其他线程
    并发清除:暂停其他线程
  • G1:基于标记-整理算法,针对于多处理器大内存容量的服务器端垃圾收集器。将内存分为多个连续的小内存,每个小内存并发标记,标记完成后优先回收空闲的内存
    具体可参考http://blog.csdn.net/u013782203/article/details/52222722

10、 HashMap和HashTable区别

  • hashmap允许键、值存入null,hashtable不允许
  • hashtable是synchronized,hashmap不是,所以hashtable允许多个线程同时访问,如果想要多个线程同时访问hashmap,可以通过Map m = Collections.synchronizeMap(hashMap);将hashtable变成同步的,或者使用Concurrent包下的currentHashMap
  • hashmap的迭代器iterator是fail-fast迭代器,而hashtable的迭代器enumerator非fail-fast迭代器。所以在用迭代器遍历hashmap的时候,线程不可进行更改hashmap结构的操作,但是可以通过iterator自身的方法对hashmap进行删除操作。
  • hashtable是synchronized,所以在单线程情况下,hashmap的性能更优
  • hashmap不能保证随着时间的推移map中元素的顺序不改变
  • hashtable在不指定容量情况下默认容量是11,hashmap是16。hashmap要求底层数组容量为2的幂次方,hashtable不做要求。hashtable扩容为原来容量的两倍加1,hashmap扩容为原来的两倍。

11、synchronized和lock的区别

  • synchronized和reentrantlock都有并发性,但reentrantlock有定时锁和中断锁。如果线程A和线程B都争用obj对象,假设A获得obj对象:
    如果使用的是synchronized,B将一直等待下去,直到获得obj对象
    如果使用的是reentrantlock,B可以在等待一段时间后,中断等待,去做其他的事情
  • synchronized是在jvm层上实现的,可以通过监控工具监控synchronized的锁定与释放锁,但是lock需要在finally{}中通过代码unlock()释放锁,且必须释放。
  • 在资源竞争不是很激烈的情况下,synchronized的性能要优于reentrantlock,但是在资源竞争激烈的情况下,synchronized的性能要下降几十倍,而reentrantlock性能可以维持常态

12、Integer与Int区别

  • int是基本数据类型,Integer是int的包装类
  • int默认值为0,integer默认为null
  • int可以直接存储数据,integer指向一个对象
  • 声明为int的对象不需要实例化,声明为integer的对象需要实例化
  • 泛型可以用integer,不可以用int
  • Arraylist、Hashmap容器中可以装integer,不可以装int

    13、抽象类和接口的区别

  • 抽象类中可以有方法申明也可以有方法实现,接口中只能有方法申明

  • 抽象类中定义普通常量,接口中的常量只能定义为public static
  • 抽象类和接口都不能直接实例化,如果要实例化,抽象类需要指向实现所有抽象方法的子类实例,接口需要指向实现接口中所有抽象方法的子类
  • 抽象类只能单继承,接口可以多实现

    14、public和private优缺点
    public是公共的,外部可以访问的,所以访问起来很容易,一个类访问另一个类的变量可以直接用类名.变量名访问,但是安全性差,也就是类中的变量可以随意被修改。private是私有的,外部不可以直接访问,一个类访问另一个类中用private定义的变量需要通过共有的get方法,但是可以保证程序的安全性。

15、java的基本类型
java类型:
—–基本数据类型
——数值型
——–整数型
———–byte:1字节
———–short:2字节
———–int:4字节
———–long:8字节
——–浮点型
———–float:4字节
———–double:8字节
——布尔型boolean
——字符型char
—–引用数据类型
——类class
——接口interface
——数组

16、数据库分页查找
select * from 表 limit m n;
从m处取出n条记录

17、类加载机制

  • 装载:查找和导入class文件
  • 链接:把类的二进制数据合并到JRE
    校验:检查载入class文件数据的正确性
    准备:给类的静态变量准备存储空间
    解析:将符号引用转变成直接引用
  • 初始化:对类的静态变量、静态代码块执行初始化操作