目录
面试题2.1 JVM内存划分
a. 静态方法和栈帧
b. 程序计数器
c. 堆和栈中数据的默认值
d.局部变量表
e. 操作数栈
f. 静态解析/动态连接
g.方法出口
扩展(无需背诵)
面试题2.2 heap和stack有什么区别?
面试题2.3 面向对象的基本特征是什么?
java%E4%B8%AD%E5%AE%9E%E7%8E%B0%E5%A4%9A%E6%80%81%E7%9A%84%E6%9C%BA%E5%88%B6%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F%C2%A0-toc" style="margin-left:80px;">面试题2.4 java中实现多态的机制是什么?
面试题2.5 成员变量与局部变量的区别有哪些?
面试题2.6 值传递和引用传递的区别
面试题2.7 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
面试题2.8 为什么 Java 中只有值传递?
面试题2.9 static关键字的作用
面试题2.10 静态变量和实例变量的区别?
面试题2.11 一个静态方法,里面可不可以用this和super关键字
面试题2.1 JVM内存划分
【技术难度: 3 出现频率:3 】
JVM内存可以分为线程共享部分和线程独享部分;
共享部分有堆和方法区(或称元空间);
独享部分有虚拟机栈、本地方法栈、程序计数器。
先看线程共享部分:
1.堆用来存储所有new出来的对象实例及数组;
2.方法区用来存储已被JVM加载的类信息、静态变量、运行时常量池等。(每个类都有自己独有的运行时常量池)
再看线程独享部分:
- 虚拟机栈是用来控制方法的执行过程的,每执行一个方法,都会通过一个栈帧来表示,所以方法调用过程就是栈帧出栈入栈的过程。
虚拟机栈是为Java方法服务的,每个Java方法执行时会在虚拟机栈中创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等;- 本地方法栈为native本地方法服务,内部结构和虚拟机栈类似;
- 程序计数器记录对应线程执行的位置,此区域是jvm中唯一不可能出现内存溢出或泄露的位置。
a. 静态方法和栈帧
静态方法和类都存储在方法区中,那静态方法会在虚拟机栈中创建栈帧吗?
静态方法存储在方法区是指:静态方法的字节码存储在方法区中。当静态方法被调用时,会在栈中创建一个新的栈帧,以存储该方法的局部变量、操作数栈等信息。这个栈帧的生命周期与静态方法的执行时间相同,当方法执行完毕后,栈帧会被销毁。但是,与普通方法不同的是,静态方法没有this引用,因为它们不依赖于任何对象实例。
b. 程序计数器
1.程序计数器为什么是jvm中唯一不可能出现内存溢出或泄露的位置?
因为每个线程都有一个独立的程序计数器,它们不会共享内存或相互影响。而且程序计数器只存储当前线程执行的字节码指令的地址,并且这个地址的大小是固定的所以不存在内存溢出问题。
2.为什么在多线程情况下程序可以精准的定位对应线程执行到了哪个位置?
因为有程序计数器。
c. 堆和栈中数据的默认值
- 虚拟机栈中的数据没有默认值,要初始化才能用,所以方法中的局部变量必须先赋值。
- 堆中的数据有默认值,各个类型与对应的默认值分别是这样:
- byte、short、int、long的默认值为0;
- float、double的默认值为0.0;
- boolean的默认值为false;
- char的默认值为'\u0000'(空字符);
- 引用类型的默认值为null。
关于栈帧中的局部变量表、操作数栈、静态/动态链接、方法出口的细节是这样:
d.局部变量表
- 它是一组变量值存储空间,用于存放方法内的局部变量和形参。
- 一个局部变量可以保存类型为boolean、byte、char、short、int、float、reference(引用类型)和returnAddress类型的数据。
- 局部变量表的容量以变量槽(Variable Slot)为最小单位,JVM规范只要求一个槽至少能存放一个32位(4字节)以内的数据类型,所以long或double类型数据可能会占用两个槽。
- 局部变量表还会存储方法的形参。
e. 操作数栈
当一个方法刚刚开始执行时,其操作数栈是空的,随着方法执行和字节码指令的执行,会从局部变量表或对象实例的字段中复制常量或变量,写入到操作数栈。当JVM执行+-等运算指令,JVM会从操作数栈中弹出相应的操作数,执行相应的运算,然后将结果压回操作数栈。
f. 静态解析/动态连接
动态连接不是一个具体结构,而是一种处理机制:在方法执行过程中,如果需要调用其他方法,JVM会通过栈帧中保存的指向运行时常量池的引用,进入运行时常量池中找到要调用方法的符号引用,并将解析为直接引用,这一处理过程叫做动态链接(就是把 方法调用指令 翻译为 方法在内存中的具体地址 的过程)。
当类被加载进入方法区时,类中的所有方法都会有一个对应的符号引用(一般就是方法签名)被保存在这个类的运行时常量池中(它是类的元数据的一部分)。当在栈帧中遇到调用类中方法的指令时,先通过一个指向运行时常量池的引用找到常量池,再到常量池中找到要调用方法的符号引用然后将其解析为直接引用。
静态解析不同于动态链接在运行时进行转换,静态解析是类加载的过程之一,在类加载到方法区或第一次使用时就已经完成将符号引用转换为直接引用的工作,静态解析主要适用于那些在编译时期就可以确定调用的目标方法,比如静态方法、私有方法、实例构造器、被final修饰的方法等。
- 为什么需要动态连接?
为了支持多态。因为存在行为多态,所以有些方法(非静态方法)在运行时才能确定到底调用的是父类中的方法还是子类中的方法。所以在运行时对符号引用进行解析,才能更好的支持多态。- 什么是动态连接?
在程序运行时,JVM把符号引用转换成实际的内存地址,也就是直接引用的过程。
g.方法出口
- 方法执行完成后,需要返回到调用者栈帧中方法被调用的位置,程序才能继续执行。方法返回地址就是用来存储这个返回位置的。
- 一般来说,方法正常退出时,调用者的程序计数器(PC)值或指令地址作可以作为返回地址,栈帧中可能保存此计数值;
- 而方法异常退出时,返回地址是通过异常处理器表确定的,栈帧中一般不会保存此部分信息。
扩展(无需背诵)
1. JDK1.8后方法区更名为元空间,元空间并不在虚拟机中,而是使用本地内存,这样做可以很大程度避免JDK1.7以前将这些数据存放在堆内存中引发的内存溢出问题;
2.运行时常量池主要用于存放被JVM加载类的各个方法、字段的最终内存布局信息等等,以便于JVM调用;
3.直接内存不是虚拟机运行时数据区的一部分也不是Java虚拟机规范中定义的内存区域。在NIO(Non-blocking IO非阻塞输入输出操作,相关类在java.nio包)中,它可以使用Native函数直接分配堆外内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作(可以提高性能);
4.jdk1.8 JVM内存模型,如下图所示:
面试题2.2 heap和stack有什么区别?
【技术难度: 3 出现频率:3 】
1.stack栈内存:
是用来存放方法的栈帧的,当程序执行一个方法时,会在栈中为这个方法单独分配一块私属存储空间,叫做栈帧,用于存储这个方法内部的局部变量等,当这个方法结束时,对应栈帧释放,栈帧中变量随之释放;
线程私有、内存排布紧密。
2.heap堆内存:
一般用于存放new关键字创建的对象实例,对象实例不会随方法的结束消失,而是由垃圾回收机制处理。
线程共享、排布分散存在内存碎片。一般来说堆的内存大小远大于栈。
面试题2.3 面向对象的基本特征是什么?
【技术难度: 2 出现频率:2 】
第一层:
面向对象的基本特征是指封装、继承、多态。抽象。
第二层:
- 抽象是指将现实世界中的某类东西提取出来,用程序代码表示(抽象只关注业务需要的部分);
- 封装是指私有化属性,提供公共的get和set方法访问;
通过权限修饰符来控制外界访问对象的成员,让外界只能通过对象提供的接口来访问对象的属性和方法。(如我们可将对象的属性都私有化,然后提供接口供外界访问)(安全性)- 继承是指子类继承父类非私有的属性和方法(代码复用)。
- 多态是指一个类的方法可以有不同的表现(扩展性,可维护性[修复、改进])。
java%E4%B8%AD%E5%AE%9E%E7%8E%B0%E5%A4%9A%E6%80%81%E7%9A%84%E6%9C%BA%E5%88%B6%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F%C2%A0" style="text-align:left;">面试题2.4 java中实现多态的机制是什么?
【技术难度: 2 出现频率:2 】
多态的定义:同一个方法通过不同对象调用可以有不同的表现形式。
对象多态:父类引用可以指向子类对象;
行为多态:一个方法可以有不同的表现。(方法重写;父类引用指向子类对象;)
拓:
静态多态:方法重载实现多态,可变长参数实现多态。
面试题2.5 成员变量与局部变量的区别有哪些?
【技术难度: 1 出现频率:1 】
面试题2.6 值传递和引用传递的区别
【技术难度:1 出现频率: 1 】
1.值传递:基本数据类型做的是值传递,将当前变量的值复制一份存入其它变量。对其它变量的值进行修改时,当前变量的值没有影响。
2.引用传递:引用数据类型做的是引用传递,将当前引用变量的内存地址存入其它引用变量。通过其它引用变量对堆中的值修改时,再通过当前引用变量获取的是堆中修改以后的值。
面试题2.7 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
【技术难度: 1 出现频率:1 】
是引用传递,但引用传递的本质还是值传递。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用的一个副本。 Java本质上只有值传递。
面试题2.8 为什么 Java 中只有值传递?
【技术难度:1 出现频率:1 】
Java中的引用传递实际上是一个伪概念,当传递的参数为引用类型时,不会传递引用指向的对象,对象仍存在堆中,而是将引用拷贝一份传递给形参,所以引用传递的本质还是值传递。
面试题2.9 static关键字的作用
【技术难度:2 出现频率:1 】
1.static可以修饰内部类、静态导包、属性、方法、静态代码块;
2.static修饰的属性和方法属于类,一般用类名访问,只有一份在方法区;
3.static修饰的属性和方法存放在方法区中,除非卸载类,否则GC不予回收,所以不能什么都用static修饰。
静态导入:如果想不加类名就使用其他类的静态成员,那么我们可以在开头,静态导入该类的静态成员。(import static 包名.类名.成员)
static关键字的作用总结下来就是static修饰的部分可以直接通过类来使用,而不需要创建对象后再使用。
面试题2.10 静态变量和实例变量的区别?
【技术难度: 1 出现频率:2 】
1.静态变量 (或称类变量) 和类相关,通过类名调用。实例变量(或称成员变量,属性) 和对象相关,需要先创建对象,通过对象名调用;
2.静态变量存在方法区内存,只有一份,实例变量存在堆内存。
3.静态变量也有默认值。
面试题2.11 一个静态方法,里面可不可以用this和super关键字
【技术难度: 1 出现频率:1 】
不能。因为this代表的是调用这个方法的对象的引用,super代表当前父类对象的引用,而静态方法是属于类的,不属于对象。静态优先于对象,静态方法成功加载后,对象还不一定存在。
------------------------END-------------------------
才疏学浅,谬误难免,欢迎各位批评指正。