java面试题-精心准备

1、接口和抽象类的区别是什么?
Java 提供和支持创建抽象类和接口。它们的实现有共同点,不同点在于: 
接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。 
类可以实现很多个接口,但是只能继承一个抽象类 
类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,类可以不实现抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。 
抽象类可以在不提供接口方法实现的情况下实现接口。 
Java 接口中声明的变量默认都是 final 的。抽象类可以包含非 final 的变量。 
Java 接口中的成员函数默认是 public 的。抽象类的成员函数可以是 private , protected 或者是 public 。 
接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是,如果它包含 main 方法的话是可以被调用的。 


2、创建线程有几种不同的方式?你喜欢哪一种?为什么?
继承 Thread 类 
实现 Runnable 接口 
应用程序可以使用 Executor 框架来创建线程池 
实现 Runnable 接口这种方式更受欢迎,因为这不需要继承 Thread 类。在应用设计中已经继承了别的对象的情况下,这需要多继承(而 Java 不支持多继承),只能实现接口。同时,线程池也是非常高效的,很容易实现和使用。


3、为什么集合类没有实现Cloneable和Serializable接口?
克隆 (cloning) 或者是序列化 (serialization) 的语义和含义是跟具体的实现相关的。因此,应该由集合类的具体实现来决定如何被克隆或者是序列化。


4、Iterator和ListIterator的区别是什么?

Iterator 可用来遍历 Set 和 List 集合,但是 ListIterator 只能用来遍历 List 。 
Iterator 对集合只能是前向遍历, ListIterator 既可以前向也可以后向。 
ListIterator 实现了 Iterator 接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。


5、Java中的HashMap的工作原理是什么?

Java 中的 HashMap 是以键值对 (key-value) 的形式存储元素的。 HashMap 需要一个 hash 函数,它使用 hashCode() 和 equals() 方法来向集合 / 从集合添加和检索元素。当调用 put() 方法的时候, HashMap 会计算 key 的 hash 值,然后把键值对存储在集合中合适的索引上。如果 key 已经存在了, value 会被更新成新值。 HashMap 的一些重要的特性是它的容量 (capacity) ,负载因子 (load factor) 和扩容极限 (threshold resizing)


6、hashCode()和equals()方法的重要性体现在什么地方?

Java 中的 HashMap 使用 hashCode() 和 equals() 方法来确定键值对的索引,当根据键获取值的时候也会用到这两个方法。如果没有正确的实现这两个方法,两个不同的键可能会有相同的 hash 值,因此,可能会被集合认为是相等的。而且,这两个方法也用来发现重复元素。所以这两个方法的实现对 HashMap 的精确性和正确性是至关重要的。


7、HashMap和Hashtable有什么区别?
HashMap 和 Hashtable 都实现了 Map 接口,因此很多特性非常相似。但是,他们有以下不同点: 
HashMap 允许键和值是 null ,而 Hashtable 不允许键或者值是 null 。 
Hashtable 是同步的,而 HashMap 不是。因此, HashMap 更适合于单线程环境,而 Hashtable 适合于多线程环境。 
HashMap 提供了可供应用迭代的键的集合,因此, HashMap 是快速失败的。另一方面, Hashtable 提供了对键的列举 (Enumeration) 。 
一般认为 Hashtable 是一个遗留的类。


8、ArrayList和LinkedList有什么区别?

ArrayList 和 LinkedList 都实现了 List 接口,他们有以下的不同点: 
ArrayList 是基于索引的数据接口,它的底层是数组。它可以以 O(1) 时间复杂度对元素进行随机访问。与此对应, LinkedList 是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链接在一起,在这种情况下,查找某个元素的时间复杂度是 O(n) 。 
相对于 ArrayList , LinkedList 的插入,添加,删除操作速度更快,因为当元素被添加到集合任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。 
LinkedList 比 ArrayList 更占内存,因为 LinkedList 为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素。


9、HashSet和TreeSet有什么区别?

HashSet 是由一个 hash 表来实现的,因此,它的元素是无序的。 add() , remove() , contains() 方法的时间复杂度是 O(1) 。 
另一方面, TreeSet 是由一个树形的结构来实现的,它里面的元素是有序的。因此, add() , remove() , contains() 方法的时间复杂度是 O(logn) 。 
垃圾收集器 (Garbage Collectors)


10、在Java中,对象什么时候可以被垃圾回收?
当对象对当前使用这个对象的应用程序变得不可触及的时候,这个对象就可以被回收了。


11、Java中的两种异常类型是什么?他们有什么区别?

Java 中有两种异常:受检查的 (checked) 异常和不受检查的 (unchecked) 异常。不受检查的异常不需要在方法或者是构造函数上声明,就算方法或者是构造函数的执行可能会抛出这样的异常,并且不受检查的异常可以传播到方法或者是构造函数的外面。相反,受检查的异常必须要用 throws 语句在方法或者是构造函数上声明。这里有 Java 异常处理的一些小建议。 检查异常: ( 编译器必须处理的异常)除 error,runtimeexception 及其子类以外,其他的 Exception 类及其子类都是检查异常。该异常特点是 java 编译器检查,即当程序中出现异常时,要么用 try-catch 语句捕获,要么用 throws 子句声明抛出,否则编译不通过。 非检查异常:(编译器不要求处置的异常),包括运行时异常( runtimeexception 及其子类)和错误( error )


12、Java中Exception和Error有什么区别?
Exception 和 Error 都是 Throwable 的子类。 Exception 用于用户程序可以捕获的异常情况。 Error 定义了不期望被用户程序捕获的异常。


13、t hrow和throws有什么区别?
throw 关键字用来在程序中明确的抛出异常,相反, throws 语句用来表明方法不能处理的异常。每一个方法都必须要指定哪些异常不能处理,所以方法的调用者才能够确保处理可能发生的异常,多个异常是用逗号分隔的。 
45. 异常处理的时候, finally 代码块的重要性是什么? ( 译者注:作者标题的序号弄错了 ) 
14、什么是JDBC?
JDBC 是允许用户在不同数据库之间做选择的一个抽象层。 JDBC 允许开发者用 JAVA 写数据库应用程序,而不需要关心底层特定数据库的细节。


15、什么是cookie?session和cookie有什么区别?

cookie 是 Web 服务器发送给浏览器的一块信息。浏览器会在本地文件中给每一个 Web 服务器存储 cookie 。以后浏览器在给特定的 Web 服务器发请求的时候,同时会发送所有为该服务器存储的 cookie 。下面列出了 session 和 cookie 的区别: 
无论客户端浏览器做怎么样的设置, session 都应该能正常工作。客户端可以选择禁用 cookie ,但是, session 仍然是能够工作的,因为客户端无法禁用服务端的 session 。 
在存储的数据量方面 session 和 cookies 也是不一样的。 session 能够存储任意的 Java 对象, cookie 只能存储 String 类型的对象。


16、concurrenthashmap如何实现
ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。它使用了多个锁来控制对hash表的不同部分进行的修改。ConcurrentHashMap内部使用段(Segment)来表示这些不同的部分,每个段其实就是一个小的hash table,它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。


17、synchronized与volatile异同 
1.volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。 
2.volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的 
3.volatile仅能实现变量的修改可见性,并能保证原子性;而synchronized则可以保证变量的修改可见性和原子性 
4.volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。 
5.volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化 


18、Java内存模型
Java内存模型的抽象在java中,所有实例域、静态域和数组元素存储在堆内存中,堆内存在线程之间共享(本文使用“共享变量”这个术语代指实例域,静态域和数组元素)。局部变量(Local variables),方法定义参数(java语言规范称之为formal method parameters)和异常处理器参数(exception handler parameters)不会在线程之间共享,它们不会有内存可见性问题,也不受内存模型的影响。


19、hashCode() 和equals() 区别和作用
equals(Object obj)方法用来判断两个对象是否“相同”,如果“相同”则返回true,否则返回false。 
hashcode()方法返回一个int数,在Object类中的默认实现是“将该对象的内部地址转换成一个整数返回”。 
接下来有两个个关于这两个方法的重要规范(我只是抽取了最重要的两个,其实不止两个): 
规范1:若重写equals(Object obj)方法,有必要重写hashcode()方法,确保通过equals(Object obj)方法判断结果为true的两个对象具备相等的hashcode()返回值。说得简单点就是:“如果两个对象相同,那么他们的hashcode应该 相等”。不过请注意:这个只是规范,如果你非要写一个类让equals(Object obj)返回true而hashcode()返回两个不相等的值,编译和运行都是不会报错的。不过这样违反了Java规范,程序也就埋下了BUG。 
规范2:如果equals(Object obj)返回false,即两个对象“不相同”,并不要求对这两个对象调用hashcode()方法得到两个不相同的数。说的简单点就是:“如果两个对象不相同,他们的hashcode可能相同”。 
这样我们就可以推断Java运行时环境是怎样判断HashSet和HastMap中的两个对象相同或不同了。我的推断是:先判断hashcode是否相等,再判断是否equals。 


20、你对线程优先级的理解是什么?

每一个线程都是有优先级的,一般来说,高优先级的线程在运行时会具有优先权,但这依赖于线程调度的实现,这个实现是和操作系统相关的(OS dependent)。我们可以定义线程的优先级,但是这并不能保证高优先级的线程会在低优先级的线程前执行。线程优先级是一个int变量(从1-10),1代表最低优先级,10代表最高优先级。


21、 什么是ThreadLocal?

ThreadLocal用于创建线程的本地变量,我们知道一个对象的所有线程会共享它的全局变量,所以这些变量不是线程安全的,我们可以使用同步技术。但是当我们不想使用同步的时候,我们可以选择ThreadLocal变量。


23、Java Concurrency API中的Lock接口(Lock interface)是什么?对比同步它有什么优势?
Lock接口比同步方法和同步块提供了更具扩展性的锁操作。他们允许更灵活的结构,可以具有完全不同的性质,并且可以支持多个相关类的条件对象。
它的优势有:
可以使锁更公平
可以使线程在等待锁的时候响应中断
可以让线程尝试获取锁,并在无法获取锁的时候立即返回或者等待一段时间
可以在不同的范围,以不同的顺序获取和释放锁


24、spring的IOC,AOP原理
就是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。
一个对象想使用另一个对象的方法不用new关键字去创建,而是把new的
过程交给spring容器,然后在需要在需要用的类中写上要使用对象的set方法
这就是依赖注入
AOP原理,aop就是面向切面编程


25、如何选择使用hashmap还是使用treemap
当要遍历是就使用treemap
当要删除,插入,定位元素的操作是使用hashmap


26、synchronized 和 ReentrantLock 的 区别
使用synchronized时候,如果程序运行出错,就会抛出异常,但是不会去做清理工作。使用ReentrantLock允许你尝试着获取但最终未获取的锁,这样如果其他人已经获得这个锁,那你就可以离开去执行别的事情,而不是等待直到这个锁被释放。


27、java都有哪些加锁方式(synchronized、ReentrantLock、共享锁、读写锁等)


28、springMVC的工作原理图:

1、客户端发出一个http请求给web服务器,web服务器对http请求进行解析,如果匹配DispatcherServlet的请求映射路径(在web.xml中指定),web容器将请求转交给DispatcherServlet.
2、DipatcherServlet接收到这个请求之后将根据请求的信息(包括URL、Http方法、请求报文头和请求参数Cookie等)以及HandlerMapping的配置找到处理请求的处理器(Handler)。
3-4、DispatcherServlet根据HandlerMapping找到对应的Handler,将处理权交给Handler(Handler将具体的处理进行封装),再由具体的HandlerAdapter对Handler进行具体的调用。
5、Handler对数据处理完成以后将返回一个ModelAndView()对象给DispatcherServlet。
6、Handler返回的ModelAndView()只是一个逻辑视图并不是一个正式的视图,DispatcherSevlet通过ViewResolver将逻辑视图转化为真正的视图View。
7、Dispatcher通过model解析出ModelAndView()中的参数进行解析最终展现出完整的view并返回给客户端。


29、什么是死锁(Deadlock)?如何分析和避免死锁?

死锁是指两个以上的线程永远阻塞的情况,这种情况产生至少需要两个以上的线程和两个以上的资源。
分析死锁,我们需要查看Java应用程序的线程转储。我们需要找出那些状态为BLOCKED的线程和他们等待的资源。每个资源都有一个唯一的id,用这个id我们可以找出哪些线程已经拥有了它的对象锁。


30、饱汉和饿汉的区别
饿汉式是线程安全的,在类创建的同时就已经创建好一个静态的对象供系统使用,以后不在改变
          懒汉式如果在创建实例对象时不加上synchronized则会导致对对象的访问不是线程安全的
          推荐使用第一种 
从实现方式来讲他们最大的区别就是懒汉式是延时加载,
他是在需要的时候才创建对象,而饿汉式在虚拟机启动的时候就会创建,


HashMap通过hashcode对其内容进行快速查找,而 TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用TreeMap(HashMap中元素的排列顺序是不固定的)。 




31、Java中HashMap和TreeMap的区别深入理解

HashMap 非线程安全 TreeMap 非线程安全 
hashmap适用于插入修改
而treemap适用于排序


32、浅拷贝与深拷贝的区别

简单的来说就是,在有指针的情况下,浅拷贝只是增加了一个指针指向已经存在的内存,而深拷贝就是增加一个指针并且申请一个新的内存,使这个增加的指针指向这个新的内存,采用深拷贝的情况下,释放内存的时候就不会出现在浅拷贝时重复释放同一内存的错误!


33.HashSet的实现:



  对于HashSet而言,它是基于HashMap实现的,HashSet底层使用HashMap来保存所有元素,更确切的说,HashSet中的元素,只是存放在了底层HashMap的key上, 而value使用一个static final的Object对象标识。因此HashSet 的实现比较简单,相关HashSet的操作,基本上都是直接调用底层HashMap的相关方法来完成,


34、线程同步(5种同步方式)

1.同步方法 
    即有synchronized关键字修饰的方法。
    public synchronized void save(){}
2.同步代码块 
    即有synchronized关键字修饰的语句块。 
    被该关键字修饰的语句块会自动被加上内置锁,从而实现同步
    synchronized(object){ 
    }
3.使用特殊域变量(volatile)实现线程同步
//需要同步的变量加上volatile
            private volatile int account = 100;
4.使用重入锁实现线程同步
    在JavaSE5.0中新增了一个java.util.concurrent包来支持同步。 
    ReentrantLock类是可重入、互斥、实现了Lock接口的锁
5.使用局部变量实现线程同步 
    如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本, 
    副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。


35、volatile与synchronized
volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住.
volatile仅能使用在变量级别,synchronized则可以使用在变量,方法.
volatile仅能实现变量的修改可见性,但不具备原子特性,而synchronized则可以保证变量的修改可见性和原子性.
volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞.
volatile标记的变量不会被编译器优化,而synchronized标记的变量可以被编译器优化.


36、join() 的作用:让“主线程”等待“子线程”结束之后才能继续运行。


37、为什么我们调用start()方法时会执行run()方法,为什么我们不能直接调用run()方法?

当你调用start()方法时你将创建新的线程并且执行在run()方法里的代码。但是如果你直接调用run()方法,它不会创建新的线程也不会执行调用线程的代码


38、和 CountDownLatch 一样,CyclicBarrier 同样可以可以在构造函数中设定总计数值。与 CountDownLatch 不同的是,CyclicBarrier 的构造函数还可以接受一个 Runnable,会在 CyclicBarrier 被释放时执行。


39、死锁的情况: 

A和B都不是讲礼貌的人,都不愿给别人让路,所以A和B都在等对方让路,导致谁也过不去。 
活锁的情况: 
A和B都是很讲礼貌的人,都主动给别人让路。A往左移,同时B往右移;A往右移,同时B往左移。 A和B在移动的时候,同时挡住对方,导致谁也过不去。


40、volatile关键字在Java中有什么作用?
当我们使用volatile关键字去修饰变量的时候,所以线程都会直接读取该变量并且不缓存它。这就确保了线程读取到的变量是同内存中是一致的。 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值