1.Java IO 与 NIO 的区别(补充)
NIO 即 New IO ,这个库是在 JDK1.4 中才引入的。 NIO 和 IO 有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以 NIO 的效率要比 IO 高很多。在 Java API 中提供了两套 NIO ,一套是针对标准输入输出NIO ,另一套就是网络编程 NIO 。
2 、 java 反射的作用于原理
1 、定义:
反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象,
都能够调用它的任意一个方法。在 java 中,只要给定类的名字,就可以通过反射机制来获得类的所
有信息。
这种动态获取的信息以及动态调用对象的方法的功能称为 Java 语言的反射机制。
2 、哪里会用到反射机制?
jdbc 就是典型的反射
Class . forName ( 'com.mysql.jdbc.Driver.class' ); // 加载 MySQL 的驱动类
这就是反射。如 hibernate , struts 等框架使用反射实现的。
3 、反射的实现方式:
第一步:获取 Class 对象,有 4 中方法: 1 ) Class.forName(“ 类的路径 ”) ; 2 )类名 .class 3 )对象
名 .getClass() 4 )基本类型的包装类,可以调用包装类的 Type 属性来获得该包装类的 Class 对象
4 、实现 Java 反射的类:
1 ) Class :表示正在运行的 Java 应用程序中的类和接口 注意:
所有获取对象的信息都需要 Class 类
来实现。 2 ) Field :提供有关类和接口的属性信息,以及对它的动态访问权限。 3 ) Constructor :
提供关于类的单个构造方法的信息以及它的访问权限 4 ) Method :提供类或接口中某个方法的信息
5 、反射机制的优缺点:
优点: 1 )能够运行时动态获取类的实例,提高灵活性; 2 )与动态编译结合 缺点: 1 )使用反射
性能较低,需要解析字节码,将内存中的对象进行解析。 解决方案: 1 、通过 setAccessible(true)
关闭 JDK 的安全检查来提升反射速度; 2 、多次创建一个类的实例时,有缓存会快很多 3 、
ReflflectASM 工具类,通过字节码生成的方式加快反射速度 2 )相对不安全,破坏了封装性(因为通过反射可以获得私有方法和属性)
3 、说说 List,Set,Map 三者的区别?
List( 对付顺序的好帮手 ) : List 接口存储一组不唯一(可以有多个元素引用相同的对象),有序
的对象
Set( 注重独一无二的性质 ): 不允许重复的集合。不会有多个元素引用相同的对象。
Map( 用 Key 来搜索的专家 ): 使用键值对存储。 Map 会维护与 Key 有关联的值。两个 Key 可以引
用相同的对象,但 Key 不能重复,典型的 Key 是 String 类型,但也可以是任何对象。
4. 、 Object 有哪些常用方法?大致说一下每个方法的含义
java.lang.Object 下面是对应方法的含义。
clone 方法
保护方法,实现对象的浅复制,只有实现了 Cloneable 接口才可以调用该方法,否则抛出
CloneNotSupportedException 异常,深拷贝也需要实现 Cloneable ,同时其成员变量为引用类型
的也需要实现 Cloneable ,然后重写 clone 方法。
fifinalize 方法
该方法和垃圾收集器有关系,判断一个对象是否可以被回收的最后一步就是判断是否重写了此方
法。
equals 方法
该方法使用频率非常高。一般 equals 和 == 是不一样的,但是在 Object 中两者是一样的。子类一
般都要重写这个方法。
hashCode 方法
该方法用于哈希查找,重写了 equals 方法一般都要重写 hashCode 方法,这个方法在一些具有哈
希功能的 Collection 中用到。
一般必须满足 obj1.equals(obj2)==true 。可以推出 obj1.hashCode()==obj2.hashCode() ,但是
hashCode 相等不一定就满足 equals 。不过为了提高效率,应该尽量使上面两个条件接近等价。
JDK 1.6 、 1.7 默认是返回随机数;
JDK 1.8 默认是通过和当前线程有关的一个随机数 + 三个确定值,运用 Marsaglia’s xorshift
scheme 随机数算法得到的一个随机数。
wait 方法
配合 synchronized 使用, wait 方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥
有者,也就是具有该对象的锁。 wait() 方法一直等待,直到获得锁或者被中断。 wait(long timeout)
设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生。
1. 其他线程调用了该对象的 notify 方法;
2. 其他线程调用了该对象的 notifyAll 方法;
3. 其他线程调用了 interrupt 中断该线程;
4. 时间间隔到了。
此时该线程就可以被调度了,如果是被中断的话就抛出一个 InterruptedException 异常。
notify 方法
配合 synchronized 使用,该方法唤醒在该对象上 等待队列 中的某个线程(同步队列中的线程是给
抢占 CPU 的线程,等待队列中的线程指的是等待唤醒的线程)。
notifyAll 方法
配合 synchronized 使用,该方法唤醒在该对象上等待队列中的所有线程。
总结
只要把上面几个方法熟悉就可以了, toString 和 getClass 方法可以不用去讨论它们。该题目考察的是对 Object 的熟悉程度,平时用的很多方法并没看其定义但是也在用,比如说: wait() 方法,
equals() 方法等。
大致意思: Object 是所有类的根,是所有类的父类,所有对象包括数组都实现了 Object 的方法。
5 、 Java 创建对象有几种方式?
这题目看似简单,要好好回答起来还是有点小复杂的,我们来看看,到底有哪些方式可以创建对
象?
使用 new 关键字 ,这也是我们平时使用的最多的创建对象的方式,示例:
使用反射方式创建对象 ,使用 newInstance() ,但是得处理两个异常 InstantiationException 、
IllegalAccessException :
Class Object is the root of the class hierarchy.Every class has Object as a
superclass. All objects, including arrays, implement the methods of this class.
User user=new User();
User user=User.class.newInstance();
Object object=(Object)Class.forName("java.lang.Object").newInstance()
使用 clone 方法 ,前面题目中 clone 是 Object 的方法,所以所有对象都有这个方法。
使用反序列化创建对象 ,调用 ObjectInputStream 类的 readObject() 方法。
我们反序列化一个对象, JVM 会给我们创建一个单独的对象。 JVM 创建对象并不会调用任何构造函 数。一个对象实现了 Serializable 接口,就可以把对象写入到文件中,并通过读取文件来创建对
象。
总结
创建对象的方式关键字: new 、反射、 clone 拷贝、反序列化。
6 、获取一个类 Class 对象的方式有哪些?
搞清楚类对象和实例对象,但都是对象。
第一种:通过类对象的 getClass() 方法获取,细心点的都知道,这个 getClass 是 Object 类里面的
方法。
第二种:通过类的静态成员表示,每个类都有隐含的静态成员 class 。
第三种:通过 Class 类的静态方法 forName() 方法获取。
7 、 ArrayList 和 LinkedList 的区别有哪些?
ArrayList
优点 : ArrayList 是实现了基于动态数组的数据结构,因为地址连续,一旦数据存储好了,查询
操作效率会比较高(在内存里是连着放的)。
缺点 :因为地址连续, ArrayList 要移动数据,所以插入和删除操作效率比较低。
LinkedList
User user = new User ();
//clazz 就是一个 User 的类对象
Class <?> clazz = user . getClass ();
//clazz 就是一个 User 的类对象
Class <?> clazz = User . class ;
Class <?> clazz = Class . forName ( "com.tian.User" );
优点 : LinkedList 基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等
一个连续的地址。对于新增和删除操作, LinkedList 比较占优势。 LinkedList 适用于要头尾操
作或插入指定位置的场景。
缺点 :因为 LinkedList 要移动指针,所以查询操作性能比较低。
适用场景分析
当需要对数据进行对随机访问的时候,选用 ArrayList 。
当需要对数据进行多次增加删除修改时,采用 LinkedList 。
如果容量固定,并且只会添加到尾部,不会引起扩容,优先采用 ArrayList 。
当然,绝大数业务的场景下,使用 ArrayList 就够了,但需要注意避免 ArrayList 的扩容,以及非顺
序的插入。
8 、用过 ArrayList 吗?说一下它有什么特点?
只要是搞 Java 的肯定都会回答 “ 用过 ” 。所以,回答题目的后半部分 ——ArrayList 的特点。可以从这几个方面去回答:
Java 集合框架中的一种存放相同类型的元素数据,是一种变长的集合类,基于定长数组实现,当加入数据达到一定程度后,会实行自动扩容,即扩大数组大小。
底层是使用数组实现,添加元素。
如果 add(o) ,添加到的是数组的尾部,如果要增加的数据量很大,应该使用 ensureCapacity()
方法,该方法的作用是预先设置 ArrayList 的大小,这样可以大大提高初始化速度。
如果使用 add(int,o) ,添加到某个位置,那么可能会挪动大量的数组元素,并且可能会触发扩
容机制。高并发的情况下,线程不安全。多个线程同时操作 ArrayList ,会引发不可预知的异常或错误。
ArrayList 实现了 Cloneable 接口,标识着它可以被复制。注意: ArrayList 里面的 clone() 复制其实
是浅复制。
9 、有数组了为什么还要搞个 ArrayList 呢?
通常我们在使用的时候,如果在不明确要插入多少数据的情况下,普通数组就很尴尬了,因为你不
知道需要初始化数组大小为多少,而 ArrayList 可以使用默认的大小,当元素个数到达一定程度
后,会自动扩容。
可以这么来理解:我们常说的数组是定死的数组, ArrayList 却是动态数组。
10 、说说什么是 fail-fast ?
fail-fast 机制是 Java 集合( Collection )中的一种错误机制。当多个线程对同一个集合的内容进行
操作时,就可能会产生 fail-fast 事件。
例如:当某一个线程 A 通过 iterator 去遍历某集合的过程中,若该集合的内容被其他线程所改变
了,那么线程 A 访问集合时,就会抛出 ConcurrentModifificationException 异常,产生 fail-fast 事
件。这里的操作主要是指 add 、 remove 和 clear ,对集合元素个数进行修改。
解决办法:建议使用 “java.util.concurrent 包下的类 ” 去取代 “java.util 包下的类 ” 。
可以这么理解:在遍历之前,把 modCount 记下来 expectModCount ,后面 expectModCount 去
和 modCount 进行比较,如果不相等了,证明已并发了,被修改了,于是抛出
ConcurrentModifificationException 异常。
11 、说说 Hashtable 与 HashMap 的区别
本来不想这么写标题的,但是无奈,面试官都喜欢这么问 HashMap 。
1. 出生的版本不一样, Hashtable 出生于 Java 发布的第一版本 JDK 1.0 , HashMap 出生于 JDK
1.2 。
2. 都实现了 Map 、 Cloneable 、 Serializable (当前 JDK 版本 1.8 )。
3. HashMap 继承的是 AbstractMap ,并且 AbstractMap 也实现了 Map 接口。 Hashtable 继承
Dictionary 。
4. Hashtable 中大部分 public 修饰普通方法都是 synchronized 字段修饰的,是线程安全的,
HashMap 是非线程安全的。
5. Hashtable 的 key 不能为 null , value 也不能为 null ,这个可以从 Hashtable 源码中的 put 方
法看到,判断如果 value 为 null 就直接抛出空指针异常,在 put 方法中计算 key 的 hash 值之
前并没有判断 key 为 null 的情况,那说明,这时候如果 key 为空,照样会抛出空指针异常。
6. HashMap 的 key 和 value 都可以为 null 。在计算 hash 值的时候,有判断,如果
key==null ,则其 hash=0 ;至于 value 是否为 null ,根本没有判断过。
7. Hashtable 直接使用对象的 hash 值。 hash 值是 JDK 根据对象的地址或者字符串或者数字算出
来的 int 类型的数值。然后再使用除留余数法来获得最终的位置。然而除法运算是非常耗费时
间的,效率很低。 HashMap 为了提高计算效率,将哈希表的大小固定为了 2 的幂,这样在取
模预算时,不需要做除法,只需要做位运算。位运算比除法的效率要高很多。
8. Hashtable 、 HashMap 都使用了 Iterator 。而由于历史原因, Hashtable 还使用了
Enumeration 的方式。
9. 默认情况下,初始容量不同, Hashtable 的初始长度是 11 ,之后每次扩充容量变为之前的
2n+1 ( n 为上一次的长度)而 HashMap 的初始长度为 16 ,之后每次扩充变为原来的两倍。
另外在 Hashtable 源码注释中有这么一句话:
Hashtable is synchronized. If a thread-safe implementation is not needed, it is
recommended to use HashMap in place of Hashtable . If a thread-safe highly
concurrent implementation is desired, then it is recommended to use
ConcurrentHashMap in place of Hashtable.
大致意思: Hashtable 是线程安全,推荐使用 HashMap 代替 Hashtable ;如果需要线程安全高并
发的话,推荐使用 ConcurrentHashMap 代替 Hashtable 。
这个回答完了,面试官可能会继续问: HashMap 是线程不安全的,那么在需要线程安全的情况下
还要考虑性能,有什么解决方式?
这里最好的选择就是 ConcurrentHashMap 了,但面试官肯定会叫你继续说一下
ConcurrentHashMap 数据结构以及底层原理等。