对象都是存在在堆上的吗?
不一定,Java中的对象不一定是在堆上分配的,因为JVM通过逃逸分析,能够分析出一个新对象的使用范围,并以此确定是否要将这个对象分配到堆上。
如果一个对象是在方法内部创建的,但是这个对象的引用没有传递到方法外,那么这个对象不会存在在堆上。
逃逸分析就是:一种确定指针动态范围的静态分析,它可以分析在程序的哪些地方可以访问到指针。
在JVM的即时编译语境下,逃逸分析将判断新建的对象是否逃逸。即时编译判断对象是否逃逸的依据:一种是对象是否被存入堆中(静态字段或者堆中对象的实例字段),另一种就是对象是否被传入未知代码。
典型的就是:在方法内部创建对象并发 对象的引用赋值给 方法外的变量,或者使用return Object 返回对象。
可能出现的异常
1 StackOverFlowError,Java虚拟机允许栈空间大小固定不变,比如无限递归,就会抛出异常。-Xss 规定了栈的最大空间,超出这个值就会报错
2 OutOfMemoryError,虚拟机栈可以动态扩展,如果扩展到无法申请足够的内存空间,内存不足,会出现OOM.
虚拟机中提供的几条方法调用指令:
-
invokestatic 调用静态方法,解析阶段确定唯一方法版本
-
invokespecial 调用<init>方法,私有及父类方法,解析阶段确定唯一方法版本
-
-
invokeinterface 调用接口方法
-
invokedynamic 动态解析需要调用的方法,然后执行。
前四条指令固化在虚拟机内部,不可人为干预,最后一条指令由用户确定具体调用方法的版本。
其中invokestatic,invokespecial指令调用的方法是非虚方法,其余的(final修饰的方法除外)都称为虚方法。
方法的重写与重载:
明确一个概念,方法的签名,方法的签名有 方法的名字 和 方法参数列表组成
重载:方法的签名不同
重写:方法的签名相同
重写是 Java 运行时的多态;重载 是Java 编译时的多态。
重写 使得 父类引用能 指向 子类的引用,执行父类方法。 方法的执行过程,父类和子类的继承关系,组成了一条链表,从子类 到达 父类, 从子类开始寻找,如果某个子类重写了 父类的方法,那么执行子类的重写的方法,否则继续向上寻找,直到执行父类的方法。