基础篇
基本功
- 面向对象的特征
- 抽象:抽象是将一类事物的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两个方面。抽象只关注对象的属性和行为,不关心这些行为的具体细节。
- 继承:继承是从已知类得到信息继承信息创建新类的过程。提供继承信息的类成为超类或者父类;得到继承信息的成为子类或者派生类。继承让变化中的软件系统有了一定的延展性,同时继承也是封装程序中可变因素的重要手段。
- 封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的方法只能定义的接口。在类中编写方法就是对实现细节的一种封装。可以说封装就是隐藏可隐藏的东西,只对外面提供最简单的接口。
- 多态:不同子类型的对象对同一行为做出不同的响应,简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态分为运行时多态和编译时多态,方法重写(override)实现的允许时多态,方法重载(overload)实现的编译时多态。
- final,finally,finalize的区别
- final:final可以修饰类,方法和属性,修饰类时表示该类不能被继承,修饰方法时表示该方法不能被子类覆盖,修饰属性时表示该属性为一个常量,给定初值后该常量的引用就不能被修改。
- finally:总是和try…catch..语句块一起使用,无论代码是否发生异常,finally中的语句总是被执行,可以将释放资源的代码放在finally块中
- finalize:finalize是Object类中定义的方法,Java允许在垃圾回收器清理对象时使用finalize()方法做一些必须的清理工作。
- int和Integer的区别
int是Java中一个基本数据类型,Integer是int对应的包装器类型,Java5开始引入了自动拆箱/装箱机制,是的两者可以相互转换。包装器类型的目的可以将基本数据类型当做对象来操作。
其他的基本数据类型:byte、short、long、char、boolean、float、double
对应的包装器类型为:Byte、Short、Long、Character、Boolean、Folat、Double
- 重载和重写的区别
重载(overload)和重写(overwrite)都是实现多态的方式,重载实现的编译时多态,而重写实现的是运行时多态。重载发生在一个类中,同名的方法如果有不同的参数列表则可视为重载,重载不能工具返回值类型进行区分。重写发生在父类和子类之间,被重新的方法与父类被重新的方法具有相同的返回值类型,要具有更大的范围权限,要比父类被重新方法抛出更少的异常。
- 抽象类和接口的区别
抽象类和接口都不能实例化,但是能够定义抽象类和接口类型的引用。抽象类可以有构造方法,可以包含抽象方法和具体方法,但是接口不能定义构造函数,接口中的方法全部都是抽象方法。抽象类中可以定义普通成员变量,接口中的成员变量实际上为常量。抽象类中的方法可以是public、protected、默认、private的,而接口中的方法只能是public的。有抽象方法的的类必须是抽象类,抽象类中可以没有抽象方法。
- 反射的用途和实现
- 自定义注解的场景及实现
- HTTP的GET和POST方式的区别
- GET用于向服务器请求数据,POST用于向服务器提交数据
- GET请求的数据会跟在URL后面,POST提交的数据会放在HTTP Body中
- GET提交的数据量较小,POST提交的数据较大
- POST安全性要比GET安全性高。
详见:浅谈HTTP中Get与Post的区别
- session和cookie的区别
详见:理解Cookie和Session机制
- session分布式处理
集群/分布式环境下5种session处理策略
- JDBC流程
a. 注册驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
b. 创建连接
Connection con = DriverManager.getConnection("jdbc.oracle:thin:@localhost:1521:orcl""name", "password");
c. 创建查询语句
PreparedStatement ps = con.prepareStatement("select * from emp where sal between ? and ?");
ps.setInt(1, 1000);
ps.setInt(2, 3000);
d. 执行语句
ResultSet rs = ps.executeQuery();
e. 处理结果集
while (rs.next()) {
System.out.println(rs.getInt("empno") + "-" + rs.getString("ename"));
}
f. 关闭连接
finally {
if (con != null) {
try {
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
equals与==区别
- equals比较两个对象的内容是否相等,equals()方法来自Object类,该方法使用==比较两对象,所有使用equals比较对象之前通常需要重写该方法,同时应该重写hashCode()方法。
- 用==比较基本类型的时候,比较基本类型的数值是否相等。当比较对象时,比较的是两个对象在内存的地址是否相等。
- 两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
不对,如果两个对象通过equals()比较返回结果为true,那么它们的hash code应该相等。如果两个对象的hash code相等,那这两个对象并一定相同。
equals()方法应该遵循自反性(x.equals(x)必须返回true)、对称性(x.equals(y)返回true时,y.equals(x)也必须返回true)、传递性(x.equals(y)和y.equals(z)都返回true时,x.equals(z)也必须返回true)和一致性(多次调用x.equals(y)返回的结果相同)。
- &和&&区别
&
运算符有两种用法:(1)按位与;(2) 非短路逻辑与。&&
运算符为短路与。相对的|
运算符也有两种用法:(1)按位或;(2)非短路逻辑或。同样||
运算符为短路逻辑或。
- String和StringBulider、StringBuffer区别
- 三个类都为final类,不能被继承
- String引用的字符串内容是不能被改变的,而StringBulider和StringBuffer内容可以改变
- StringBuffer是线程安全的,StringBulider是非线性安全的
- Error和Exception有什么区别
Error表示系统级的错误和程序不必处理的异常,恢复很困难的一种严重问题。Exception表示需要捕获或者程序进行处理的异常,是一种设计或者实现问题。
集合
- List和Set区别
- List和Set都实现了Collection接口。
- List中允许存在重复元素,允许存在多个null元素,List中的元素是有序的。常用的实现类有ArrayList、LinkedList和Vector。
- Set中不允许存在重复元素,最多只能包含一个null元素,Set中的元素是无序的。Set常用的实现类有HashSet、LinkedHashSet、TreeSet。
- List和Map区别
- List继承自Collection接口。
- Map集合是以Key-Value键值对的形式存储数据的。
- ArrayList与LinkedList的区别
- 都是Collection接口的实现类,ArrayList内部使用数组实现,LinkedList是基于链表的数据结构。
- ArrayList可以对数据进行随机存取,此时效率高于LinkedList。LinkedList不支持随机存取,但由于LinkedList是基于链表的数据结构,所以在元素的删除和添加上效率要高于ArrayList。
- ArrayList与Vector区别
- ArrayList不是线程安全的,Vector是线程安全的。
- 默认情况下,在内部数组空间不足的时,ArrayList会在原来的基础上扩展0.5倍,Vector会在原来的基础上扩展1倍。
- HashMap和Hashtable的区别
- HashMap不是线程安全的,Hashtable是线程安全的。
- HashMap允许key或value为null,Hashtable不允许key和value为空,会报空指针异常。
- Hashtable直接使用对象的hashcode,HashMap会重新计算hashcode。
- HashMap的iterator迭代器执行快速失败机制,也就是说在迭代过程中修改集合结构,除非调用迭代器自身的remove方法,否则以其他任何方式的修改都将抛出并发修改异常。而Hashtable返回的Enumeration不是快速失败的。
- HashSet和HashMap区别
HashSet内部使用HashMap实现
- HashMap和ConcurrentHashMap的区别
- HashMap的工作原理及代码实现
- ConcurrentHashMap的工作原理及代码实现
Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析
线程
线程的创建方式及实现
Java5以前实现多线程的方法有两种:一种是继承Thread类,另一种实现Runnable接口。两种方式都要重写run()方法来定义线程的行为。推荐使用后者,因为Java为单继承,如果继承了Thread类就无法继承别的类,使用Runnable接口更为灵活。Java5之后还可以使用Callable接口创建线程,该接口中的call()方法会返回线程执行结果。sleep()、join()、yield()有什么区别
- sleep()方法给其他线程运行机会不会考虑到优先级,因此也会给低优先级的线程执行机会;yeild()方法只会给和自己相同或者高优先级的线程执行机会。
- 线程执行完sleep()方法后转入阻塞(blocked)状态,而执行yield()方法后转入就绪状态(runnable)。
- sleep()方法声明抛出了InterruptedException异常, yeild()方法没有声明抛出异常。
- join()方法会使当前线程等待调用join()方法的线程执行结束后才能执行。
- sleep()和wait()的区别
- sleep()为Thread类的静态方法,wait()为Object类中的方法。
- sleep()方法不会释放锁对象,wait()方法会释放锁对象。wait()方法通常和notify()、notifyAll()方法一起使用,这三个方法通常用于协调多线程中的共享数据,所以必须在synchronized语句块中使用,使用之前必须获取锁对象。当调用某一对象的wait()方法,该线程会暂停,并将当前线程放入对象等待池中,直到调用了notify()方法后,将从等待池中移除任意一个线程放入锁等待池中,只有当锁等待池中的线程获得锁后才能运行。当调用了notifyAll()方法,会将对象等待池中的所有线程移到锁等待池中。
- 说说CountDownLatch原理
并发工具类(一)等待多线程完成的CountDownLatch
- 说说CycliBarrier原理
并发工具类(二)同步屏障CyclicBarrier
- 说说Semaphore原理
并发工具类(三)控制并发线程数的Semaphore
- 说说ExChanger原理
并发工具类(四)两个线程进行数据交换的Exchanger
- 说说CountDownLatch与CyclicBarrier区别
- CountDownLatch和CyclicBarrier都是实现线程间的等待,但两者有不同的侧重点:CountDownLatch一般用于某个线程等待其他若干个线程执行玩再继续执行;CyclicBarrier一般用于多个线程相互等待至某个状态,然后这一组线程再同时执行。
- CountDownLatch不能重用,CyclicBarrier可以重用。
- ThreadLocal原理分析
一个故事讲明白线程的私家领地:ThreadLocal
讲讲线程池的实现原理
线程池的好处:- 线程是稀缺资源,不能频繁创建
- 将线程放入线程池中,可以交给其他任务进行复用
- 解耦,线程的创建与执行完全分开,便于维护
创建一个线程池:
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler)
corePoolSize
为核心线程数大小
maximumPoolSize
为线程池最大线程数大小
keepAliveTime
和unit
为线程空闲后的存活时间
workQueue
为存放任务的阻塞队列
handler
为队列和最大线程数都满了后的饱和策略
常见的饱和策略:直接丢弃任务、调用者线程执行、丢弃队列中的最近任务执行当前任务
线程池原理分析
深度解读 java 线程池设计思想及源码实现
- 创建线程池的几种方式
- 线程的生命周期
锁机制
- 线程安全问题
- volatile实现原理
面试必问的volatile,你了解多少
漫画:什么是volatile关键字?(整合版) - synchronized实现原理
synchronized关键字原理 - synchronized与lock的区别
- CAS乐观锁
- ABA问题
漫画:什么是 CAS 机制?
漫画:什么是CAS机制?(进阶篇) - 乐观锁的业务场景及实现方式