1、JDK 和 JRE 有什么区别?
JDK:Java 开发工具高
JRE:Java 运行环境
JDK 中包含 JRE ,JDK 中有一个名为 jre 的目录,里面包含两个文件夹 bin 和 lib,bin就是JVM,lib 就是 JVM 工作所需要的类库
2、== 和 equals 的区别?
==比较的是值==比较的是地址==3、final 在 java 中有什么作用?
(1)用来修饰一个引用
如果引用为基本数据类型,则该引用为常量,该值无法修改;
如果引用为引用数据类型,比如对象、数组,则该对象、数组本身可以修改,但指向该对象或数组的地址的引用不能修改。
如果引用时类的成员变量,则必须当场赋值,否则编译会报错。
(2)用来修饰一个方法
当使用 final 修饰方法时,这个方法将成为最终方法,无法被子类重写。但是,该方法仍然可以被继承。
(3)用来修饰类
当用 final 修改类时,该类成为最终类,无法被继承。比如常用的 String 类就是最终类。
4、String str=“i” 与 String str=new String(“i”) 一样吗?
String str=“i” 会将分配到常量池中,常量池中没有重复的元素,如果常量池中存中 i,就将 i 的地址赋给变量,如果没有就创建一个再赋给变量。
String str=new String(“i”) 会将对象分配到堆中,即使内存一样,还是会重新创建一个新的对象。
5、如何将字符串反转?
将对象封装到 StringBuilder 中,调用 reverse 方法反转。
6、普通类和抽象类有哪些区别?
7、接口和抽象类有什么区别?
(1)接口
接口使用 interface 修饰;
接口不能实例化;
类可以实现多个接口;
① java8之前,接口中的方法都是抽象方法,省略了public abstract。② java8之后;接口中可以定义静态方法,静态方法必须有方法体,普通方法没有方法体,需要被实现;
(2)抽象类
抽象类使用abstract修饰;
抽象类不能被实例化;
抽象类只能单继承;
抽象类中可以包含抽象方法和非抽象方法,非抽象方法需要有方法体;
如果一个类继承了抽象类,①如果实现了所有的抽象方法,子类可以不是抽象类;②如果没有实现所有的抽象方法,子类仍然是抽象类
8、Java 中 IO 流分为几种?
(1)按流划分,可以分为输入流和输出流;
(2)按单位划分,可以分为字节流和字符流;
字节流:inputStream、outputStream;
字符流:reader、writer;
9、BIO、NIO、AIO 有什么区别?
(1)同步阻塞BIO
一个连接一个线程。
JDK1.4之前,建立网络连接的时候采用BIO模式,先在启动服务端socket,然后启动客户端socket,对服务端通信,客户端发送请求后,先判断服务端是否有线程响应,如果没有则会一直等待或者遭到拒绝请求,如果有的话会等待请求结束后才继续执行。
(2)同步非阻塞 NIO
NIO主要是想解决 BIO 的大并发问题,BIO是每一个请求分配一个线程,当请求过多时,每个线程占用一定的内存空间,服务器瘫痪了。
JDK1.4 开始支持 NIO,适用于连接数目多且连接比较短的架构,比如聊天服务器,并发局限于应用中。
当NIO创建一个新的链接之后,不会直接连接一个线程,而是先连接到复用路由器上。该复用路由器可以连接多个线程。
一个请求一个线程。
(3)异步非阻塞 AIO
一个有效请求一个线程。
JDK1.7开始支持AIO,适用于连接数目多且连接比较长的结构,比如相册服务器,充分调用 OS 参与并发操作。
10、什么是反射?
所谓反射,是 Java 在运行时进行自我观察的能力,通过class、constructor、field、method 四个方法获取一个类的各个组成部分。
在 Java 运行时环境中,对任意一个类,可以知道类有哪些属性和方法。这种动态获取类的信息以及动态调用对象的方法的功能来自于反射机制。
11、什么是 Java 序列化?什么情况下需要序列化?
序列化就是一种用来处理对象流的机制。将对象的内容流化,将流化后的对象传输于网络之间。
序列化是通过实现 serializable 接口,该接口没有需要实现的方法,implement Serializable只是为了标注该对象是可被序列化的,使用一个输出流(FileOutputStream)来构造一个ObjectOutputStream 对象,接着使用 ObjectOutputStream 对象的 writeObejct(Object object)方法就可以将参数的 obj 对象到磁盘,需要恢复的时候使用输入流。
序列化是将对象转换为容易传输的格式的过程。
例如,可以序列化一个对象,然后通过HTTP通过Internet在客户端和服务器之间传输该对象。在另一端,反序列化将从流中心构造成对象。
一般程序在运行时,产生对象,这些对象随着程序的停止而消失,但我们想将某些对象保存下来,这时,我们就可以通过序列化将对象保存在磁盘,需要使用的时候通过反序列化获取到。
对象序列化的最主要目的就是传递和保存对象,保存对象的完整性和可传递性。
譬如通过网络传输或者把一个对象保存成本地一个文件的时候,需要使用序列化。
12、为什么要使用克隆?如何实现对象克隆?深拷贝和浅拷贝区别是什么?
(1)什么叫使用克隆?
想对一个对象进行复制,又想保留原有的对象进行接下来的操作,这个时候就需要克隆了。
(2)如何实现对象克隆?
实现 Cloneable 接口,重写 clone 方法
实现 Serializable 接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深克隆。
BeanUtils,apache 和 Spring 都提供了bean工具,只是这都是浅克隆。
(3)深拷贝和浅拷贝区别是什么?
浅拷贝:仅仅克隆基本类型变量,不克隆引用类型变量;
深克隆:既克隆基本类型变量,又克隆引用类型变量;
13、throw 和 throws 的区别?
(1)throw
作用在方法内,表示抛出具体异常,由方法体内的语句处理;一定抛出了异常;
(2)throws
作用在方法的声明上,表示抛出异常,由调用者来进行异常处理;可能出现异常,不一定会发生异常;
14、final、finally、finalize 有什么区别?
final 可以修饰类,变量,方法,修饰的类不能被继承,修饰的变量不能重新赋值,修饰的方法不能被重写
finally 用于抛异常,finally 代码块内语句无论是否发生异常,都会执行 finally,常用于一些流的关闭。
finalize 方法用于垃圾回收。
一般情况下不需要我们实现 finalize,当对象被回收的时候需要释放一些资源,比如 socket 链接,在对象初始化时创建,整个生命周期内有效,那么需要实现 finalize 方法,关闭这个链接。
但是当调用 finalize 方法后,并不意味着 gc 会立即回收该对象,所以有可能真正调用的时候,对象又不需要回收了,然后到了真正要回收的时候,因为之前调用过一次,这次又不会调用了,产生问题。所以,不推荐使用 finalize 方法。
15、hashcode 是什么?有什么作用?
Java 中 Object 有一个方法:
public native int hashcode();
(1)hashcode() 方法的作用
hashcode()方法主要配合基于散列的集合一起使用,比如HashSet、HashMap、HashTable。
当集合需要添加新的对象时,先调用这个对象的 hashcode() 方法,得到对应的 hashcode 值,实际上 HashMap 中会有一个 table 保存已经存进去的对象的 hashcode 值,如果 table 中没有改 hashcode 值,则直接存入,如果有,就调用 equals 方法与新元素进行比较,相同就不存了,不同就存入。
(2)equals 和 hashcode 的关系
如果 equals 为 true,hashcode 一定相等;
如果 equals 为 false,hashcode 不一定不相等;
如果 hashcode 值相等,equals 不一定相等;
如果 hashcode 值不等,equals 一定不等;
(3)重写equals方法时,一定要重写 hashcode 方法
关于hash冲突:
当两个对象equals相同,hashCode规定也必须相同,但反过来就不一定,两个对象对应一个hashCode,但equals却并不相等。。这就是传说中的hash冲突。HashMap是以hashCode取模数组形式存放值的,那两个对象hashCode一样会不会造成前一个对象的值覆盖呢?答案是不会,因为它采用了另外一种链表数据结构来解决hash冲突的情况,即使两个对象的hashCode一样,它们会放到当前数组索引位置的链表中。
16、Java 中操作字符串都有哪些类?它们之间有什么区别?
(1)String
String 是不可变对象,每次对 String 类型的改变时都会生成一个新的对象。
(2)StringBuilder
线程不安全,效率高,多用于单线程。
(3)StringBuffer
线程安全,由于加锁的原因,效率不如StringBuilder,多用于多线程。
不频繁的字符串操作使用 String,操作频繁的情况不建议使用String 。
StringBuilder > StringBuffer > String。
17、Java 中都有哪些引用类型?
(1)强引用
Java中默认声明的就是强引用,比如:
Object obj = new Object();
obj = null;
只要强引用存在,垃圾回收器将永远不会回收被引用的对象。如果想被回收,可以将对象置为 null;
(2)软引用(SoftReference)
在内存足够的时候,软引用不会被回收,只有在内存不足时,系统才会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会跑出内存溢出异常。
byte[] buff = new byte[1024 * 1024];
SoftReference<byte[]> sr = new SoftReference<>(buff);
(3)弱引用(WeakReference)
进行垃圾回收时,弱引用就会被回收。
(4)虚引用(PhantomReference)
(5)引用队列(ReferenceQueue)
引用队列可以与软引用、弱引用、虚引用一起配合使用。
当垃圾回收器准备回收一个对象时,如果发现它还有引用,就会在回收对象之前,把这个引用加入到引用队列中。
程序可以通过判断引用队列中是否加入了引用,来判断被引用的对象是否将要被垃圾回收,这样可以在对象被回收之前采取一些必要的措施。
18、在 Java 中,为什么不允许从静态方法中访问非静态变量?
静态变量属于类本身,在类加载的时候就会分配内存,可以通过类名直接访问;
非静态变量属于类的对象,只有在类的对象产生时,才会分配内存,通过类的实例去访问;
静态方法也属于类本身,但是此时没有类的实例,内存中没有非静态变量,所以无法调用。