最近,我在ImportNew网站上,看到了这篇文章,觉得总结的非常好,就默默的收藏起来了,觉得日后一定要好好整理学习一下,昨天突然发现在脉脉的行业头条中,居然也推送了这篇文章,更加坚定了我整理的信心。
文中答案和详解部分过于详细的我会附上,本人认为写的 比较好的链接,供大家参考,如果有什么不正确的地方,还希望各位大神,在评论中给予指导,谢谢!
J2SE基础
1. 九种基本数据类型的大小,以及他们的封装类?
Java提供了一组基本数据类型,包括 boolean, byte, char, short, int, long, float, double, void.
同时,java也提供了这些类型的封装类,分别为 Boolean, Byte, Character, Short, Integer, Long, Float, Double, Void
为什么Java会这么做?在java中使用基本类型来存储语言支持的基本数据类型,这里没有采用对象,而是使用了传统的面向过程语言所采用的基本类在型,主要是从性能方面来考虑的:因为即使最简单的数学计算,使用对象来处理也会引起一些开销,而这些开销对于数学计算本来是毫无必要的。但是在java中,泛型类包括预定义的集合,使用的参数都是对象类型,无法直接使用这些基本数据类型,所以java又提供了这些基本类型的包装器。区别:1、基本数据类型只能按值传递,而封装类按引用传递,2、基本类型在堆栈中创建;而对于对象类型,对象在堆中创建,对象的引用在堆栈中创建。基本类型由于在堆栈中,效率会比较高,但是可能会存在内存泄漏的问题。
2.Switch能否用string做参数?
在 Java 7之前,switch 只能支持 byte、short、char、int或者其对应的封装类以及 Enum 类型。在 Java 7中,String支持被加上了。
3.equals与==的区别?
“==”比较的是值【变量(栈)内存中存放的对象的(堆)内存地址】
equal用于比较两个对象的值是否相同【不是比地址】
【特别注意】Object类中的equals方法和“==”是一样的,没有区别,而String类,Integer类等等一些类,是重写了equals方法,才使得equals和“==不同”,所以,当自己创建类时,自动继承了Object的equals方法,要想实现不同的等于比较,必须重写equals方法。"=="比"equal"运行速度快,因为"=="只是比较引用.
4. Object有哪些公用方法?
直接上代码:
Object o = new Object();
/**
* 比较当前对象和是否等于另一个对象,指向的对象是否相同
*/
System.out.println(o.equals(new Object()));
/**
* 返回hashCode
*/
System.out.println(o.hashCode());
/**
* 返回包名+类名+Integer.toHexString(hashCode())
*/
System.out.println(o.toString());
/**
* 返回class对象
*/
System.out.println(o.getClass());
try {
/**
* 线程等待,Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
*/
o.wait();
o.wait(1000);
o.wait(1000,1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
/**
* notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。两者的最大区别在于:
* notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。
* notify则文明得多他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁此时如果该对象没有再次使用notify语句,则即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。
*/
o.notify();
o.notifyAll();
5. Java的四种引用,强弱软虚,用到的场景。
强引用
最普遍的一种引用方式,如String s = "abc",变量s就是字符串“abc”的强引用,只要强引用存在,则垃圾回收器就不会回收这个对象。
软引用(SoftReference)
用于描述还有用但非必须的对象,如果内存足够,不回收,如果内存不足,则回收。一般用于实现内存敏感的高速缓存,软引用可以和引用队列ReferenceQueue联合使用,如果软引用的对象被垃圾回收,JVM就会把这个软引用加入到与之关联的引用队列中。
弱引用(WeakReference)
弱引用和软引用大致相同,弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
虚引用(PhantomReference)
就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。 虚引用主要用来跟踪对象被垃圾回收器回收的活动。
虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中
参考链接:http://droidyue.com/blog/2014/10/12/understanding-weakreference-in-java/
hashCode方法的主要作用是为了配合基于散列的集合一起正常运行,这样的散列集合包括HashSet、HashMap以及HashTable
参考链接:浅谈Java中的hashcode方法
7.ArrayList、LinkedList、Vector的区别
这三者都是实现了List接口,都拥有List接口里面定义的方法,并且同时拥有Collection接口的方法;
ArrayList:采用的是数组的方式进行存储数据的,查询和修改速度快,但是增加和删除速度慢;线程是不同步的
LinkedList:采用的是链表的方式进行存储数据的,查询和修改速度慢,但是增加和删除速度快;线程是不同步的
Vector:也采用的是数组的方式进行存储的,Vector在java1.0以前用,但是ArrayList是在java1.2版本后使用的,线程是同步的,效率相比ArrayList来说慢一点;同时Vector查询数据有迭代器,有枚举,有get(int index),有indexOf(int index)四种方式,而ArrayList却没有枚举
8. String、StringBuffer与StringBuilder的区别
1、可变与不可变
String类中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的。
private final char value[];
StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,如下就是,可知这两种对象都是可变的。
char[] value;
2、是否多线程安全
String中的对象是不可变的,也就可以理解为常量,显然线程安全。
AbstractStringBuilder是StringBuilder与StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity、append、insert、indexOf等公共方法
StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的
StringBuilder并没有对方法进行加同步锁,所以是非线程安全的
9. Map、Set、List、Queue、Stack的特点与用法
Map
Map是键值对,键Key是唯一不能重复的,一个键对应一个值,值可以重复。
TreeMap可以保证顺序,HashMap不保证顺序,即为无序的。
Map中可以将Key和Value单独抽取出来,其中KeySet()方法可以将所有的keys抽取正一个Set。而Values()方法可以将map中所有的values抽取成一个集合。
Set
不包含重复元素的集合,set中最多包含一个null元素
只能用Lterator实现单项遍历,Set中没有同步方法
List
有序的可重复集合。
可以在任意位置增加删除元素。
用Iterator实现单向遍历,也可用ListIterator实现双向遍历
Queue
Queue遵从先进先出原则。
使用时尽量避免add()和remove()方法,而是使用offer()来添加元素,使用poll()来移除元素,它的优点是可以通过返回值来判断是否成功。
LinkedList实现了Queue接口。
Queue通常不允许插入null元素
Stack
Stack遵从后进先出原则。
Stack继承自Vector。
它通过五个操作对类Vector进行扩展,允许将向量视为堆栈,它提供了通常的push和pop操作,以及取堆栈顶点的peek()方法、测试堆栈是否为空的empty方法等
如果涉及堆栈,队列等操作,建议使用List
对于快速插入和删除元素的,建议使用LinkedList
如果需要快速随机访问元素的,建议使用ArrayList
HashMap和Hashtable都实现了Map接口,但决定用哪一个之前先要弄清楚它们之间的分别。主要的区别有:线程安全性,同步(synchronization),以及速度。
10. HashMap和HashTable的区别。
- HashMap几乎可以等价于Hashtable,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受为null的键值(key)和值(value),而Hashtable则不行)。
- HashMap是非synchronized,而Hashtable是synchronized,这意味着Hashtable是线程安全的,多个线程可以共享一个Hashtable;而如果没有正确的同步的话,多个线程是不能共享HashMap的。Java 5提供了ConcurrentHashMap,它是HashTable的替代,比HashTable的扩展性更好。
- 另一个区别是HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。这条同样也是Enumeration和Iterator的区别。
- 由于Hashtable是线程安全的也是synchronized,所以在单线程环境下它比HashMap要慢。如果你不需要同步,只需要单一线程,那么使用HashMap性能要好过Hashtable。
- HashMap不能保证随着时间的推移Map中的元素次序是不变的
11、HashMap和ConcurrentHashMap的区别,HashMap的底层源码。
Hashmap本质是数组加链表。根据key取得hash值,然后计算出数组下标,如果多个key对应到同一个下标,就用链表串起来,新插入的在前面。
ConcurrentHashMap:在hashMap的基础上,ConcurrentHashMap将数据分为多个segment(类似hashtable),默认16个(concurrency level),然后在每一个分段上都用锁进行保护,从而让锁的粒度更精细一些,并发性能更好
参考文章:HashMap VS ConcurrentHashMap
HashMap的源码:【Java集合源码剖析】HashMap源码剖析
12、TreeMap、HashMap、LindedHashMap的区别
1.HashMap里面存入的键值对在取出的时候是随机的,也是我们最常用的一个Map.它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。在Map 中插入、删除和定位元素,HashMap 是最好的选择。 2.TreeMap取出来的是排序后的键值对。但如果您要按自然顺序或自定义顺序遍历键,那么TreeMap会更好。 3. LinkedHashMap 是HashMap的一个子类,如果需要输出的顺序和输入的相同,那么用LinkedHashMap可以实现. (应用场景:购物车等需要顺序的) 13. Collection包结构,与Collections的区别。
Collection是集合类的上级接口,子接口主要有Set
Collections是针对集合类的一个帮助类,提供了操作集合的工具方法:一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。
给大家补充一个链接:collections在java中的常见用法
参考链接:http://blog.sina.com.cn/s/blog_105817120102vzh6.html
14、try catch finally,try里有return,finally还执行么?
1、不管有木有出现异常,finally块中代码都会执行;
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的;
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值。
情况1:try{} catch(){}finally{} return;
显然程序按顺序执行。
情况2:try{ return; }catch(){} finally{} return;
程序执行try块中return之前(包括return语句中的表达式运算)代码;
再执行finally块,最后执行try中return;
finally块之后的语句return,因为程序在try中已经return所以不再执行。
情况3:try{ } catch(){return;} finally{} return;
程序先执行try,如果遇到异常执行catch块,
有异常:则执行catch中return之前(包括return语句中的表达式运算)代码,再执行finally语句中全部代码,
最后执行catch块中return. finally之后也就是4处的代码不再执行。
无异常:执行完try再finally再return.
情况4:try{ return; }catch(){} finally{return;}
程序执行try块中return之前(包括return语句中的表达式运算)代码;
再执行finally块,因为finally块中有return所以提前退出。
情况5:try{} catch(){return;}finally{return;}
程序执行catch块中return之前(包括return语句中的表达式运算)代码;
再执行finally块,因为finally块中有return所以提前退出。
情况6:try{ return;}catch(){return;} finally{return;}
程序执行try块中return之前(包括return语句中的表达式运算)代码;
有异常:执行catch块中return之前(包括return语句中的表达式运算)代码;
则再执行finally块,因为finally块中有return所以提前退出。
无异常:则再执行finally块,因为finally块中有return所以提前退出。
最终结论:任何执行try 或者catch中的return语句之前,都会先执行finally语句,如果finally存在的话。
如果finally中有return语句,那么程序就return了,所以finally中的return是一定会被return的,
编译器把finally中的return实现为一个warning。
15. Excption与Error包结构。OOM你遇到过哪些情况,SOF你遇到过哪些情况
(一)Throwable
Throwable 类是 Java 语言中所有错误或异常的超类。只有当对象是此类或其子类之一的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出,才可以是 catch 子句中的参数类型。
Throwable 类及其子类有两个构造方法,一个不带参数,另一个带有 String 参数,此参数可用于生成详细消息。
Throwable 包含了其线程创建时线程执行堆栈的快照。它还包含了给出有关错误更多信息的消息字符串。
Java将可抛出(Throwable)的结构分为三种类型:
错误(Error)
运行时异常(RuntimeException)
被检查的异常(Checked Exception)
1.Error
Error 是 Throwable 的子类,用于指示合理的应用程序不应该试图捕获的严重问题。大多数这样的错误都是异常条件。
和RuntimeException一样, 编译器也不会检查Error。
当资源不足、约束失败、或是其它程序无法继续运行的条件发生时,就产生错误,程序本身无法修复这些错误的。
2.Exception
Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。
对于可以恢复的条件使用被检查异常(Exception的子类中除了RuntimeException之外的其它子类),对于程序错误使用运行时异常。
① ClassNotFoundException
当应用程序试图使用以下方法通过字符串名加载类时:
Class 类中的 forName 方法。
ClassLoader 类中的 findSystemClass 方法。
ClassLoader 类中的 loadClass 方法。
但是没有找到具有指定名称的类的定义,抛出该异常。
1
2
3
4
|
<code>② CloneNotSupportedException
当调用 Object 类中的 clone 方法复制对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。重写 clone 方法的应用程序也可能抛出此异常,指示不能或不应复制一个对象。
</code>
|
③ IOException
当发生某种 I/O 异常时,抛出此异常。此类是失败或中断的 I/O 操作生成的异常的通用类。
-EOFException
当输入过程中意外到达文件或流的末尾时,抛出此异常。
此异常主要被数据输入流用来表明到达流的末尾。
注意:其他许多输入操作返回一个特殊值表示到达流的末尾,而不是抛出异常。
-FileNotFoundException
当试图打开指定路径名表示的文件失败时,抛出此异常。
在不存在具有指定路径名的文件时,此异常将由 FileInputStream、FileOutputStream 和 RandomAccessFile 构造方法抛出。如果该文件存在,但是由于某些原因不可访问,比如试图打开一个只读文件进行写入,则此时这些构造方法仍然会抛出该异常。
-MalformedURLException
抛出这一异常指示出现了错误的 URL。或者在规范字符串中找不到任何合法协议,或者无法解析字符串。
-UnknownHostException
指示主机 IP 地址无法确定而抛出的异常。
④ RuntimeException
是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。可能在执行方法期间抛出但未被捕获的 RuntimeException 的任何子类都无需在 throws 子句中进行声明。
Java编译器不会检查它。当程序中可能出现这类异常时,还是会编译通过。
虽然Java编译器不会检查运行时异常,但是我们也可以通过throws进行声明抛出,也可以通过try-catch对它进行捕获处理。
-ArithmeticException
当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。
-ClassCastException
当试图将对象强制转换为不是实例的子类时,抛出该异常。
例如:Object x = new Integer(0);
-LllegalArgumentException
抛出的异常表明向方法传递了一个不合法或不正确的参数。
-IllegalStateException
在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。
-IndexOutOfBoundsException
指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
应用程序可以为这个类创建子类,以指示类似的异常。
-NoSuchElementException
由 Enumeration 的 nextElement 方法抛出,表明枚举中没有更多的元素。
-NullPointerException
当应用程序试图在需要对象的地方使用 null 时,抛出该异常。这种情况包括:
调用 null 对象的实例方法。
访问或修改 null 对象的字段。
将 null 作为一个数组,获得其长度。
将 null 作为一个数组,访问或修改其时间片。
将 null 作为 Throwable 值抛出。
应用程序应该抛出该类的实例,指示其他对 null 对象的非法使用。
(二) SOF (堆栈溢出 StackOverflow)
StackOverflowError 的定义:
当应用程序递归太深而发生堆栈溢出时,抛出该错误。因为栈一般默认为1-2m,一旦出现死循环或者是大量的递归调用,在不断的压栈过程中,造成栈容量超过1m而导致溢出。
栈溢出的原因:
<code>递归调用
大量循环或死循环
全局变量是否过多
数组、List、map数据过大
</code>