1. 重载和重写的区别:
1.重载发生在同一个类中,同名的方法中如果有不同的参数列表(个数不同,顺序不同,类型不同)则视为重载
2.重写发生在子类和父类之间,重写之后的子类要求与父类被重写的方法有相同的返回类型,
比父类重写的方法更好访问,且不能比父类重写的方法声明更多的异常。
2. String 和 StringBuffer、StringBuilder 的区别是什么
1.可变性
String类使用关键字final修饰字符数组来保存字符串,所以String对象是不可变的
StringBuffer和StringBuilder都继承自AbstractStringBuilder类,
在AbstractStringBuilder类中是使用字符数组char[]保存字符串的,
但是没有使用final关键字修饰,所以这两种对象是可变的。
2.线程安全性
String类中的对象是不可变的,可以理解为常量,所以线程安全
StringBuffer类对方法加了同步锁或者对调用的方法加了同步锁,所以线程安全。
StringBuilder并没有对方法加同步锁,所以线程不安全。
3.性能
每次对String类型进行改变的时候,都会重新创建新的String对象,然后将指针指向新的String对象。
StringBuffer每次都会对StringBuffer对象自身操作,不会创建新的对象。
相同情况下,使用StringBuilder会比使用StringBuffer提升10%-15%的性能,但却要冒多线程不安全的风险
3. == 与 equals 的区别?
==对于基本数据类型和引用类型来说作用是不同的,
对于基本数据类型来说,使用==比较的两个值是否相等,
对于引用类型来说,使用==比较的是引用地址是否相等。
equals本质是==,只是String,Integer等重写了equals(),把它变成了值比较
4. 说说自己是怎么使用synchronized 关键字,在项目中用到了吗?
修饰实例方法,作用于当前对象实例加锁,在进入同步代码块前获取对象实例的锁。
修饰静态方法,作用于当前类对象加锁,在进入同步代码块前获取类对象的锁。
修饰代码块,指定加锁对象,对给定加锁对象,在进入同步代码块前获取给定加锁对象的锁。
项目中使用:双重校验锁实现对象单例(线程安全)
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {
}
public static Singleton getUniqueInstance() {
//先判断对象是否已经实例过,没有实例化过才进入加锁代码
if (uniqueInstance == null) { //类对象加锁
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance; 123456789101112131415161718
}
5. 抽象类和接口的区别是什么?
1.实现:抽象类的子类使用extends继承父类,接口使用implements实现接口。
2.构造方法:抽象类可以有构造方法,接口不能有构造方法。
3.实现个数量:类可以实现多个接口,但只能继承一个抽象类(Java只支持单继承 )
4.访问修饰符:接口中的方法默认为public修饰,抽象类中的方法可以使用public和protected修饰,但使用private修饰则会报错,
接口中除了final、static变量不能有其他变量,而抽象类则不一定
5.设计层面:抽象类是对类的抽象,是一种模板设计。接口是对行为的抽象,是一种行为规范。
6. Collection 和 Collections 有什么区别?
1.Collection是一个集合接口,它提供了对集合进行基本操作的通用接口方法,所有的集合都是它的子类,比如List、Set等。
2.Collecitons是一个包装类,提供了很多静态方法,不能被实例化,就像是一个包装类,
比如提供的排序方法:Collections.sort(list).
7. List、Set、Map 之间的区别是什么?
三者最主要的区别是 元素是否有序,是否允许元素重复
8. HashMap 和 Hashtable 有什么区别?
1.存储:HashMap允许key和value为null ,Hashtable不允许
2.线程安全:Hashtable线程安全,HashMap线程不安全
3.推荐使用: 在Hashtable的类注释中,可以看到Hashtable是一个保留类,不推荐使用,
推荐在单线程环境下使用HashMap,多线程中推荐使用ConcurrentHashMap;
9. 说一下 HashMap 的实现原理?
HashMap是基于hash算法实现的,HashMap通过put(key,value)存储元素,使用get(key)获取元素。
当传入key值时,通过key.hashcode()计算出hash值,根据hash值,将value保存在bucket。
当计算出来的hash值相同时,则称之为hash冲突,通常使用链表和红黑树解决hash冲突。
当冲突个数少时使用链表,否则使用红黑树。
10. 说一下 HashSet 的实现原理?
HashSet是基于HashMap实现的,HashSet底层使用HashMap保存数据的,因此HashSet的实现比较简单。
关于HashSet的操作,直接调用底层HashMap中的方法完成。HashSet不允许元素重复。
11.ArrayList和LinkedList的区别?
ArrayList:
ArrayList是基于动态数组的,连续内存存储,随机访问元素。
扩容机制:因为数组长度固定,超出数组长度就要重新创建新的数组,将老的数组中的元素复制到新的数组中。
如果不是尾部插入数据,还会涉及到元素的移动,所以使用尾插法并指定初始容量,可以极大提升性能,甚至超过LinkedList.
LinkedList:
LinkedList是基于链表,可以存储在分散的内存中,适合做添加、删除元素,不适合做查询,
因为查询会逐一遍历元素,遍历LinkedList必须使用iterator接口,不能使用for循环,
因为在for循环体内,通过get(i)获取元素时,都需要重新遍历list链表,性能消耗极大。
12.ConcurrentHashMap原理解析,jdk7和jdk8版本的区别
jdk7:
数据结构:ReentrantLock+Segement+HashEntry,每一个Segement中都包含一个HashEntry数组,每一个HashEntry
又是链表结构。
元素查询:二次Hash,第一次Hash定位在Segement上,第二次查询定位在元素所在的链表头部。
锁: 采用Segement分段锁,Segement继承了ReentrantLock,锁定操作的Segement,不影响其他的Segement,
并发数为Segement的个数,可以通过构造函数指定,数组扩容时不会影响其他Segement,
get方法无需加锁,Volatile保证。
jdk8:
数据结构:红黑树+CAS+Node+Synchronized ,Node中的val和next都是用volatile修饰,保证可见性
元素查询: 替换和赋值都是用CAS
锁: 锁定链表的头节点,不影响其他元素的读写操作,锁粒度更细,效率更高,扩容时,阻塞所有读写操作,并发扩容。
读操作无锁:Node的val和next使用volatile修饰,保证读写操作对该变量互相可见
数组使用volatile修饰,保证扩容时被读线程感知。
13.哪些集合类是线程安全的?
Hashtable、Stack、Vector都是线程安全的,HashMap是线程不安全,但自jdk1.5之后,随着java.util.concurrent并发包的出现,
它们也有了自己对应的线程安全类,比如:HashMap的线程安全类就是ConcurrentHashMap。
14.创建线程有哪几种方式?
1. 继承Thread实现run()
2. 实现runnable接口
3. 实现callable接口
15.说一下 runnable 和 callable有什么区别?
runnable没有返回值,callable可以拿到返回值,callable可以看作是runnable的补充。
16. 线程有哪些状态?
创建线程对象时,线程进入新建状态;当调用线程对象的start()方法时,线程进入就绪状态;
当cpu获得时间片时,线程进入运行状态;
当线程调用wait()或者sleep()方法时,线程进入阻塞状态;
当休眠时间结束,或者线程调用notify()或者notifyAll()方法时,
线程会从阻塞状态进入就绪状态,在重新获取时间片,进入运行状态;
当线程执行完毕,或者因异常退出run()方法,则线程生命周期结束,进入终止状态。
17. sleep() 和wait() 有什么区别?
1. sleep()方法来自于Thread,而wait()方法来自于Object
2. sleep()不是放锁,而wait()释放锁。
3. 用法不同:sleep()时间到了会自动恢复,而wait()使用notify或notifyAll()直接唤醒
18. notify()和 notifyAll()有什么区别?
notify唤醒一个线程,而notifyAll()唤醒全部线程。
notifyAll()会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功,则继续执行,否则继续留在锁池等待锁被释放后,
重新参与锁的竞争。
notify只会唤醒一个线程,具体唤醒哪个线程,由虚拟机决定。
19.线程的 run() 和 start() 有什么区别?
start()方法用于启动线程,而run()方法用于执行线程的运行时代码,run()可以重复调用,而start()只能调用一次。
20.说一说几种常见的线程池及适用场景?
FixedThreadPool:
用于固定线程数的线程池,适合用于负载较重的服务器。
SingleThreadExexutor:
只会创建一个线程执行任务,适用于需要保证顺序执行各个任务,
并且在任意时间点没有多线程活动的场景。
CachedThreadPool:
是一个会根据需要调整线程数量的线程池。
大小无界,适用于执行很多的短期异步任务的小程序,或负载较轻的服务器。
ScheduledThreadPool:
继承自ThreadPoolExecutor.
它主要用来在给定的延迟之后运行任务,或者定期执行任务。
使用DelayQueue作为任务队列。
21. 线程池中 submit() 和 execute() 方法有什么区别?
execute()适用于runnable类型任务
submit()适用于runnable类型和callable类型任务
runnable类型无返回值,callable类型任务可以拿到返回值。
22. 在 Java 程序中怎么保证多线程的运行安全
1. 使用安全类,比如java.until.concurrent并发类
2. 使用synchronized自动锁
3. 使用手动锁Lock
23. 什么是死锁?
当线程A持有独占锁a,并尝试去获取独占锁b的同时,线程B持有独占锁b,并尝试获取独占锁a的情况下,
就会发生由于线程AB互相持有对方所需要的锁,而发生阻塞现象,则称之为死锁。
24. 怎么防止死锁?
1. 尽量使用tryLock(long timeout, TimeUnit unit)下方法ReentrantLock或者ReentrantReadWriteLock设置超时时间,
超时可以退出,可防止死锁。
2. 尽量使用java.until.concurrent下的并发安全类
3. 尽量降低锁的使用粒度,尽量不要几个功能使用同一把锁。
4. 尽量减少同步代码块
25. ThreadLocal 是什么?有哪些使用场景?
ThreadLock为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立的改变自己的变量副本,
而不影响其它线程所对应的变量副本。
应用场景:数据库连接,session管理。
26. synchronized 和 Lock 有什么区别?
1. synchronized 可以给类,代码块,方法加锁,而Lock只能给方法加锁。
2. synchronized 不需要手动获取锁和释放锁,发生异常就会自动释放锁,
而lock需要手动释放锁和获取锁,如果使用不当,没有使用unlock释放锁,则会造成死锁。
3. 使用Lock可以知道有没有成功获取锁,而使用synchronized 却无法办到。
27. 什么是 Java 序列化?什么情况下需要序列化?
Java序列化就是为了保存各种对象在内存中的状态,并且可以把保存的对象状态在内存中读出来
以下情况需要使用 Java 序列化:
1.使用socket在网络传输对象的时候
2.使用RMI在网络传送对象的时候
3.想把内存中的状态保存到文件或者数据库中的时候
28. 动态代理是什么?有哪些应用?
动态代理就是运行时动态生成代理类
应用:spring中的aop、java注解对象获取、rpc
29. 怎么实现动态代理?
1. 使用JDK原生动态代理和cglib动态代理
2. JDK原生动态代理是基于接口实现的,而cglib是基于继承当前类的子类实现的
30. 为什么要使用克隆?
克隆的对象可能包含一些已经修改后的属性,而使用new创建的对象都是初始化状态,
所以当需要一个新的对象保存当前对象的状态时,就靠克隆方法了。
31. session 和 cookie 有什么区别?
1. 存储位置不同:session是保存在服务器端,cookie保存在浏览器端
2. 安全性不同:cookie的安全性一般,可以被伪造和修改
3. 容量和个数限制:cookie有容量限制,每个站点下的cookie也容量限制
4. 存储的多样性:session可以保存在redis、数据库、应用程序中,cookie只能保存在浏览器端
32. 如何避免 SQL 注入?
1. 使用预处理 preparedstatement
2. 使用正则表达式过滤掉字符中的特殊字符
33. throw 和 throws 的区别?
throw是真实抛出一个异常
throws是声明可能会抛出一个异常
34. final、finally、finalize 有什么区别?
1. final:是修饰符,如果修饰类,此类不能被继承;
如果修饰方法和变量,则表示此方法和此变量不能在被改变,只能使用。
2. finally:是try{}catch{}finally{}最后一部分,表示不论发生任何情况都会执行,
finally部分可以省略,
但如果finally部分存在,则一定会执行finally里面的代码。
3. finalize:是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法。
35. 常见的异常类有哪些?
1. NullPointerException 空指针异常
2. ClassNotFoundException 指定类不存在
3. NumberFormatException 字符串转换为数字异常
4. IndexOutOfBoundsException 数组下标越界异常
5. ClassCastException 数据类型转换异常
6. FileNotFoundException 文件未找到异常
7. NoSuchMethodException 方法不存在异常
8. IOException IO 异常
9.SocketException Socket异常
36. 说一下你熟悉的设计模式?
1. 单例模式:保证被创建一次,节省系统资源
2. 工厂模式:解耦代码
3. 观察者模式:定义对象之间一对多的依赖关系,
这样一来,当一个改变时,所有的依赖着都会收到通知并自动改变
4. 外观模式:提供一个统一接口,用来访问子接口中的一群接口,
外观定义了一个高层的接口,让子系统更容易使用。
5. 模板方法模式:定义一个算法骨架,而将一些具体步骤延申到子类中,
模板方法模式使得子类在不改变算法结构的情况下,重新定义算法的执行步骤
6. 代理模式:代理模式给某一个对象提供了一个代理对象,并由代理对象控制对原对象的引用。
37. spring框架使用了那些设计模式
1.spring的bean的创建默认使用单例模式
2.spring中获取bean对象通过的是工厂模式
3.spring的aop采用的是动态代理模式
4.在各种BeanFactory以及ApplicationContext实现中也都用到模板模式;
38. 为什么要使用 spring?
1. spring提供ioc技术,容器会帮你管理依赖的对象,从而不需要自己创建和管理依赖对象了,
更轻松的实现了程序的解耦。
2. spring提供了事务支持,使得事务操作变的更加方便。
3. spring提供了面向切片编程,这样可以更方便的处理某一类的问题。
4. 更方便的框架集成,spring可以很方便的集成其他框架,比如MyBatis、hibernate等。
39. spring常用的注入方式有哪些?
1. setter属性注入
2. 构造方法注入
3. 注解方式注入
40. spring 事务实现方式有哪些?
1. 声明式事务:声明式事务也有两种实现方式,
基于xml配置文件的方式和注解方式(在类上添加@Transaction注解)。
2. 编码方式:提供编码的形式管理和维护事务