Java面试考点

Posted by Bokala on September 1, 2016

一、Java基础概念

1.Java的优点

简单、高效; 面向对象; 平台无关性; 交互式特性; 多线程机制; 动态的内存管理机制; 安全性;JVM

  • 简单:提供多种基本方法,去除了类似于头文件、指针变量、结构、运算符重载、多重继承等复杂的面向对象特性;
  • 高效:Java利用具体的面向对象方法描述用户的动作;
  • 面向对象:Java程序用类 class 来定义各种对象行为,支持继承;
  • 平台无关:Java解释器对生成字节码的解释执行,因此具有强鲁棒性;
  • 交互式特性:支持 TCP/IP 协议,使得用户可以通过浏览器访问到 Internet 上的各种动态对象;
  • 多线程机制:Java 程序可以设计成具有多个线程,例如让一个线程负责数据的检索、查寻,另一个线程与用户进行交互,这样,两个线程得以并行执行,多线程机制可以很容易地实现网络上的交互式操作; 动态的内存管理机制:Java采用自动垃圾回收机制进行内存管理;
  • 安全性:Java 语言在安全性方面引入了实时内存分配及布局来防止程序员直接修改物理内存布局;通过字节代码验证器对字节代码的检验,以防止网络病毒及其它非法代码侵入,Java还采用了许多面向对象的异常处理机制,负责对一些异常事件进行处理。

2.Java虚拟机

Java虚拟机是一个可以执行Java字节码的虚拟机进程,故Java没有平台限制。

3.JDK、JRE和JVM

  • JDK–Java开发工具包:Java 环境的核心组件,并提供编译、调试和运行一个 Java 程序所需的所有工具,可执行文件和二进制文件
  • JRE–Java运行时环境:JRE 是 JVM 的实施实现,它提供了运行 Java 程序的平台。
  • JVM–Java虚拟机:Java 编程语言的核心,JVM 负责将字节码转换为特定机器代码,提供了一个不依赖于底层操作系统和机器硬件的接口。

    4.Java基本数据类型

  • byte
  • short
  • int
  • long
  • float
  • double
  • boolean
  • char

5.静态变量和实例变量

  • 语法定义区别:静态变量前需加 static
  • 运行时区别:实例变量 属于对象的属性,只有创建了对象实例,类中定义的实例变量才能被分配到内存空间,才能使用这个变量;静态变量 属于类而不属于对象,是类变量,只要程序加载了类的字节码,静态变量就会被分配到内存空间。
  • 具体使用:实例变量 通过对象引用,静态变量 通过类引用。

6.创建对象方法

  • new() 方法(调用构造函数)
  • 反射手段(调用构造函数):调用 java.lang.Classjava.lang.reflect.Constructor 类的 newInstance()实例方法
  • 对象的 clone() 方法(不调用构造函数)
  • 反序列化手段(不调用构造函数):调用 java.io.ObjectInputStream 对象的 readObject() 方法

7.对象克隆

  • 实现 Cloneable 接口,重写Object类中的clone()方法
  • 实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,真正的深度克隆

二、集合类

1.Java集合类框架的基本接口

Collection, Set, List,Map

2.IteratorListIterator

  • Iterator 可用来遍历SetList集合,但 ListIterator只用来遍历List
  • Iterator 是前向遍历,而ListIterator可实现双向遍历

3.HashMap 工作原理

Java 中的 HashMap 是以键值对(key-value)的形式存储元素的,通过hashCode()equals() 方法向集合添加、检索元素。

4.HashMapHashTable

  • HashMapHashTable 均实现了 map接口
  • HashMap允许键和值是null,而HashTable 不允许
  • HashTable 是线程同步的,而HashMap不是
  • HashMap提供了可供迭代的键的集合,HashTable提供了对键的列举

5.ArrayListLinkedList

  • ArrayListLinkedList 都实现了 List 接口
  • ArrayList 是基于索引的接口,,底层是数组,查找复杂度为 O(1),而 LinkedList 是以元素列表形式进行存储的,查找复杂度为 O(n)

三、异常处理

1.Java异常处理

Java中的异常都是对象,为Throwable类或其子类的实例;具体实现通过try, catch, throw, throws, finally关键字的实现。

  1. try 用来指定一段具有“异常”的执行程序
  2. catch 用来指定想要捕捉的“异常”类型
  3. throw 用来抛出一个“异常”
  4. throws 用来标明一个成员函数可能抛出的所有“异常”
  5. finally 用来确保一段肯定执行的代码

2.常见的 runtime exception

  • NullPointerException:空引用错误
  • NumberFormatException:数据格式转换出现问题时出现此异常
  • ClassCastException:强制类型转换类型不匹配时出现此异常
  • ArrayIndexOutOfBoundsException:数组下标越界,当使用一个不存在的数组下标时出现此异常
  • ArithmeticException:数学运行错误时出现此异常

四、多线程

1.创建线程

  • 继承 Thread
  • 实现 Runnable 接口
  • 应用程序使用 Executor 框架创建线程池

2.线程的可用状态

  • 就绪(Ready):线程准备运行,不一定立马就能开始执行
  • 运行中(Running):进程正在执行线程的代码
  • 等待中(Waiting):线程处于阻塞的状态,等待外部的处理结束
  • 睡眠中(Sleeping):线程被强制睡眠
  • I/O阻塞(Blocked on I/O):等待I/O操作完成
  • 同步阻塞(Blocked on Synchronization):等待获取锁
  • 死亡(Dead):线程完成了执行

3.死锁(deadlock)

两个进程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是两个进程都陷入了无限的等待中

产生死锁的必要条件:

  1. 互斥条件:一个资源每次只能被一个进程使用
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
  3. 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

解决方案:

  1. 撤消陷于死锁的全部进程
  2. 逐个撤消陷于死锁的进程,直到死锁不存在
  3. 从陷于死锁的进程中逐个强迫放弃所占用的资源,直至死锁消失
  4. 从另外一些进程那里强行剥夺足够数量的资源分配给死锁进程,以解除死锁状态

如何确保多个线程同时访问相同资源时不会死锁

获取指定锁的顺序,强制线程按照指定的顺序获取锁,所有的线程以同样的顺序加锁和释放锁,就可以避免死锁

4.sleep(), wait()yield()

  • sleep()Thread 类的静态方法,用于在指定时间内暂停线程,时间结束后恢复就绪状态
  • wait()Object 类的方法,调用该方法克导致该线程放弃对象锁(线程暂停执行),进入到等待锁定池,只有针对此对象发出notify() 方法后才能进入到对象池准备获得对象锁进入就绪状态

  • 线程执行 sleep() 方法后转入阻塞(blocked)状态,而执行 yield() 方法后转入就绪(ready)状态
  • sleep() 方法声明抛出InterruptedException,而 yield() 方法没有声明任何异常
  • sleep() 方法比 yield() 方法更具有更好的可移植性

5.线程池

事先创建若干个可执行的线程放入一个池(容器)中,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销。