前言:
这是下篇,上篇链接在下面!
2020金三银四冲击BAT必备面试题(上篇):集合类+阻塞队列+锁
一. 类加载机制
1. 类加载过程
1.1 加载
查找和导入class文件。
1.2 链接
- 验证:检验载入的class文件的正确性,完整性。
- 准备:给类的静态变量分配存储空间,会赋对象类型的默认值。
- 解析:将class常量池中的符号引用转换成直接引用。
符号引用和直接引用的区别:
- 符号引用:java编译阶段不知道所引用的对象的实际地址,使用符号引用来代替
- 直接引用:能够直接定位到对象的指针,或相对偏移量。能定位到一个对象的内存实际地址。
1.3 初始化
对类的静态变量,代码块执行初始化操作,静态变量赋值顺序根据代码定义的顺序执行。
2. 类的加载顺序
- 父类静态成员变量
- 父类静态代码块
- 子类静态成员变量
- 子类静态代码块
- 父类非静态成员变量
- 父类非静态代码块
- 父类构造方法
- 子类非静态成员变量
- 子类非静态代码块
- 子类构造方法
3. 类加载时机
- 创建类实例-使用new关键字,反射,克隆,反序列化。
- 调用类的静态变量或者静态方法,或对静态变量进行赋值操作。
- 初始化子类时会先初始化父类。
- 虚拟机启时,包含main方法的启动类。
注意:
**通过数组定义的引用类,不会造成类的初始化。
**访问类的静态常量是不会造成类加载的。因为在编译时期,静态常量已经放入类的常量池中了。访问类静态常量其实是直接访问常量池中的常量,不需要加载类。
4. 静态常量是什么时候赋值的
静态常量在编译阶段把初始值存入class文件的常量池中,在类的准备阶段,将值赋给静态变量。
5. 什么是双亲委派
- 类加载器包括:BootstrapClassLoader、ExtensionClassLoader、 ApplicationClassLoader、自定义的类加载器。
- 双亲委派模型:如果一个类加载器收到了加载类的请求,首先交给父类加载器进行加载,如果父类加载器加载失败,当前类才会自己加载类。
- 双亲委派的作用:避免重复加载,父类已经加载子类不用加载,防止用户自定义加载器加载java核心的api,带来安全隐患。
- 一个类是否被加载是通过全类名和命名空间确定的,命名空间是加载类的加载器名。
6. 如何自定义类加载器
继承classloader类,重写findClass方法。
二. Web与网络
1. 转发与重定向的区别
- 转发是服务器请求资源,服务器直接访问目标地址url,把响应内容返回给浏览器。 重定向根据服务器返回的状态码重新请求地址。
- 转发是服务器行为,重定向是客户端行为。
- 转发显示的url不变而重定向显示新的url。
- 转发页面和转发到的页面共享request的信息,重定向不共享数据。
- 转发一般用于用户登录,根据角色转发到响应的模块, 重定向一般用于用户注销,跳转到其他的地方。
2. TCP三次握手
建立连接时进行TCP三次握手:
- 客户端发送syn给服务端 连接请求。
- 服务端发送syn ack 给客户端 授予连接。
- 客户端发送ack给服务端 确认连接。
第一次客户端确认自己的发送正常,服务端确认自己的接收正常。
第二次服务端确认自己的发送,接收正常,客户端的发送正常。客户端确认自己的发送、接受正常,服务端的发送、接受正常。
第三次客户端服务端都确认双方的发送接收正常。
3. TCP四次挥手
- 客户端发送fin给服务端,关闭客户端到服务端的数据传送。
- 服务端发送ack 。
- 服务端发送fin,关闭服务端和客户端的连接。
- 客户端发送ack,连接关闭。
4. 为什么是三次握手四次挥手
建立连接的时候,syn和ack可以同时发送,但是断开连接的时候fin和ack不能同时发送,因为server还未确认是否所有的报文都发送完了,所有的报文发送完了才能发送fin。所以建立连接需要三次握手,断开连接需要四次挥手。
5. TCP与UDP的区别
- TCP协议是有连接的,必须通过三次握手建立连接,UDP是无连接的。
- TCP保证数据按序到达,UDP不能保证。
- TCP是面向字节流的服务,UDP是面向报文的服务。
6. 什么是Servlet
是http请求和程序之间的中间层。可以读取客户端请求数据,处理数据并生成结果。
7. 拦截器与过滤器的区别
- 拦截器基于java反射实现,过滤器基于函数回调。
- 拦截器不依赖Servlet容器,过滤器依赖Servlet。
实现一个拦截器继承HandlerIntecepterAdapter。
实现过滤器继承Filter,在web.xml中进行配置。
8. HTTPS的过程
- 客户端发起https请求,建立连接,发送所支持的ssl/tls的版本,支持的加密套件等。
- 服务器收到请求后,会发送服务端的证书,选择的ssl/tls的版本,使用的加密套件。
- 客户端收到证书之后对证书进行验证,验证证书是否被篡改,验证证书的有效期。获取服务器的公钥。
- 使用服务器的公钥对一个随机数进行加密,传送给服务器。
- 然后使用这个随机数进行对称加密进行传输数据。
9. 加密相关
- 对称加密:加解密使用同一套秘钥,常用的加密算法: AES、 DES。
- 非对称加密:指的是加解密使用不同的密匙,一个公钥一个私钥。公钥加密的信息只有私钥能解开,私钥加密的信息只有公钥能解开。
- 摘要:一段信息,经过摘要算法得到一串hash值。常用的摘要算法:MD5、SHA1、SHA256。
- 数字签名:先用摘要算法,获取内容的摘要,之后使用自己的私钥对摘要进行加密生成签名。
- 数字证书:证书有签发者、证书用途、公钥、加密算法、hash算法、到期时间等。数字证书会做一个数字签名防止证书被篡改。会用CA的私钥进行加密。CA的公钥是公开的,浏览器会缓存。
三. 其他
1. 自定义注解
- @target:说明了Annotation所修饰的对象范围: constructor、method、field、package、type等等。
- @retention:定义了该Annotation被保留的时间长短, source(源文件保留)、class( class保留)、runtime(运行时有效)。
- @inherited:某个被标记的类型是被继承的。一个类标记了带有@inherited的注解,那么他的子类也拥有这个注解。
- @document:被修饰的注解会生成到javadoc中。
2. 内部类
- 内部类分为:成员内部类,匿名内部类,静态内部类,局部内部类。
- 除了静态内部类,其他的内部类不能拥有静态变量或静态方法,因为内部类属于外部类的一个成员变量,先加载外部类在加载内部类。
原因:
- 静态变量在类加载的时候需要将符号引用替换为直接引用而此时还没有内部类的对象。
- 内部类无法在没有外部类的实例下直接使用。
2.1 为什么静态内部类可以拥有静态常量
因为静态常量是在编译时期就确定的值,会存入类的常量池,而访问常量池中的常量是不需要加载类的。
2.2 内部类的使用场景
- 达到一个多重继承的效果
- 访问控制,只能通过外部类调用
3. 自动拆箱装箱
- 基本类型和引用类型之间的转换。
- 集合类只接受对象。
- 注意包装类的缓存值,Float和Double值没有缓存值,Integer和Long缓存值为-128~127超过之后会自动转换成对象。两个包装类型进行比较时需要用equals。
4. String为什么是final,StringBuilder与StringBuffer的区别
- String定义成final类型表示不能被继承,确保不会在子类中改变语义。
每次对string对象的改变相当于重新生成了一个新的string对象。经常改变的字符串不建议使用String。
- StringBuffer是线程安全的, StringBuilder是非线程安全的。
5. transient
- 被标记的成员变量不参与序列化过程。
- 只能修饰成员变量,不能修饰类和方法。
6. 如何进行序列化
- 实现Serializable接口。
- 序列化使用输出流进行writeObject。
- 反序列化使用输入流进行readObject。
7. 如何实现对象克隆
- 实现Cloneable接口,并重写clone方法。
- 也可通过序列化方式进行深拷贝
- 一般实际使用过程中我们只需要拷贝对象的属性,通常使用BeanUtils.copy()
这种拷贝都是浅拷贝
- 几种拷贝对象的性能
cglib>Spring>apache, 一般不建议使用apache的因为对象转换会出错,Spring的date类型转换也可能会出错。
8. 异常
8.1 Error
系统级别的错误,程序不必处理。出了错误之后只能退出运行。
8.2 Exception
- 需要进行捕捉或者程序处理的异常。
- Exception分为运行时异常和受检异常
RuntimeException包括:空指针异常,数组下标越界,classNotFound,类型转换异常等等。
受检异常指:编译器要求方法必须声明抛出可能发生的受检异常。
9. Object中的finalize方法
如果类中重写了finalize方法,当该类对象被回收时,finalize方法有可能会被触发。