不知道你有没有遇到过这种情况,在大四准备面试时,看着一本厚厚的《Java从入门到精通》无从下手?甚至失去了干开发的欲望?面临着毕业即失业的窘境?这些我都在今年体验了一遍。。。不知道在经历了多少次的笔试面试之后,我终于在5.20当天收到Offer,这是个幸运的日子,在入职了将近一个半月后,我决定把我面试过程整理的高频“面点”分享出来,希望可以帮助更多刚毕业的小伙伴尽早找到工作!(因个人能力有限,面试次数有限,肯定还有还有漏掉的地方,大家谅解)
1、Object()默认构造方法。
2、clone() 创建并返回此对象的一个副本。
3、equals(Object obj) 指示某个其他对象是否与此对象“相等”。
4、finalize()当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
5、getClass()返回一个对象的运行时类。
6、hashCode()返回该对象的哈希码值。
7、notify()唤醒在此对象监视器上等待的单个线程
8、notifyAll()唤醒在此对象监视器上等待的所有线程。
9、toString()返回该对象的字符串表示。
10、wait()导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
11、wait(long timeout)导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。
12、wait(long timeout, int nanos) 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量
抽象类和接口中,都有抽象方法需要实现,他们都不能创建实例对象,区别是:
1、抽象类可以有构造方法、普通成员变量、普通方法,但接口不行。
2、抽象类和接口都可以包含静态成员变量、静态方法,抽象类中的静态成员变量可以是任意访问类型,但接口必须是public(Java8支持default)。
3、抽象类的抽象方法的访问类型可以是public、protected,但接口必须是public。
4、一个类可以实现多个接口,但只能继承一个抽象类。
java.lang.NullPointerException |
空指针异常 |
java.lang.ClassNotFoundException |
指定的类不存在 |
java.lang.ArithmeticException |
数学运算异常 |
java.lang.ArrayIndexOutOfBoundsException |
索引越界 |
java.lang.IllegalArgumentException |
方法的参数错误 |
java.lang.IncompatibleClassChangeError |
不兼容的类变化错误 |
java.lang.InstantiationError |
实例化错误 |
java.lang.LinkageError |
链接错误 |
java.lang.StackOverflowError |
堆栈溢出 |
Overload是重载的意思,Override是覆盖的意思,也就是重写。
重载Overload表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)
重写Override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。子类方法的访问权限只能比父类的更大,不能更小。
如果两个方法的参数列表完全一样,是否可以让它们的返回值不同来实现重载Override。这是不行的
1、父类中的静态变量和静态代码块
2、子类中的静态变量和静态代码块
3、父类中的普通变量和代码块->构造方法
4、子类中的普通变量和代码块->构造方法
变量和代码块的执行与声明顺序有关,变量一般声明在代码块前
修饰符 |
同一个类 |
同一个包 |
子类 |
任何地方 |
private |
√ |
|
|
|
default |
√ |
√ |
|
|
protected |
√ |
√ |
√ |
|
public |
√ |
√ |
√ |
√ |
String只读字符串,意味着其引用的字符串内容不能发生改变
StringBuffer/StringBuilder 表示的字符串对象可以直接进行修改。
StringBuilder 是 Jdk1.5 中引入的,它和 StringBuffer 的方法完全相同,区别在于它是在单线程环境下使用的,
因为它的所有方法都没有被 synchronized 修饰,因此它的效率理论上也比StringBuffer 要高。
final 用于声明变量,方法,类,表示变量不可改变(引用不能改变,只可以改变),方法不能重写,类不可以被继承
finally 用于异常处理中,表示,必须要执行的代码块,除非java虚拟机停止工作,否则一定会执行
finalize() 是Object类中的一个方法,用于java虚拟机的垃圾回收
1、继承Thread类并重写run()方法;
2、实现Runnable接口并重写run方法;
3、实现Callable接口由FeatureTask创建
4、通过线程池创建 如ExecutorService
新建:当通过new操作符创建一个线程时,处于新建状态
就绪:使用start()方法之后处于就绪状
运行:真正执行run()方法
阻塞:执行了sleep()、wait() 方法后
死亡:当线程执行完或者因为异常退出run()方法后
sleep()属于Thread类中,wait()属于Object类中的。
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。
在调用sleep()方法的过程中,线程不会释放对象锁。wait()会释放对象锁,重新进入就绪状态需要notify()或者notifyAll()方法
指的是两个或两个以上的线程执行过程中,为争夺资源出现相互等待的现象,当一下四个条件全部满足时便会产生死锁。
1、互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用
2、不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
3、请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
4、循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
最简单的办法是阻止循环等待条件,规定线程争夺资源是以一定的顺序进行的
一个是修饰符,一个是方法,
==:如果比较的对象是基本数据类型,则比较的是数值是否相等;如果比较的是引用数据类型,则比较的是对象的地址值是否相等,
equals():用来比较方法两个对象的内容是否相等,equals方法不能比较基本数据类型。
当synchronized修饰静态方法时,修饰的是当前类的class对象锁
当synchronized修饰实例方法时,修饰的时对象中的实例方法
Lock产生异常时不会自动释放锁,所以要在finally中释放锁(lock.unlock();)
synchronized修饰的锁产生异常时会自动释放
在网络数据传输中,传输层协议TCP(传输控制协议)是建立连接的可靠传输,TCP建立连接的过程,我们称为三次握手。
第一次,客户端向服务器发送SYN同步报文段,请求建立连接
第二次,服务器确认收到客户端的连接请求,并向客户端发送SYN同步报文,表示要向客户端建立连接
第三次,客户端收到服务器端的确认请求后,处于建立连接状态,向服务器发送确认报文
客户端是在收到确认请求后,先建立连接
服务器是在收到最后客户端的确认后,建立连接
发起连接请求的一定是客户端
之所以把集合单独列出来,是因为集合这块是高频中的高频,如果说前面的知识被面试到的概率是看面试官心情的话,那么这块就是面试官必问,鄙人面试了这么多次,可以说是没有一个面试官不问的!!!
答:Map接口和Collection接口是所有集合框架的父接口:
Collection接口的子接口包括:Set接口和List接口
Map接口的实现类主要有:HashMap、TreeMap、Hashtable等,常用实现方式有:HashMap和TreeMap
Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等,常用实现方式有:HashSet和TreeSet
List接口的实现类主要有:ArrayList、LinkedList等,常用实现方式有:ArrayList和LinkedList
1. 是否保证线程安全: ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
2. 底层数据结构: Arraylist 底层使用的是Object数组;LinkedList 底层使用的是双向循环链表数据结构;
3. 插入和删除是否受元素位置的影响: ① ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。 比如:执行add(E e)方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话(add(int index, E element))时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② LinkedList 采用链表存储,所以插入,删除元素时间复杂度不受元素位置的影响,都是近似 O(1)而数组为近似 O(n)。
4. 是否支持快速随机访问: LinkedList 不支持高效的随机元素访问,而ArrayList 实现了RandmoAccess 接口,所以有随机访问功能。快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
5. 内存空间占用: ArrayList的空 间浪费主要体现在在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。
Vector的线程同步,效率低
HashMap 是非线程安全的,HashTable 是线程安全的;HashTable 内部的方法基本都经过 synchronized 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap 吧!);
效率: 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。
HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。但是在 HashTable 中 put 进的键值只要有一个 null,直接抛出 NullPointerException。
①创建时如果不指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小。也就是说 HashMap 总是使用2的幂作为哈希表的大小底
层数据结构:JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。
Collection接口继承自Iterable接口,Iterable接口中有个抽象方法交iterator(),这个方法的返回值是Iterator,如ArrayList类,实现了Iterable接口,重写了iterator()
//第一种:普遍使用,二次取值
System.out.println("通过Map.keySet遍历key和value:");
for(String key : map.keySet()) {
System.out.println("key= "+ key + " and value= "+ map.get(key));
}
//第二种
System.out.println("通过Map.entrySet使用iterator遍历key和value:");
Iterator> it = map.entrySet().iterator();
while(it.hasNext()) {
Map.Entry entry = it.next();
System.out.println("key= "+ entry.getKey() +" and value= "+ entry.getValue());
}
//第三种:推荐,尤其是容量大时
System.out.println("通过Map.entrySet遍历key和value");
for(Map.Entry entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() +" and value= "+ entry.getValue());
}