JavaSE面试题复习第一弹
1、反射
- 首先获取到字节码,三种方法:
- Class.forName(className)
- 类名.class
- this.getClass()
- 将字节码中的方法、变量、构造函数等映射成相应的Method、Filed、Constructor等类,这些类提供了丰富的方法可以被我们使用。
2、类什么时候被初始化
- 创建类的实例,new一个对象
- 访问某个类或接口的静态变量,或者对该静态变量赋值
- 调用类的静态方法
- 反射
- 初始化一个类的子类(会首先初始化子类的父类)
- JVM启动时标明的启动类,即文件名和类名相同的那个类
3、类初始化的步骤
- 如果这个类还没有被加载和链接,那就先进行加载和链接
- 加入这个类存在直接父类,并且这个类还没有被初始化(注意:在一个类加载器中,类只能初始化一次),那就初始化直接的父类(不适用于接口)
- 加入类中存在初始化语句(如static变量和static代码块),那就依次执行这些初始化语句
4、Java的双亲委托机制
5、描述JVM加载class文件
类的加载是由类加载器(ClassLoader)和它的子类来实现的,Java中的类加载器是一个重要运行时系统组件,它负责在运行时查找和装入类文件中的类。
类的加载是指把类的.class文件中的数据读入到内存中,通常是创建一个字节数组读入.class文件,然后产生与所加载类对应的Class对象。加载完成后,Class对象还不完整,所以此时的类还不可用。当类被加载后就进入连接阶段,这一阶段包括验证、准备(为静态变量分配内存并设置默认的初始值)和解析(将符号引用替换为直接引用)三个步骤。最后JVM对类进行初始化,包括:
如果类中存在直接的父类并且这个类还没有被初始化,那么就先初始化父类;如果类中存在初始化语句,就依次执行这些初始化语句。类的加载是由类加载器完成的,类加载器包括:根加载器(BootStrap)、扩展加载器(Extension)、系统加载器(System)和用户自定义类加载器(java.lang.ClassLoader的子类)。
6、类加载器的说明
- BootStrap:一般用本地代码实现,负责加载JVM基础核心类库(rt.jar);
- Extension:从java.ext.dirs系统属性所指定的目录中加载类库,它的父加载器是BootStrap;
- System:又叫应用类加载器,其父类是Extension。它是应用最广泛的类加载器。它从环境变量classpath或者系统属性java.class.path所指定的目录中加载类,是用户自定义加载器的默认父加载器。
7、获得类对象的方式
- 类型.class
- 对象.getClass()
- Class.forName()
8、既然有GC机制,为什么还会有内存泄漏的情况
理论上是不会有存在内存泄漏的问题的(这也是java被广泛用于服务端编程的一个重要原因),然后在实际开发中,可能会存在无用但可达的对象,这些对象不能被GC回收,因此也会导致内存泄漏的发生。
比如hibernate的Session(一级缓存)中的对象属于持久态,垃圾回收器是不会回收这些对象的,然而这些对象中可能存在无用的垃圾对象,如果不及时关闭(close)或清空(flush)一级缓存就可能导致内存泄漏。
9、Java中为什么会有GC机制
- 安全性考虑;
- 减少内存泄漏
- 减少程序员工作量
10、对于Java的GC哪些内存需要回收
Java运行时候,会有一个运行时数据区来管理内存,主要包括5个部分:
-
程序计数器(Program Counter Register)
-
虚拟机栈(VM Stack)
-
本地方法栈(Native Method Stack)
-
方法区(Method Area)
-
堆(Heap)
而其中程序计数器、虚拟机栈、本地方法栈是每个线程私有的内存空间,随线程而生,随线程而亡。例如栈中每一个栈帧中分配多少内存基本上在类结构确定是哪个时就已知了,因此这三个区域的内存分配和回收都是确定的,无需考虑内存回收的问题。
但是方法区和堆就不同了,一个接口的多个实现类需要的内存可能不一样,我们只有在程序运行期间才会知道创建哪些对象,这部分内存的分配和回收都是动态的,GC主要关注的是这部分的内存。
GC主要就是进行回收的内存是JVM中的方法区和堆
10、Java的GC什么时候回收垃圾
当内存空间还够时,能够保存在内存中;如果进行了垃圾回收之后内存空间仍旧非常紧张,则可以抛弃这些对象。所以根据不同的需求,给出如下四种引用,根据引用类型的不同,GC 回收时也会有不同的操作:
- 强引用(Strong Reference):Object obj = new Object();只要强引用还存在,GC永远不会回收掉被引用的对象。
- 软引用(Soft Reference):描述一些还有用但非必需的对象。在系统将会发生内存泄漏溢出之前,会把这些对象列入回收范围进行二次回收(即系统将会发生内存溢出了,才会对他们进行回收)。
- 弱引用(Weak Reference):程度比软引用还要弱一些。这些对象只能生存到下次GC之前。当GC工作时,无论内存是否足够都会将其回收(即只要进行GC,就会对他们进行回收)。
- 虚引用(Phantom Reference):一个对象是否存在虚引用,完全不会对其生存空间构成影响。
方法区需要回收的时一些废弃的常量和无用的类
- 废弃的常量的回收,查看引用计数就可以,没有对象引用该常量就可以放心的回收了。
- 无用的类的回收,什么时无用的类呢?
- 该类所有的实例都已经被回收,也就是Java堆中不存在该类的任何实例
- 加载该类的ClassLoader已经被回收
- 该类对应的java.lang.Class对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法
对于堆中的对象,主要用可达性分析判断一个对象是否还存在引用,如果该对象没有任何引用就应该被回收。而根据我们实际对引用的不同需求,又分成了 4 种引用,每种引用的回收机制也是不同的。
对于方法区中的常量和类,当一个常量没有任何对象引用它,它就可以被回收了。而对于类,如果可以判定它为无用类,就可以被回收了。
本文地址:https://blog.csdn.net/BUG_S/article/details/109253522