1. JDK和JRE是什么,分别有什么作用?
    JDK:Java Developement Kit是Java的标准开发包,普通用户只需要安装JRE来运行Java程序。
    JRE:Java runtime environment 是运行基于Java语言编写的程序的运行环境,用于执行字节码文件。
  2. Java中什么样的标示符是合法的?
    由数字、字母、下划线和美元符号组成的标识符是合法的,但是不能以数字开头,且不能使用Java中的关键字。
  3. Java中的数据类型有哪些?
    四类八种:
    整型:byte、short、int、long
    浮点型:float、double
    布尔型:Boolean
    字符型:char
  4. 隐式类型转换和显示类型转换的区别?
    隐式类型转换(自动类型转换):由系统自动完成类型的转换,从存储范围小的类型到存储范围大的类型转换。
    显示类型转换(强制类型转换):由我们手动转换类型,从存储范围大的类型到存储范围小的类型转换。
  5. 为什么说Java语言是跨平台的?
    Java语言一次编译,处处运行,平台上只要提供并且安装了相对应的虚拟机就可以执行。
  6. HashMap和Hashtable有什么区别?
    Hashmap底层是数据+链表结构,存在形式是以键值对的形式存在的,可以存null键和null值,不保证元素的顺序不变,通过hashcode和equals方法来保证键的唯一性,且实现不同步,线程不安全。
    Hashtable中的方法是同步的,所以在多线程并发的环境下,可以直接使用。且key和value不允许出现null值,哈希值的使用不同,hashtable直接使用对象的hashcode,而hashmap是重新计算hash值的。且hashmap数组默认大小是16, hashtable数组默认大小是11。
  7. Java中哪些集合类是线程安全的?
    Vector:底层是数组实现的,是多线程安全的,Vector类中的方法很多都用了synchronized关键字进行了修饰。
    Hashtable:在对应的方法上使用了synchronized关键字进行了修饰。
    ConcurrentHashMap:引入了分段锁,所以线程安全。
    Stack:栈,继承于Vector。
  8. 并行和并发有什么区别?
    并行:同一时刻执行多个事件,多个处理器同时处理多个不同的任务。
    并发:一个处理器可以同时处理多个任务,同一时间段内交替执行多个事件。
  9. 线程中sleep和wait方法有什么区别?
    sleep方法是让正在执行的线程主动让住cpu,而且不会释放同步资源。
    wait方法则是让当前线程暂时退出同步资源,以便其他正在等待该资源的线程而运行。
  10. Jdbc的执行流程
    加载数据库连接驱动
    获取数据连接对象
    执行sql,获取sql会话对象
    执行处理结果集
    关闭结果集、关闭会话、关闭连接
    资源关闭时,遵循先开后关的原则
  11. 什么情况下会发生栈内存溢出?
    栈是线程私有的,生命周期与线程相同,方法在被创建的时候,会创建一个控件,用来存储局部变量等,所有方法的递归调用都会产生栈内存溢出。
  12. ArrayList和LinkedList的区别
    ArrayList:基于动态数组实现的,所以可以动态扩容,因为地址连续,在内存里是连着放的,查找快,增删慢。
    LinkedList:基于链表实现的,地址是任意的,查找慢,增删快。
  13. 创建线程的方式有哪些?
    继承Thread类创建线程
    通过Runnable接口创建线程类
    通过Callable和Future线程
  14. 线程池的工作原理及好处有哪些?
    当线程池创建后,线程池中的线程数为空,当任务提交给线程池后,处理策略分别为:
    如果此时线程池中的数量小于corePoolSize,就要创建一个线程来执行该任务。
    如果此时线程池中的数量大于等于corePoolSize,但是workQueue未满,则放入缓冲队列,等待空闲的线程将其取出执行。
    如果此时线程池中的数量大于等与corePoolSize,但是缓冲队列满了,则创建新的线程来处理被添加的任务。
  15. 线程的生命周期
    新建、就绪、运行、死亡、阻塞
    正在睡眠:用sleep(long t)方法可以使线程进入睡眠方式,一个睡眠的线程在指定的时间过去后可进入就绪状态。
    正在等待:调用wait()方法,调用notify()方法回到就绪状态。
  16. 乐观锁和悲观锁
    乐观锁:每次获取数据时,都不会担心数据被修改,所以每次获取数据的时候都不会进行加锁,但是在更新数据的时候,要进行判断该数据是否被别人修改过。
    悲观锁:比较适合读取比较频繁的场景,如果出现大量的写入操作,数据发生冲突的可能性就会增大,为了保证数据的一致性,应用层需要不断的更新获取数据,这样会增加大量的查询操作,降低了系统的吞吐量。