java面试经典题
1、 jdk、jre和jvm的区别
JDK是 Java 语言的软件开发工具包(SDK)。在JDK的安装目录下有一个jre目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib合起来就称为jre。
jdk:java开发工具
jre:java运行时环境
jvm:虚拟机
2、hashMap和hashTable的区别
- hashMap方法没有synchronized修饰,线程不安全
- hashTable方法使用了synchronized修饰,线程安全
- hashMap允许key和value的值为null
- hashTable不允许
hashMap底层结果为数组+链表实现
hashMap存储步骤:
- 计算Key的hash值,然后二次hash并对数组的长度取模,就得到对应的下标
- 如果的到的下标位置没有冲突,则会创建node存入数组
- 如果产生了冲突,先进行equals比较,如果相同,则取代该元素。如果不同,数据就会放入链表后面。
- key为null,存入数组下标为0的位置。
3、==和equals的区别
-
java当中的数据类型和“==”的含义
- 基本数据类型(也称原始数据类型) :byte,short,char,int,long,float,double,boolean。他们之间的比较,应用双等号(==),比较的是他们的值。
- 引用数据类型:当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址(确切的说,是堆内存地址)。
-
equals()方法介绍 JAVA当中所有的类都是继承于Object这个超类的,在Object类中定义了一个equals的方法,equals的源码是这样写的: public boolean equals(Object obj) {
return (this == obj);
}
可以看到,这个方法的初始默认行为是比较对象的内存地址值,一般来说,意义不大。所以,在一些类库当中这个方法被重写了,如String、Integer、Date。在这些类当中equals有其自身的实现(一般都是用来比较对象的成员变量值是否相同),而不再是比较类在堆内存中的存放地址了。 所以说,对于复合数据类型之间进行equals比较,在没有覆写equals方法的情况下,他们之间的比较还是内存中的存放位置的地址值,跟双等号(==)的结果相同;如果被复写,按照复写的要求来。
总结:
== 的作用:
- 基本类型:比较的就是值是否相同
- 引用类型:比较的就是地址值是否相同
equals 的作用:
注:不过,我们可以根据情况自己重写该方法。一般重写都是自动生成,比较对象的成员变量值是否相同
4、ArrayList和LinkedList区别及使用场景
LinkedList和ArrayList的差别主要来自于Array和LinkedList数据结构的不同。ArrayList是基于数组实现的,LinkedList是基于双链表实现的。另外LinkedList类不仅是List接口的实现类,可以根据索引来随机访问集合中的元素,除此之外,LinkedList还实现了Deque接口,Deque接口是Queue接口的子接口,它代表一个双向队列,因此LinkedList可以作为双向队列 ,栈(可以参见Deque提供的接口方法)和List集合使用,功能强大。
ArrayList是基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的,可以直接返回数组中index位置的元素,因此在随机访问集合元素上有较好的性能。但是要插入、删除数据却是开销很大的,因为这需要移动数组中插入位置之后的的所有元素和可能面临数组扩容的损耗。
相对于ArrayList,LinkedList的随机访问集合元素时性能较差,因为需要在双向列表中根据指针顺序找到要index的位置,再返回;但在插入,删除操作是更快的。因为LinkedList不像ArrayList一样,不需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重新装入一个新的数组。
使用场景:
(1)如果应用程序对数据有较多的随机访问,ArrayList对象要优于LinkedList对象;
( 2 ) 如果应用程序有更多的插入或者删除操作,较少的随机访问,LinkedList对象要优于ArrayList对象;
(3)不过ArrayList的插入,删除操作也不一定比LinkedList慢,如果在List靠近末尾的地方插入,那么ArrayList只需要移动较少的数据,而LinkedList则需要一直查找到列表尾部,反而耗费较多时间,这时ArrayList就比LinkedList要快。
5、泛型中extend和super的区别
- <? extends T> 表示包括T在内的任何T的子类
- <? super T> 表示T在内的任何T的父类
6、深拷贝和浅拷贝的区别
对于基本类型,深拷贝和浅拷贝都是一样的,都是对原始数据的复制,修改原始数据,不会对复制数据产生影响。
两者的区别,在于对引用属性的复制。
6.1 浅拷贝说明
- 对于数据类型是基本数据类型的成员变量,浅拷贝时候会直接复制一份属性值给到新对象。
- 对于数据类型是引用数据类型的成员变量,比如说成员变量是集合列表、某个类的对象,那么浅拷贝会进行引用传递,就是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。
浅拷贝的实现通常有两种
- 构造方法拷贝 ——使用对象的构造方法,将原对象的各属性值传递过去,获得新的对象。**使用构造方法拷贝对象的时候,基本属性拷贝的是对象的值,对象属性和集合属性拷贝的是对象的引用。**拷贝后,如果原对象属性做了修改,新对象的属性值会跟着一起修改。
- 普通重写clone()方法 ——通过实现clone方法,直接克隆一个新的对象。
6.2 深拷贝说明
浅拷贝时候,对于基本数据类型都已经实现拷贝后修改无影响了,对引用类型的拷贝因为指向同一内存空间而没有实现彻底的隔离。若要实现深拷贝,则主要的给引用类型的属性申请到新的内存空间,让引用类型的拷贝对象不再与原对象指向同一块内存空间,以实现物理上个拷贝隔离。
深拷贝的实现通常有两种方式
- clone方法拷贝 ——对引用类型的对象依次实现clone方法
- 使用clone方法做深拷贝的时候,须对原对象中每一个对象属性都重写clone方法。
- 序列化实现 —— 把原对象写入到一个字节流中,再从字节流中将其读出来,创建一个新的对象
- 序列化方式,继承Serializable接口进行序列化与反序列化进行深拷贝,这里要注意,深拷贝的时候,主对象里面涉及到的对象属性均须实现Serializable接口,否则,会出错。
7、重载和重写的区别
重写: 在一个类中,如果两个方法的方法名和相同,参数列表(参数的个数,顺序)不同,那么这个方法就被定义为方法重载。因此,只要在同一个类中,两个方法的方法名相同,参数列表不同即可,与其权限修饰符、返回值类型无关。
**重载:**发生在子类继承父类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为private则子类不能重写该方法。
8、访问修饰符的区别
修饰符 | 当前类 | 同 包 | 子 类 | 其他包 |
---|
public | √ | √ | √ | √ | protected | √ | √ | √ | × | default | √ | √ | × | × | private | √ | × | × | × |
9、final 在 java 中有什么作用?
- final 修饰的类叫最终类,该类不能被继承。
- final 修饰的方法不能被重写。
- final 修饰的变量叫常量,常量必须初始化,初始化之后值就不能被修改。
10、java 中操作字符串都有哪些类?它们之间有什么区别?
操作字符串的类有:String、StringBuffer、StringBuilder。
String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,然后将指针指向新的 String 对象,而 StringBuffer、StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。
StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。
|